关于this的二三事

什么是this

this是JS中一个非常重要的关键字。this 就是你 call 一个函数时,传入的 context。任何形式的函数调用都可以写成call形式,传入的第一个参数就是this。

f(a,b)   等价于  f.call(undefined , a , b)
f.m.n(a,b)  等价于  f.m.n.call(f.m , a , b)
fn.call(context , p1 , p2)

所以当我们无法确定this时我们可以转换成call形式来确认this。

如何确定this

通常我们确定this会用以下方式

1、console.log(this)
2、查看API源代码
3、查看API相关文档

this的使用

全局变量

function f() {
  console.log(this); // window
}
var a=1
function f() {
  console.log(this.a); 
}
f()
//1

对象的方法

当A对象的方法被赋予B对象,该方法中的this就从指向A对象变成了指向B对象。所以要特别小心,将某个对象的方法赋值给另一个对象,会改变this的指向。

var obj ={
  foo: function () {
    console.log(this);
  }
};
obj.foo()  // obj

但是,只有这一种用法(直接在obj对象上调用foo方法),this指向obj;其他用法时,this都指向代码块当前所在对象(浏览器为window对象)。

(obj.foo = obj.foo)()
/ 等价于 /
(obj.foo = function () {
  console.log(this);
})()
//window

可以这样理解,obj和obj.foo储存在两个内存地址,简称为M1和M2。只有obj.foo()这样调用时,是从M1调用M2,因此this指向obj。但是,上面情况是直接取出M2进行运算,然后就在全局环境执行运算结果(还是M2),因此this指向全局环境。

避免多层this

由于this的指向是不确定的,所以切勿在函数中包含多层的this。

var o = {
  f1: function () {
    console.log(this);
    var f2 = function () {
      console.log(this);
    }();
  }
}
o.f1()
// Object
// Window

上面代码等价于

var temp = function () {
  console.log(this);
};
var o = {
  f1: function () {
    console.log(this);
    var f2 = temp();
  }
}

当我们把代码修改为

var o = {
  f1: function() {
    console.log(this);
    var that = this;
    var f2 = function() {
      console.log(that);
    }();
  }
}
o.f1()
// Object
// Object

上面代码定义了变量that,固定指向外层的this,然后在内层使用that,就不会发生this指向的改变。

避免数组处理方法中的this

数组的map和foreach方法,允许提供一个函数作为参数。这个函数内部不应该使用this。

var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    });
  }
}
o.f()
// undefined a1
// undefined a2

上面代码相当于

var temp = function(){
   o.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    });
} //this指向全局变量
var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: temp() 
}
o.f()
// undefined a1
// undefined a2

我们同样可以这样修改

var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    var that = this;
    this.p.forEach(function (item) {
      console.log(that.v+' '+item);
    });
  }
}
o.f()
// hello a1
// hello a2

或者将this当作foreach方法的第二个参数,固定它的运行环境。

var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    }, this);
  }
}
o.f()
// hello a1
// hello a2

bind方法

bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。

var counter = {
  count: 0,
  inc: function () {
    this.count++;
  }
};
var func = counter.inc;
func();
counter.count // 0
count // NaN

上面代码中,函数func是在全局环境中运行的,这时inc内部的this指向顶层对象window,所以counter.count是不会变的,反而创建了一个全局变量count。因为window.count原来等于undefined,进行递增运算后undefined++就等于NaN。

var func = counter.inc.bind(counter);
func();
counter.count
//1

使用bind方法将inc方法绑定到counter以后,再运行func就会得到正确结果。

小结

对于this,我们只要记得其本质就是call函数时传入的第一个参数,如果函数调用形式不是 call 形式,请将其转换为 call 形式,函数的this值可以用call改变,也可以用bind改变默认的this值。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 11,807评论 15 54
  • 与其他语言相比,函数的this关键字在JavaScript中的表现略有不同,此外,在严格模式和非严格模式之间也会有...
    codingC阅读 3,655评论 0 0
  • 特别说明,为便于查阅,文章转自https://github.com/getify/You-Dont-Know-JS...
    杀破狼real阅读 4,028评论 0 1
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 8,698评论 0 4
  • 窗外疾驰的车辆 驱赶着深秋的冷雾 汽笛声阵阵催促我忙碌 尘世那渐行渐远的脚步 诗歌在柴米油盐中荒芜 拨开杂草丛生阡...
    古月ypc阅读 1,463评论 0 0

友情链接更多精彩内容