KyleBlog.cn 文章 标签 关于
文章 标签 关于

JavaScript的this关键字的小结

在Java等面向对象语言里,this的功能是比较清晰的,它一定是指向当前对象(正在被调用的方法所属的对象)。

而在JS里,情况会更复杂些。

JS this的几种不同指向

  • 在对象的方法里,this指向该对象。
  • 在函数里:
    • 严格模式下,this的值为undefined。
    • 非严格模式下,this指向全局对象。
  • 在脚本里(不在方法或者函数)里,this指向全局对象。
  • call()apply()bind()可以让this指向任意对象。
  • ES6箭头函数里的this和上面的几种this有本质的不同,它实际上和箭头函数上下文里的this是同一个this。听起来有点费解,具体请看最后面的章节。

注意:

  • 全局对象(global object),在浏览器环境下是指window对象
  • 在JS里,函数和方法是不同的概念!具体见下个章节。

方法vs函数

先看一个方法的例子:

const user = {
  username: "jack",
  hello : function() {
    console.log('hello ' + this.username)
  }
};
user.hello();

输出:

hello jack

当执行user.hello()方法时,方法内部的this指向的实际是user对象,因此输出的this.username等同于user.username

接着上面的代码,我们再补充一个函数例子:

var hello = user.hello;
hello();

输出:

hello undefined

上面的代码里,我们将方法user.hello赋值给hello变量,然后再执行hello(),结果,输出变了,this.username不再是jack,而是undefined

之所以出现这个怪相,是因为,hello变量是一个函数,而不是方法,只有对象名.方法名()的形式才是方法调用,其他情况是函数调用!根据我们前面对this的解释,在函数中,this指向全局对象window(暂不考虑strict模式),那么函数内部的this.username就等同于window.username,而window没有username属性,即,window.username的值是undefined

call()apply()bind()的比较

三者都可以指定this的值。我们接下来通过代码示例来了解它们。

首先,准备好这两个对象,jack对象拥有一个hello方法,tom对象没有方法。我们将分别通过call()apply()bind()来让jack.hello()方法中的this指向tom对象。

const jack = {
  username: "jack",
  hello : function(times) {
    for(let i = 0; i < times; i++) {
      console.log('hello ' + this.username);
    }
  }
};
const tom = {username: "tom"};

借助call()

jack.hello.call(tom, 2);

借助apply()

jack.hello.apply(tom, [2]);

借助bind()

var hello = jack.hello.bind(tom);
hello(2);

上述三段代码的输出都是:

hello tom
hello tom

上述3个代码段,都实现了我们想要的效果,hello方法得到正常运行,而且输出的this.username实际确实是tom的username,而不是jack的username。

注意:

  • call和apply的功能类似,都是修改函数的this并执行函数。区别在于,前者的函数参数是直接传入的,后者的函数参数是打包成一个数组传入的。
  • bind不会立即执行函数,而是返回一个新函数。

ES6箭头函数的this

ES6箭头函数里的this和上面的几种this有本质的不同,它实际上和箭头函数上下文里的this是同一个this。

这个说法有点拗口,我们直接看代码:

const jack = {
  username: "jack",
  hello: () => console.log(this.username)
};

jack.hello();

这段代码的输出是undefined,而不是"jack"。看上去很不符合直觉,因为,假如hello不是箭头函数,而是普通function的时候,this应当会绑定到(指向)jack对象,那么jack.hello()输出的this.username就应该是"jack"

实际上,箭头函数() => console.log(this.username)内部的所谓this实际上和箭头函数外部的this是同一个东西!箭头函数内部只是访问了一下上下文里的this。示例代码里,箭头函数的上下文就是定义jack变量、执行jack.hello();的这段代码,对于这段代码而言,this自然指向window。于是,箭头函数里访问this.username等同于访问window.username

本文为kyleblog.cn原创,转载请注明出处:https://www.kyleblog.cn/posts/js_this

发布日期:2022-08-16 联系作者