资讯专栏INFORMATION COLUMN

不一样的 this 问题

fizz / 2784人阅读

摘要:的指向问题是老生常谈的难点了。网上也有很多关于的文章了,本文就简单说说,再聊点不一样的。所以箭头函数虽然好用,但是不要滥用哦箭头函数还常用于数组的等循环方法中,比如

JS 的 this 指向问题是老生常谈的难点了。我当初从 Java 转过来时极其不适应,花了好长时间才摆脱这个阴影。网上也有很多关于 this 的文章了,本文就简单说说,再聊点不一样的。

this 主要是在函数中使用,在函数外使用的话,一律指向全局对象
console.log(this)    // window

var o = {
  global: this       // window
}
在函数内使用 this 时,具体指向是由函数的调用方式决定,而不是根据函数定义方式决定
1. 函数作为普通函数运行时,可以看做是当做全局对象的方法运行,此时 this 指向全局对象
function hello() {
  console.log(this)
}
hello()    // window 作为普通函数运行
2. 函数作为对象的方法调用时,函数内的 this 指向该对象

所以上面一条,普通函数可以看做是全局对象的方法,所以 this 指向全局对象

var name = "global"

var obj = {
  name: "local",
  getName: function () {
    console.log(this.name)
  },
  outer: function () {
    function inner() {
      console.log(this.name) 
    }
    inner()      // 这是第 12 行代码
  }
}

obj.getName()    // local 作为 obj 的方法调用,此时 this 指向 obj
obj.outer()      // 打印什么?控制台试试吧

这里提到了一个大家容易忽视的点: 嵌套函数
还记得上面标题说的吗? this 的指向是由函数的调用方式来决定的

由于大多数嵌套函数是直接被调用的, 比如:第 12 行代码,调用 inner()
这时 inner 是被当做普通函数调用的,也可以看做是 window.inner() ,所以此时 inner 内部的 this 指向 window,打印 global

常见的解决方案如下:

var obj = {
  name: "local",
  outer: function () {
    var that = this
    function inner() {
      console.log(that.name) 
    }
    inner()
  }
}

// 声明变量 that ,在 inner 内部用 that 代替 this
obj.outer()    // local

还有个问题

var name = "global"
var obj = {
  name: "local",
  getName: function () {
    console.log(this.name)
  }
}

obj.getName()    // local
var getName = obj.getName
getName()     // ?

直接调用 getName() 会打印 global
还是前面说的,虽然 obj.getName() 在声明的时候是作为 obj 的方法
但是把它赋值给 getName, 再调用 getName() 和 obj.getName() 的调用方式已经不同了

3. apply call bind 改变 this 指向

这个没啥还说的,强制改变 this 的指向,bind 的优先级最高。

var name = "global"
var obj = {
  name: "local",
  getName: function () {
    console.log(this.name)
  }
}

var obj2 = {
  name: "xiaoming"
}

var obj3 = {
  name: "laowang"
}

obj.getName()     // local
obj.getName.call(obj2)    // xiaoming

var getName = obj.getName.bind(obj3)    // 将 getName 内部的 this 绑定到 obj3
getName()     // laowang 不再是 window

getName.call(obj2)    // laowang
                      // bind 不会受到 apply 和 call 影响
4. 定时器设置的函数,this 会指向全局
var name = "global"
var obj = {
  name: "local",
  getName: function () {
    console.log(this.name)
  }
}

var obj3 = {
  name: "laowang"
}

setTimeout(obj.getName, 1000)            // global
setTimeout(obj.getName.bind(obj3), 2000) // laowang

bind 强制绑定优先级最高,不受定时器影响
正确调用方式如下:
外面包一层匿名函数

setTimeout(function () {
  obj.getName()
}, 1000)            // local
5. ES6 箭头函数

ES6 推出了箭头函数,详细教程可以参考阮一峰老师的教程
箭头函数没有自己的 this 和 arguments, 因此在箭头函数内部使用 this 和 argments, 其实使用的是外层的 this 和 arguments

var name = "global"
var obj = {
  name: "local",
  getName: () => console.log(this.name),
  outer: function () {
    var inner = () => console.log(this.name)
    inner()
  }
}
obj.getName()    // global 由于箭头函数没有自己的 this,所以 getName 内部的 this 其实是函数外部的 this,指向全局
obj.outer()      // local

作为函数的方法,最好不要用箭头函数,因为箭头函数内部的 this 不再指向该对象。
所以箭头函数虽然好用,但是不要滥用哦

箭头函数还常用于数组的 forEach/map/some/every/filter/reduce 等循环方法中,比如

var arr = [1, 2, 3].map(item => item * 2)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86575.html

相关文章

  • 要再问我this指向问题

    摘要:所以构造函数里的指的就是将要被出来的新对象。希望看完这篇文章之后,再有人问指向的问题,你可以嘴角微微上扬,冷笑一声不要再问我的指向问题了。 this的指向已经是一个老生常谈的问题,每逢面试都要去复习复习,近来巩固js的基础,决心彻底掌握这个知识点,一劳永逸。说明一下,为了不影响大家的思考过程,下面的代码都不会去注释答案,想知道答案,只需要去控制台执行一下。 四类场景逐一击破 首先,分析...

    nifhlheimr 评论0 收藏0
  • JavaScript之对象创建

    摘要:在构造函数的内部,的指向是新创建的对象。如果构造函数没有显式的表达式,则会隐式的返回新创建的对象对象。原型模式在构造函数模式中提到每次之后创建的新的对象是互相独立的,是独享的。 1.构造函数模式 JavaScript中的构造函数是通过new调用的,也就是说,通过new关键字调用的函数都被认为是构造函数。 在构造函数的内部,this的指向是新创建的对象Object。 如果构造函数没有显式...

    Michael_Lin 评论0 收藏0
  • Js基础知识(二) - 原型链与继承精彩讲解

    摘要:有了原型链,就有了继承,继承就是一个对象像继承遗产一样继承从它的构造函数中获得一些属性的访问权。这里其实就是一个原型链与继承的典型例子,开发中可能构造函数复杂一点,属性定义的多一些,但是原理都是一样的。 作用域、原型链、继承与闭包详解 注意:本章讲的是在es6之前的原型链与继承。es6引入了类的概念,只是在写法上有所不同,原理是一样的。 几个面试常问的几个问题,你是否知道 insta...

    mrcode 评论0 收藏0
  • Js基础知识(二) - 原型链与继承精彩讲解

    摘要:有了原型链,就有了继承,继承就是一个对象像继承遗产一样继承从它的构造函数中获得一些属性的访问权。这里其实就是一个原型链与继承的典型例子,开发中可能构造函数复杂一点,属性定义的多一些,但是原理都是一样的。 作用域、原型链、继承与闭包详解 注意:本章讲的是在es6之前的原型链与继承。es6引入了类的概念,只是在写法上有所不同,原理是一样的。 几个面试常问的几个问题,你是否知道 insta...

    lingdududu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<