之前关注了一个公众号: JavaScript,里面详细描述了this的各种情况,在此总结一下.
只考虑当宿主环境是浏览器的时候,并且处于非严格模式下:
this是在运行时绑定的,并不是在编写时绑定的,this的绑定只取决于函数的调用方式.
在全局范围内,this等价于window对象。
console.log(this === window); //true
在全局范围内,用var声明一个变量和给this或者window添加属性是等价的。
var foo = 'bar';
console.log(foo); //'bar'
console.log(window.foo); //'bar'
console.log(this.foo); //'bar'
在全局范围内,直接给一个变量赋值(不用var声明)和给this或者window添加属性(也可能是改变属性值)是等价的。
//添加
foo = 'bar';
console.log(foo); //'bar'
console.log(window.foo); //'bar'
console.log(this.foo); //'bar'
//改变
foo = 'bar';
function changeFoo() {
foo = 'foo'; //因为在函数内没有用var定义foo,所以此时的foo和上面的foo是同一个变量
}
console.log(this.foo); //'bar'
changeFoo();
console.log(this.foo); //'foo'
普通函数调用
foo = 'bar';
function changeFoo() {
this.foo = 'foo';
}
console.log(this.foo); //'bar'
changeFoo();
console.log(this.foo); //'foo'
new调用
foo = 'bar';
function changeFoo() {
this.foo = 'foo';
}
console.log(this.foo); //'bar'
console.log(new changeFoo().foo); //'foo'
console.log(this.foo); //'bar'
function Thing() {
console.log(this); // 此时的this是一个新创建的空对象,即{},并且{}.__proto__ === Thing.prototype
console.log(this.foo); //该对象没有自有属性,会去访问this.__proto__上的foo属性
}
Thing.prototype.foo = 'bar';
var thing = new Thing(); //'bar'
console.log(thing.foo); //'bar'
当作对象的方法调用
var obj = {
name: 'irene',
getName: function() {
console.log(this.name);
}
}
obj.getName(); //'irene'.此时this指向对象obj
简单坑:
var getName = obj.getName;
getName(); // undefined.此时是普通函数调用,this指向全局对象window
高级坑:
var obj2 = {
name: 'irene2'
}
(obj2.getName = obj.getName)(); // undefined.此时复制操作的返回值是function() {console,.log(this.name);},然后调用这个函数,又是普通函数调用的情况,所以this指向全局对象window.
高级坑:
var obj = {
name: 'irene',
foo: function() {
console.log(this);
}
foo2: function() {
console.log(this);
setTimeout(function(){
console.log(this);
}, 1000);
}
};
obj.foo(); //指向obj,属于当作对象的方法调用的情况
obj.foo2(); //第一个this指向obj,和上面的情况一致,1s之后,输出的this指向全局对象,属于普通函数调用的情况.这是为何???
我个人的理解是酱紫的:JS只有一个线程,称为主线程.先执行主线程中执行栈里的代码,当主线程执行栈为空时,才会进行事件循环来查看是否有待处理事件,当事件循环检测到任务队列中有事件就取出相关回调放入执行栈中,由主线程执行.setTimeout的第一个函数参数function() {console.log(this);}会被添加到了任务队列中.当obj.foo2();执行完之后(即主线程执行栈为空),取出任务队列中的function() {console.log(this);}放入执行栈中,然后执行.此时的执行环境是全局环境,所以this指向全局对象window.关于JS的线程/事件循环/任务队列可以参考http://www.cnblogs.com/3body/...
简单坑:
var personA = {
name: 'xl',
showName: function() {
console.log(this.name);
}
};
var personB = {
name: 'xll',
getName: personA
};
var personC = {
name: 'xll',
getName: personA.showName
};
personB.getName.showName(); //'xl'
personC.getName(); //'xll'
简单坑:
var name = 'jay';
var person = {
name: 'irene',
getName: function() {
return function() {
return this.name;
}
}
};
console.log(person.getName()()); //'jay'
简单坑:
function a() {
var t = 'r';
function b() {
console.log(this);
console.log(t);
}
b();
return b;
}
a(); //普通函数调用,所以this指向全局对象window
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。