之前关注了一个公众号: 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




小被子
839 声望10 粉丝

« 上一篇
耦合
下一篇 »
IE兼容性