JavaScript中的this——(二)
一 前景回顾
上一篇文章,我们排除了一些对于this的错误理解并且明白了每个函数的this是在调用时被绑定的,完全取决于函数的调用位置。如果想详细了解这句话请看上一篇博客。
二 调用位置
关于调用位置我们需要明确的一点是:调用位置就是函数在代码中被调用的位置(而不是声明的位置)
三 绑定规则
这一部分我们将探究调用位置是如何决定this的绑定对象。
3.1 默认绑定
function foo(){
console.log(this.a)
}
var a=2;
foo();//2
在代码中可以看出foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定。
但是在严格模式下,则不能将全局变量用于默认绑定,因此this会绑定到undefined。
3.2 隐式绑定
这种绑定就要考虑调用的位置是否存在上写文。
function foo(){
console.log(this.a)
}
var obj ={
a:2,
foo:foo
}
obj.foo();//2
这里有一个特别重要注意的地方:无论是直接在obj中定义还是先定义再添加为引用属性,这个函数foo()严格来说都不属于obj对象。 但是,调用位置会使用obj上下文来引用函数,因此你可以说函数被调用时obj对象“拥有”或者“包含”它。
下面说到正题,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因为调用foo()时this会绑定在obj上,因此this.a和obj.a是一样的。
还有一点值得注意的是,对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。
重要:起到隐形绑定就不得不提的隐式丢失
function foo(){
console.log(this.a);
}
var obj ={
a:2,
foo:foo
}
var a="hello";
var bar=obj.foo;
bar ();//hello
是不是感觉很不可思议,想要弄清楚这个问题,最关键的一点是要搞清楚“var bar=obj.foo;”虽然bar是obj.foo的一个引用,但是实际上他引用的是foo的函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。
还有一种更微妙,更常见并且更出乎意料的情况发生在传入回调函数时:
function foo(){
console.log(this.a);
}
function doFoo(fn){
//fn其实引用的是foo
fn(); //<--调用位置!
}
var obj ={
a:2,
foo:foo
}
var a="hello";
doFoo(obj.foo)//hello
这里用到的是隐形赋值,不知道得小伙伴可以自己查找一下相关的知识。
3.3显示绑定
显性绑定就是用函数的call()和apply()的方法。
function foo(){
console.log(this.a);
}
var obj={
a:2
}
foo.call(obj);
3.4new绑定
首先需要说明的一点是JavaScript中的new的机制实际上和面向类的语言完全不一样。在JavaScript中,构造函数只是一些实用new操作符时被调用的函数。它并不会属于某个类,也不会实例化一个类。实际上,他们只是被new出来的普通普通函数。
function foo(a){
this.a=a;
}
var bar=new foo(2);
console.log(bar.a);//2