本文已参与「新人创作礼」活动,一起开启掘金创作之路。
新年快乐!
前言
this 关键字是 JavaScript 中的一个重点,它是一个特别的关键字,代表了当前的上下文。
在面试时,关于 this 的题目也是经常出现。在学习源码或别人的代码时,搞懂 this 关键字对我们对代码的理解能起到很大的帮助。
this 的绑定规则
默认绑定
普通函数的调用(不带任何修饰的调用),此时 this 指向全局对象 window。 若函数声明时使用严格模式,则 this 指向 undefined。
如下代码,在调用函数 test 时,应用了默认绑定(非严格模式),此时的 this 指向全局对象。
function test() {
console.log(this.name);
}
var name = 'hhhqzh';
test(); // 'hhhqzh'
如下代码,在函数声明时使用了严格模式,此时 this 指向 undefined,会报错。
function test() {
'use strict';
console.log(this.name);
}
var name = 'hhhqzh';
test();
隐式绑定
当函数有引用上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到函数执行上下文。简单来说就是通过对象来调用其函数。
function test(){
console.log(this.name);
}
var person = {
name: 'ppptyp',
test: test
}
var name = 'hhhqzh';
person.test(); // 'ppptyp'
test 函数声明在外部,严格来说并不属于 person 这个对象,但是在调用 test 时,调用位置会使用 person 的上下文来引用函数,隐式绑定会把函数调用中的 this(即此例 test 函数中的 this)绑定到这个上下文对象(即此例中的 person),所以最后的运行结果是 'ppptyp' 而不是 'hhhqzh'。
- 隐式丢失 隐式丢失是隐式绑定的一个小缺陷,即隐式绑定的函数丢失绑定对象,引用默认绑定。
比如:直接把函数作为参数传递或变量赋值,这时引用的只是函数本身。
var person = {
name: 'ppptyp',
test: function test(){
console.log(this.name);
}
}
var name = 'hhhqzh';
var fn = person.test;
fn(); // 'hhhqzh'
把 person 对象的 test 函数赋值给变量 fn,此时 fn 直接指向了 test 的引用,在调用的时候与 person 没有关系,此时的 this 使用的是默认绑定,指向全局对象 window。
显式绑定
-
通过使用
call、apply、bind改变this的行为。call、apply和bind的第一个参数,就是对应函数的this所指向的对象,bind属于硬绑定,即绑定后返回的函数的this无法再次使用显示绑定进行修改。
function test() {
console.log(this.name);
}
var name = 'person';
var person = {
name: 'hhhqzh'
}
test.apply(person); // 'hhhqzh'
使用了显示绑定把 this 绑定到了 person 上。
- API 调用的上下文
比如 map、forEach 等可以把对象作为参数并把它当做函数执行时的 this 的 API。
new
在 JavaScript 中,构造函数只是使用 new 操作符时被调用的函数,这些函数和普通的函数是一样的,它不是面向对象语言中的类。任何一个函数都可以使用 new 来调用。
new 关键字会进行以下四步的操作,因此使用 new 来创建新对象的时候,会将新对象绑定到构造函数的 this:
- 创建一个空的简单JavaScript对象(即
{}); - 为新创建的空对象添加属性 proto ,将该属性链接至构造函数的原型对象;
- 将新创建的对象作为
this的上下文; - 如果该函数没有返回对象,则返回
this,否则返回函数返回的对象。
function test(name){
this.name = name;
}
var my = new test('hhhqzh');
console.log(my.name); // 'hhhqzh'
箭头函数
-
箭头函数的
this指向在定义的时候继承自外层作用域的this- 一旦箭头函数的
this绑定成功,无法被直接修改(call、apply、bind都无法进行绑定) - 通过修改箭头函数外层作用于的
this指向间接修改 - 箭头函数外层没有普通函数,严格模式和非严格模式下它的
this都会指向window(全局对象)
- 一旦箭头函数的
-
箭头函数没有原型
prototype,所以箭头函数本身没有this -
箭头函数没有
argumens,其argumens继承自外层作用域的argumens,若箭头函数的this指向window,则没有argumens -
箭头函数不能被 new,因为没有
constructor -
箭头函数没有
new.target(ES6, 使用new调用函数,new.target指向类本身,普通调用就是undefined, 可以用来判断是否使用了new)
最后
欢迎大家在评论区一起交流,一起进步!