小菊花课堂之JavaScript关于this
关于this
上一章我们讲了关于作用域和闭包的相关知识,现在开始新一轮的学习,那就是JavaScript中最复杂的机制之一---this关键字。它是一个很特别的关键字,被自动定义在所有函数的作用域中。另外我们需要明确的一点就是,this在任何情况下都不指向函数的词法作用域。
那么我们来看看this到底是怎么样的机制。this是在运行时进行绑定的,它的上下文取决于函数调用时的各种条件。另外,this的绑定和函数声明的位置没有任何关系,之取决于函数的调用方式。
this的四条绑定规则
默认绑定
默认绑定就是最常用的独立函数调用时所绑定的。思考一下代码
function foo() { console.log(this.a); } var a = 2; foo(); // 2
我们可以看到,当调用foo()
时,this.a
被解析成了全局变量a。
但是,如果使用严格模式,那么就不能将全局对象用于默认绑定,报错TypeError:this is undefined
隐式绑定
一个对那个内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this隐式绑定到这个对象上。所以这一条就需要考虑调用位置是否有上下文对象。
function foo() { console.log(this.a); } var obj = { a : 2, foo: foo }; obj.foo(); // 2
这段代码中,当foo()
被调用时,前面加上了对obj
的引用。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。另外,对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。也就是说,this永远都是指向最近调用的位置。
显式绑定
前面说了隐式绑定的概念,那么我们如果不想在对象内部包含函数引用,而想在某个对象上强制调用函数,该如何做呢?
JavaScript中提供了两个方法,分别是call()
和apply()
,那么我们应该怎么在实际中运用呢?
首先我们要搞清楚call()
和apply()
的作用,这里引用MDN上的解释:
call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
具体如何实现,这里不作展开说明,可以自行研究,加深理解。
可以看出,它们俩的差异仅在于所需参数的形式不同,ok回归正题。
请看下面代码:
function foo() { console.log(a); } var obj = { a: 2 } foo.call(obj); // 2
这样,我们就可以在调用foo的时候强制把它的this绑定到obj上
new绑定
在传统的面向类语言中,使用new初始化类时会调用类中的构造函数。但是,JavaScript中的构造函数只是使用new
操作符时被调用的函数。它们并不属于某个类,也不会实例化一个类。
JavaScript中使用new调用函数时,会自动执行下面操作
- 构造一个新对象
- 新对象会被执行[[prototype]]连接
- 新对象会绑定函数调用的this
- 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
判断this
那么我们在判断函数在某个调用位置应该应用哪条规则呢,优先级如何判断呢?有下面四条法宝供参考
- 函数是否在
new
中调用?如果是,则this绑定的是新对象
var bar = new foo() - 函数是否通过call、apply调用?如果是,则this绑定的是指定对象
var bar = foo.call(obj) - 函数是否在某个上下文对象中调用?如果是,则this绑定的是上下文对象
var bar = obj.foo() - 如果都不是的话,使用默认绑定。注意,在严格模式下,就绑定到undefined,否则就绑定到全局对象
var bar = foo()
当然,也许会有例外的情况发生,暂时先留着,大家一起思考一下,看看会在什么情况下出现这种例外情况。
那么,今天就先到这里啦
see u ~ again