共计 1638 个字符,预计需要花费 5 分钟才能阅读完成。
关于 this
参考:《你不知道的 javascript 上卷》;https://www.zhihu.com/questio…;http://www.ruanyifeng.com/blo…;https://developer.mozilla.org…;
在参考了以上关于 this 的资料后,整理了一些个人认为比较有用的点,和一些自己的见解。写的有些仓促,不对的地方希望指正,共同进步。用 call 来解释 this 很形象啊,但是不是那么严谨,详情看补充 1;
试图了解 this 的本质
比较严谨的解释:一个函数可以在多个环境中执行,函数执行时允许访问环境中的其他变量,this 会指向调用函数的那个环境;
比较好懂的解释:
函数调用的多种形式都可以归结为 call,举例:
fn(x);, 可以理解为 fn.call(undefined,x); 这里 fn 中的 this 就是 undefined;
obj.fn(); 可以理解为 obj.fn.call(obj,x); 这里 fn 中的 this 就是 obj;
所以 this 可以理解为是 call 函数的第一个参数,一个函数中的 this 是由调用它的函数决定的。想要知道一个函数中的 this 是谁,大部分情况下可以去函数调用栈中找上一个函数看到。
this 的绑定规则
1. 默认绑定
像 fn();
严格模式下等价于 fn.call(undefined);
非严格模式下等价于 fn.call(全局对象); 这个全局对象在浏览器中是 window,node 中是 global;
2. 隐氏绑定
像 obj.fn(); 等价于 fn.call(obj),obj 作为一个上下文对象隐性传递到了 fn 中;
这个传递是隐性的,我们观察不到的。
3. 显示绑定
像 fn.call(context); fn 在执行时,this 就是 context;
这个绑定很明显,是我们可以观察、并且控制的。
显示绑定很常用,这里贴一个 bind 方法的极简实现
function bind(fn, obj) {
return function() {
return fn.apply(obj, arguments);
};
}
4.new 绑定
js 中的 new 操作符和其他语言的 new 机制完全不一样。
new 执行的操作用伪代码表达一下:
// 执行 new Foo() 时发生的操作
var obj = {}; // 创建空对象
obj.__proto__ = Foo.prototype; // 连接到 foo 的原型,继承机制
Foo.call(obj); // 绑定成上下文,并执行 foo
return obj; // foo 中如果没有 return 的话,return obj 这个对象回去
以上就是关于 this 比较基础的知识,要继续深入 this 的话我感觉要多看一些经典的例子,在实战中不断思考、升华~ 比如多种 this 绑定方式的优先级(this 丢失问题)、一些使用技巧、词法;网上有很多例子,这里暂时不罗列了,遇到好的再贴一下;
补充 1:this 被忽略的情况,用 call 做例子不严谨的原因
当把 null 或 undefined 作为 this 传入 call、apply、bind 时,实际应用的是默认绑定规则;
// 非严格模式
function foo() {
console.log(this.a);
}
var a = 2;
foo.call(null); // 2
补充 2:一个结合 this、声明提升、全局局部变量的例子:
var a=10;
function test(){
a=5;
alert(a);
alert(this.a);
var a;
alert(this.a);
alert(a);
}
执行 test() 和 new test() 结果是什么
答案:
alert 的内容:test(): 5,10,10,5
new test():5,undefined,undefined,5
补充 3:this 丢失(优先级)
// 用一个简单的例子开个头
// obj.fn 是一种隐性绑定,将 fn 中的 this 指向 obj
// 但是 this 又被 context 覆盖了,这种 this 丢失可以引申出优先级的问题。
obj.fn.call(context)
// 留坑