浅析js中的this
更新日期:
this的用法
this在日常javascript编码中很常见, 但是一直以来没有好好总结过。 今天在这里好好总结一下。 本文只讨论浏览器环境。
this指向全局
var name = "window";
function foo() {
var name = "local";
console.log(this.name);
}
foo();
相信这段代码大家都看到过,在这里this指向了全局,输入结果是”window”.一开始我也不理解为什么有些时候this是指向内部函数,有些时候是指向window了。 相信好多小伙伴都和我一样比较疑惑, 后来我去翻阅犀牛书,犀牛书对函数this的解释是:关键字this没有作业域限制, 嵌套的函数不会从调用它的函数中继承this如果函数嵌套作为方法调用其this的值指向调用它的对象。 如果嵌套函数作为函数调用,其this不是全局对象(非严格模式下)就是undefined(严格模式下)。
其实总结一下这段话就是: 一个函数如果是执行而不是作为一个对象的方法来使用,
那么它就指向全局对象或者undefined。 所以这就解释了第一段代码。
那接下来我们解释第二个结论:
作为对象的方法使用。
var name = "window";
function foo() {
var name = "local";
console.log(this.name);
}
var obj = {
name: 'local',
foo: foo
};
obj.foo();
根据上面的结果, 我们很容易得出这里的this就指向了对象obj。在一些称谓中,这个叫做this的隐式绑定。
call,apply 对this的显式绑定
个人不喜欢文字堆砌,还是直接上代码吧。
var name = "window";
var obj = {
name: "obj"
};
function foo() {
console.log(this.name);
}
foo(); //直接调用函数 this指向window
foo.call(obj); //改变函数的上下文,把obj传进去
这里显式绑定了函数的上下文,让this指向了obj,结果输入为“obj”
顺带提一下,call,apply的区别,面试题经常被问。
使用call或者apply让一个函数以一个对象的方法执行,第一个参数是指定上下文,可以是一个对象也可以是null。
call和apply区别是第二个参数,apply是数组的形式传参。
this在构造函数的使用
this的构造函数中使用蛮多的,也蛮方便的。
function Foo() {
this.a = "foo";
}
var f = new Foo();
console.log(f.a);
通过new一个函数,那么在构造函数中,this指向实例化的对象f。
上面说完了理论知识,那么我们来几个应用场景题
example 1:
var name = "window";
function foo() {
console.log(this.name);
}
var obj = {
name: 'obj',
foo: foo
};
var a = obj.foo;
a();
obj.foo = null;
a();
可能有些同学会认为function也是对象,对象的复制是引用类型复制,那么只是指向obj.foo,如果obj.foo置空了,那么a也就不能输出this.name了。其实结果不是的,函数的复制是值的复制,和数组复制造成引用或者其他的引用不一样。简单点说
a = obj.foo = function {
console.log(this.name);
}
那么,现在执行a(); 和obj里面的foo函数还没有任何关系了。既两次执行结果都是’window’;
example 2:
看完上面这个例子,同样的我们有些是经常使用回调函数,把函数当一个参数传递,那这个参数是不是也是值的复制?请看下面的例子。
function aaa(fn) {
fn();
}
function foo() {
console.log(this.name);
}
var obj = {
name: 'obj',
foo: foo
};
aaa(obj.foo);
如果看不懂这个的话 ,这里也可以简化一下
function aaa(fn) { //在参数这里 可以理解为 var fn = obj.foo;
fn();
}
从例子1中我们可以知道函数是值的复制,那必然在aaa里面执行另外一个函数,而不是执行一个函数的方法,结果仍然是’window’.
example 3:
var name = "window";
setTimeout(function(){
var name = "local";
console.log(this.name);
},1000);
相信大家经常用定时器吧,那么有没有踩过这个坑,在定时器中,this是指向全局window的。
因为setTimeout是window下面的方法。代码可以转换为:
var name = "window";
window.setTimeout(function(){
var name = "local";
console.log(this.name);
},1000);
一个对象的方法使用,那内部的this是指向这个方法,必然this指向了这个对象本身,既window。
参考文档:
javascript权威指南第六版