likes
comments
collection
share

一篇弄清楚JavaScript中的 this到底指向谁

作者站长头像
站长
· 阅读数 19

前言

在写代码的时候我们经常会看到this这个关键词,this到底有什么用?今天我们就来聊聊关于this的那些事。

正文

为什么要有this

1.为了让对象中的函数有能力访问对象自己的属性。

例子

如果我们想要在对象内部方法中使用对象内部的属性,就像图中的代码,它是可以在C语言里运行的,但是在JS中不可行,JS它需要使用this机制来访问(图中的myName)

一篇弄清楚JavaScript中的 this到底指向谁

let obj = {
    myName: '喜羊羊',
    age: 12,
    bar: function () { // 在对象内部方法中使用对象内部的属性
        console.log(this.myName);
    }
}
obj.bar();

一篇弄清楚JavaScript中的 this到底指向谁

2.this可以显著的提升代码质量,减少上下文参数的传递。

一篇弄清楚JavaScript中的 this到底指向谁

这种显示传参的方法有点啰嗦,如果我们采用this的话,那么就会优雅,方便很多。

function identify() {
    return this.name.toUpperCase();//英文字符转为大写
}

function speak() {
    var greeting = 'Hello, I am ' + identify.call(this);
    console.log(greeting);
}

var me = {
    name: 'gg bond'
}

speak.call(me);

运行结果是一样的 一篇弄清楚JavaScript中的 this到底指向谁

this的使用场景

可以产生作用域的地方就可以用this(除了块级作用域)

也就是:

  1. 全局
  2. 函数体内
console.log(this);

在node里打印出来是: 一篇弄清楚JavaScript中的 this到底指向谁

因为node的全局是global空对象,跟浏览器的引擎有些不一样,我们看在浏览器上的运行:

全局代指的是Window 一篇弄清楚JavaScript中的 this到底指向谁

this 代指某一块作用域

写在全局下面就代指全局的作用域

this的绑定规则

1. 默认绑定

当一个函数直接独立调用,不带任何修饰符时,使用默认绑定。 - 函数在哪个词法作用域中生效,函数中的this就指向哪里。(只要是默认绑定this一定指向全局对象window。

function foo() {
    console.log(this);//指向Window 
}
foo();//独立调用
function foo() {
    console.log(this);//还是指向Window
}
function bar() {//词法作用域在全局
    foo();
}
bar()

var

在全局,通过var声明的变量相当于window.xxx,在window对象上添加了一个属性在函数中,通过var声明的变量相当于函数的词法作用域。

一篇弄清楚JavaScript中的 this到底指向谁

let就不会

一篇弄清楚JavaScript中的 this到底指向谁

2. 隐式绑定

当函数的引用有上下文对象时(当函数被某个对象所拥有时),隐式绑定。 - 函数中的this指向的是引用它的对象。

var obj = {
  a: 1,
  foo: foo//引用
}

function foo() {
  console.log(this.a);//输出obj的a
}

obj.foo()//隐式绑定

一篇弄清楚JavaScript中的 this到底指向谁

3. 隐式丢失

当一个函数被赋值被多个对象链式调用时,函数的this指向就近的那个对象

我附庸的附庸不是我的附庸
var obj = {
  a: 1,
  foo: foo//引用
}

var obj2 = {
  a: 2,
  obj: obj
}

function foo() {
  console.log(this.a);
}

obj2.obj.foo()

一篇弄清楚JavaScript中的 this到底指向谁

4. 显示绑定

通过bind、apply、call,将函数的this指向指定的对象。call直接接受参数,apply接受参数需要用数组装起来。

bind()

band()会默认返回一个函数体。

当这个新函数被调用时,它的 this 值会被设置为在 bind() 调用中传递的第一个参数。

function greet(greeting) {
    console.log(greeting + ', ' + this.name);
}

let person = { name: 'GG Bond' };

let greetJohn = greet.bind(person, 'Hello'); // 第一个参数用于绑定 this,之后的参数将作为函数的参数
greetJohn(); // 输出 'Hello,GG Bond'

一篇弄清楚JavaScript中的 this到底指向谁

call()

立即调用一个函数,并允许指定 this 值以及任何需要传递给函数的参数。参数直接列在 call() 后面,不需要用数组包装。

function greet(greeting) {
    console.log(greeting + ', ' + this.name);
}

let person = { name: 'call' };

greet.call(person, 'Hi'); // 输出 'Hi, call'

一篇弄清楚JavaScript中的 this到底指向谁

apply()

apply() 也立即调用一个函数,但与 call() 不同的是,它的参数需要以数组的形式给出。

var obj = {
    a: 1
}

function foo(x, y) {      
    console.log(this.a, x + y);//这里的this指向了a,输出1
}
foo.apply(obj, [1, 2])

一篇弄清楚JavaScript中的 this到底指向谁

6. new绑定

通过new调用函数,将函数的this指向新创建的对象。

创建对象并绑定 this 的过程:

  1. 创建一个新对象:首先,JavaScript 引擎会创建一个全新的空对象。
  2. 设置原型链:新对象的原型(__proto__)会被设置为构造函数的 prototype 属性所指向的对象。
  3. 绑定 this:函数内部的 this 被绑定到这个新创建的对象上。
  4. 执行构造函数:构造函数的代码被执行,this 指向新创建的对象。
  5. 返回新对象:如果构造函数没有显式返回一个对象,则默认返回新创建的对象。如果构造函数返回了一个对象,那么这个返回的对象将覆盖新创建的对象。
function Person(name) {
    this.name = name;
    return {}; // 返回一个空对象,这将覆盖新创建的对象
}
let jane = new Person('Jane');
console.log(jane instanceof Object); // true
console.log(jane instanceof Person); // false

7. 箭头函数

箭头函数中没有this这个机制,写在箭头函数中的this也是它外层非箭头函数的

// 使用常规函数
function regularFunction() {
    console.log(this);
}

// 使用箭头函数
const arrowFunction = () => {
    console.log(this);
};

// 定义一个对象,其中包含一个方法和一个箭头函数属性
const obj = {
    name: 'Test',
    regularMethod: function() {
        console.log(this);
    },
    arrowMethod: () => {
        console.log(this);
    }
};

// 调用常规函数和箭头函数
regularFunction();       // 在全局作用域下,this指向全局对象
arrowFunction();         // 同样在全局作用域下,this也指向全局对象

// 调用对象的方法
obj.regularMethod();     // this指向obj
obj.arrowMethod();       // this仍然指向全局对象,而不是obj

结语

以上就是本文的全部内容,希望对你理解this的使用机制有所帮助,感谢你的阅读!

转载自:https://juejin.cn/post/7391005009666031631
评论
请登录