this
关键字是JavaScript
中最复杂的机制之一。以致于我使用多年也很难说清它到底指向什么,咱们有必要好好学习一下。this
也是咱们学习和使用JavaScript
中的一座大山,咱们必须翻过这座山。java
先看一段代码以下:函数
var foo = {
name:'tom',
age:'24',
say:function(){
console.log('name: ' + this.name + ', age: ' + this.age);
}
}
foo.say(); //name: tom, age: 24
var bar = {
name:'cat',
age:'25'
}
foo.say.call(bar); //name: cat, age: 25
复制代码
这段代码在不一样的上下文对象(foo
和bar
)中重复使用了函数say()
,不用写不一样版本的函数。若是不使用this
那么就须要给函数say()
显示传入一个上下文对象。学习
say:function(context){
console.log('name: ' + context.name + ', age: ' + context.age);
}
复制代码
this
隐式的传递了一个对象的引用,由于咱们能够将通用模块和API方法设计的更加易用和简洁。ui
在开始工做的时候很容易把this
理解成指向函数自身,不过咱们如今来分析下,this
是否是指向函数自身。思考下面一段代码:this
function foo(){
this.name = 'tom';
}
foo.name = 'cat';
foo();
console.log(foo.name); //'cat'
复制代码
最终打印的是cat
,显然this
不是指向函数自身。执行foo.name=cat
,是向对象foo
添加一个name
属性,可是函数内部代码this.name
中的this
并非指向那个函数对象。spa
遇到这样的问题,咱们会采用其余的方式来达到目的,好比建立另外一个带有name
属性的对象。设计
function foo(){
obj.name = 'tom';
}
var obj = {
name:'cat'
}
foo();
console.log(obj.name); //'tom'
复制代码
虽然这种方式确实解决了问题,其使用的是另外一种咱们比较熟悉的技术词法做用域
,并无使用this
解决。3d
另外一种方法是强制this
指向foo
函数对象。code
function foo(){
this.name = 'tom';
}
foo.name = 'cat';
foo.call(foo);
console.log(foo.name);//'tom'
复制代码
此次咱们没有回避this
,并且使用call()
来帮助咱们使用this
。cdn
this
的另外一个误区就是,指向函数的做用域。这个问题有点复杂,由于在某种状况下它是正确的,可是在其余状况下它倒是错误的。须要说明的是,this
在任何状况下都不指向函数的词法做用域。
在
javaScript
中,做用域确实和对象相似,可见的标识符都是它的属性。可是做用域“对象”没法经过javaScript
代码访问,它存在于javaScript
引擎内部。(详细的能够参考以前的文章)
思考下面一段代码:
function foo() {
var a = 1;
this.bar();
}
function bar() {
console.log(this.a);
}
foo(); //undefined
复制代码
这段代码看起来像是故意为之,但实则反映出对this
的不了解。调用bar()
最经常使用的方法是省略前面的this
,直接使用词法引用标识符。这段代码还试图经过this
在foo()
函数中联动bar()
函数访问变量a
。这也是不可能的,不能使用this
来引用一个词法做用域内部的变量及函数。
this
是在运行时进行绑定的,并非在编写时绑定,它的上下文取决于函数调用时的各类条件。this
的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会建立一个执行环境(也叫执行上下文)。执行环境中的活动对象会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this
就是记录的其中一个属性,会在函数执行的过程当中用到。(详细的能够参考以前的文章)
this 其实是在函数被调用时发生的绑定,它指向什么彻底取决于函数在哪里被调用。