Project1
标题: 简明易懂的this指针, call, apply 和 bind教程 [打印本页]
作者: 沉滞的剑 时间: 2016-6-16 20:14
标题: 简明易懂的this指针, call, apply 和 bind教程
本帖最后由 沉滞的剑 于 2017-8-3 12:53 编辑
依然是帮助新学JS的新人快速上手的简单教程.
和之前的教程一样是帮助大家阅读和模仿MV的源码而普及的基础知识
这是对修改甚至自己写脚本需要迈出的第一步.
1. this指针
this是一个指针,指向一个对象,在通常情况下它指的是代码的所有者.更正应该是呼叫者
例子1:
返回:Window
结论:Window是所有全局代码的呼叫者.
例子2:
function a(){
function b(){
console.log(this)
}
console.log(this)
b();
}
a();
function a(){
function b(){
console.log(this)
}
console.log(this)
b();
}
a();
返回:Window, Window
例子3:
a = {};
a.b = function(){console.log(this)}
c = [];
c[0] = function(){console.log(this)}
a.b();
c[0]();
a = {};
a.b = function(){console.log(this)}
c = [];
c[0] = function(){console.log(this)}
a.b();
c[0]();
返回:Object{....}和Array[...]
结论:通过上面的2个例子可以看出呼叫者是通过.或[]的语法关系体现的而和{}的层级无关.更正:呼叫者和被呼叫者的关系和被呼叫的函数所声明的位置无关,之和呼叫的主体有关。
例子4:
function a(){
console.log(this)
}
b = {};
b.c = a;
b.c();
function a(){
console.log(this)
}
b = {};
b.c = a;
b.c();
返回:Object{...}
结论: this和函数声明所在的{}层级无关, 只和对象的层级有关和上面的结论一致.
总结: this指针的指向判断要根据上下文, 也就是代码的所有者, 调用者. 注意看.和[]来判断从属关系.
2.call, apply 和 bind
以上讨论的仅是一般情况.
作为动态语言, js支持更改this指针的上下文, 也就是说改变this的指向.
最常用的就是call函数
call函数的作用是替换this指针, 立刻呼叫这个函数
call函数的格式如下
Function.prototype.call(this指针指向的对象, 函数的参数1, 函数的参数2......)
例子1:
function a(){
console.log(this.e);
}
b = {};
b.c = a;
b.e = 'B';
d = {}
d.e = 'D'
b.c.call(d);
function a(){
console.log(this.e);
}
b = {};
b.c = a;
b.e = 'B';
d = {}
d.e = 'D'
b.c.call(d);
输出: 'D'
结论: call函数改变了this指针的指向
apply函数和call函数是等价的, 只是参数上有少许变化:
Function.prototype.apply(this指针指向的对象, [函数的参数1, 函数的参数2......])
例子2:
function a(){
console.log(this.e);
}
b = {};
b.c = a;
b.e = 'B';
d = {}
d.e = 'D'
b.c.apply(d);
function a(){
console.log(this.e);
}
b = {};
b.c = a;
b.e = 'B';
d = {}
d.e = 'D'
b.c.apply(d);
输出:'D'
结论: apply除了把参数用一个数组包起来以外...嗯...基本和call没区别.
bind也是用来改变this上下文的, 和call格式上很像
Function.prototype.bind(this指针指向的对象, [函数的参数1, 函数的参数2......])
但是有一点很重要, bind并不是执行函数, 而是返回函数对象.
也就是说bind本身不会执行函数, 它返回了一个修改过this指针的新函数.
例子3:
function a(){
console.log(this.e);
}
b = {};
b.c = a;
b.e = 'B';
d = {}
d.e = 'D'
f = b.c.bind(d);
f();
function a(){
console.log(this.e);
}
b = {};
b.c = a;
b.e = 'B';
d = {}
d.e = 'D'
f = b.c.bind(d);
f();
输出:'D'
结论: bind和call或apply不同, 并不会直接执行函数而是返回了一个修改过this指针指向的新函数.
接下来展示几个带参数的用法.
例子4:
a = {};
b = {};
c = function(str, num){
console.log(this.e);
console.log(str + ':' + (++num));
}
a.e = 'A'
b.e = 'B'
a.d = c;
a.d.call(b,'HeartCase',3)
a.d.apply(b,['HeartCase',3])
a.d.bind(b,'HeartCase',3)();
a = {};
b = {};
c = function(str, num){
console.log(this.e);
console.log(str + ':' + (++num));
}
a.e = 'A'
b.e = 'B'
a.d = c;
a.d.call(b,'HeartCase',3)
a.d.apply(b,['HeartCase',3])
a.d.bind(b,'HeartCase',3)();
输出:B, HeartCase:4,B, HeartCase:4,B, HeartCase:4
结论: 以上三种写法是等价的
关于call, apply 和 bind使用的奇技淫巧是很多的
对于想要了解js原理的人来说, 对这三个函数的掌握是非常重要的,它们也有很多高级进阶技巧
但是对我们这些基础的使用者,至少对RM来说保持良好的可读性才是第一位的
弄懂了这些, 帮助你阅读源码是十分有利的.
总结:
this指针指向的是代码的所有者
利用call, bind 和 apply可以修改this指针的指向
其他: js中还有一个蛋疼的东西叫原型和原型链, 我觉得我也有必要向新手普及一下
因为需要很多配图所以不知道猴年马月能更新...
(这个月不就是猴年马月么!!!)
作者: iceBOXz 时间: 2016-6-17 16:20
這裡有其中一個受惠的新手 等著更新
這篇文 不是寫給空氣看哦
作者: taroxd 时间: 2016-6-17 21:41
本帖最后由 taroxd 于 2016-6-21 11:44 编辑
js 的 this 就是个神奇的东西,不需要去花太多时间搞得很清楚。有了 arrow function 之后 this 才算稍微正常一点。
特别是第一点和第二点,因为安全问题已经不建议使用了。(在 strict mode 里面,允许 this 为 undefined)
function foo() {
'use strict'
console.log(this)
}
class C {
bar() {
console.log(this)
}
}
foo() // undefined, NOT Window
let {bar} = C.prototype
bar() // undefined, NOT Window
function foo() {
'use strict'
console.log(this)
}
class C {
bar() {
console.log(this)
}
}
foo() // undefined, NOT Window
let {bar} = C.prototype
bar() // undefined, NOT Window
另外,js 没有规定全局对象叫 window。node 里面就叫 global
为啥要吐槽这个?因为我写js主要就是node环境
作者: xjh01 时间: 2016-10-6 18:45
this,代码的所有者。这样看是很好理解,但是在实际插件中,就好昏,不知道this到底指的是什么东西。
作者: 循环往复的时间 时间: 2024-4-5 10:58
当函数作为构造函数被调用(new操作符)时,this指向命名的对象实例;不是作为构造函数被调用时(直接被调用),this由运行时的对象上下文决定,在window全局对象下调用就指向window,作为对象的方法被调用时,this指向该对象。
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |