对于JavaScript的学习,想必每一位童鞋都会对this呀,闭包呀感到十分的“头痛”。之前也是对this一知半解,后来看了一些相关的资料渐渐明白了一些。今天整理一下,希望对大家的学习有所帮助,当然啦,如果有错误之处,还请大家指出以加以改正。我将从以下四个方面对this进行讲解:
- 默认绑定
- 隐式绑定
- 显式绑定
- new绑定
默认绑定
每一个函数的this都是在调用的时候被绑定的,完全取决于函数的调用位置。关于独立函数调用,我们先来看一段代码:
1 | var a = 9; |
此代码中,this.a
被解析为了全局变量a
。这就是应用了this的默认绑定,this指向全局对象。任何不带修饰的函数,只能使用默认绑定,无法应用其他规则。
如果是严格模式下,全局对象无法使用默认绑定,this将绑定到undefined
。
1 | var a = 9; |
隐式绑定
当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。看下面的一段代码:
1 | function foo(){ |
foo()
函数调用时会使用obj
上下文来引用函数。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
对象属性引用链中只有最顶层或者说最后一层会影响调用位置。如:
1 | function foo(){ |
隐式丢失
被隐式绑定的函数会丢失绑定对象,,这时会应用默认绑定,从而把this绑定到全局对象或者undefined
,取决于是否为严格模式。如:
1 | function foo(){ |
这里虽然bar
是obj.foo
的一个引用,但实际上,引用的是foo
函数本身,此时的bar()
是一个不带任何修饰的函数调用,因此会应用默认绑定。同理,回调函数传参也是如此。
参数传递以及把函数传入语言内置的函数都会应用默认绑定。
显示绑定
绝大多数的函数都可以使用call()
和apply()
方法,它们的第一个参数是一个对象,它们会把这个对象绑定到this,接着在函数调用时指定这个this。可以直接指定this的绑定对象,因此我们称之为显示绑定。如:
1 | function foo(){ |
ES5中提供了一种内置方法Function.prototype.bind
,用法如下:
1 | function foo(something){ |
new绑定
首先我们先来了解一下使用new调用函数时,发生的操作:
- 创建一个全新的对象
- 新对象被执行[[原型]]连接
- 新对象被绑定到函数调用的this
- 如果函数没有其他对象的返回值,new表达式中的函数就会自动调用这个新对象
看如下代码:
1 | function foo(a){ |
优先级
判断函数在某个调用位置应用哪条规则,按照如下顺序进行判断:
- 函数是否在new中调用?如果是的话this绑定的是新创建的对象。
- 函数是否通过
call()
、apply()
调用?如果是的话,this绑定的是指定的对象。 - 函数是否在某个上下文对象中调用?如果是的话,this绑定到那个上下文对象。
- 如果都不是的话,使用默认绑定。严格模式下,绑定到
undefined
,否则绑定到全局对象。
补充
ES6中的箭头函数不会使用以上四条规则,而是根据当前词法作用域来决定this,也就是箭头函数会继承外层函数调用的this绑定,类似于self = this
机制。