this
关键词this关键词是JavaScript语言中一个很重要,同时也是一个很是复杂的机制,它同时也是一个很特殊的关键词,它通常会被自动定义在函数的做用域中。很多颇有经验的开发者也常常会被this
的指向搞晕,当开发者搞不清楚它的指向的时候,心里的感觉实际上差很少是这个样子:![]()
接下来咱们将会具体讨论this
关键词到底指向什么。
this
的绑定规则首先明确一点,this
的绑定和函数的声明位置是没有任何关系的,它只取决于函数的调用位置和调用方式。jquery
首先咱们先看一下最多见的也是最简单的函数调用,全局中的独立的函数调用:编程
var a = 'hello'; function foo() { console.log(this.a); } foo();// "hello"
众所周知,声明在全局做用域中的变量,就是全局对象(window
或者global
)的一个同名的属性,在本例中,this.a
被解析成了全局变量a
,而函数foo
就是在直接在全局对象下、不带有任何修饰地进行调用的,因此,this
的默认绑定规则就是指向全局对象
。可是,当咱们使用严格模式(strict)进行开发的时候,状况发生了变化app
"use strict"; var a = 'hello'; function foo() { console.log(this.a); } foo();// undefined
在严格模式下,this
被禁止绑定到全局对象中,因此在本例中,this
指向了undefined
。函数
看下面的代码:this
var a ="world"; var foo = function () { console.log(this.a); }; var obj = { a:"hello", b:foo }; obj.b(); //"hello"
本例中,分别在全局对象中定义变量a
,和在全局对象中定义属性obj.a
,运行结果是this
被绑定到了被调用函数所在的对象中,而并不是是全局对象中的a
,或者你能够说,this
指向了该函数的上级对象中。可是严格来讲,不管是直接在obj
对象中直接定义,仍是先在全局对象中定义再添加到obj
中,foo
函数都并不属于obj
对象,然而调用位置会使用obj的上下文来引用函数。简单说,当函数引用有上下文对象时,隐式绑定
规则会将函数调用中的this
绑定到这个上下文对象中。spa
var Foo = function () { this.a = 'hello'; } Foo.prototype.bar = function () { console.log(this.a); }; Foo.prototype.bar2 = function () { this.bar(); }; var foo = new Foo(); foo.bar2();//"hello"
本例与上例相似,this在“Foo类”(严格说Foo是应该是构造函数,但通常在开发过程当中认为Foo是类,这样有助于在面向对象编程中减小误解)中绑定的是“类”里的共有变量和共有方法。prototype
this
隐式绑定丢失上述的几种应用场景仍是很是容易理解的,也是比较符合咱们对this
字面意义的理解的,相信对JavaScript有过接触和研究的童鞋很快就会掌握。下面将继续介绍几种让人感受匪夷所思的this
绑定丢失。
思考如下代码:code
var a = "world"; function foo (){ console.log(this.a); } var obj = { a:"hello", foo:foo }; var bar = obj.foo; //函数别名 bar(); //"world"
代码执行完成后,咱们看到this
被绑定到了(或者说指向了)全局对象上,而并非和前几种状况下绑定到obj
对象中,这是为啥呢?
虽然bar
是obj.foo
的一个引用,可是实际上它引用的是foo
函数自己,所以此时bar
实际上是一个不带任何修饰的函数调用,所以适用于默认绑定状况。
下面再来看看回调函数中this
的绑定状况对象
function foo() { console.log(this.a); } function do(fnc) { fnc(); }; var obj = { a:2, foo:foo }; var a = "world"; do(obj.foo);//"world"
参数传递其实就是一种隐式赋值,所以传入函数时也会被隐式赋值,因此结果和上一个例子没有区别,即使是将函数传入语言内置的的函数(好比setTimeout()
)中,结果也是没有区别的,this
要么被绑定到全局对象中,要么绑定到undefined
。
除此以外,还有一种状况也会修改this
,在一些JavaScript库中传入回调函数,可能会强制改变this
的绑定,例如在jquery中事件
$("#some-id").on('click',function () { console.log(this.id);//"some-id" });
本例中的this
就是被强制改变绑定到了触发事件的DOM元素上。
隐式绑定实际上就是在一个对象的内部包含一个指向函数的属性,并经过这个属性间接地引用属性,从而把this
间接地绑定到这个对象上。
咱们可使用call
和apply
两个函数进行显式绑定。它们的第一个参数是一个对象,它们会把这个对象绑定到this
,接着在调用函数时指定这个this
。
var a = "world"; function foo() { console.log(this.a); } var obj = { a:"hello" }; foo.call(obj);//"hello" foo() //"world"
单纯的实现this
绑定的功能的话,call
和apply
是同样的,它们的区别体如今别的参数中。
思考下面的代码:
function foo() { console.log(this.a); } var obj = { a:"hello" }; function bar() { foo.call(obj); } bar(); //"hello" setTimeout(bar,500);// "hello" bar.call(window); //"hello",硬绑定的bar不能再修改它的this
咱们建立了函数bar
,而且手动在它的内部调用foo.call(obj)
,所以强制把foo
的this
绑定到obj
,以后不管怎么调用函数bar
,它总会在obj
上调用foo
,不会丢失,这种绑定方式被称为硬绑定
.