前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript中的this指向问题

JavaScript中的this指向问题

作者头像
九仞山
发布2023-10-14 09:13:30
1950
发布2023-10-14 09:13:30
举报
文章被收录于专栏:前端漫步前端漫步

JavaScript中的this关键字

在JavaScript中,关键字 this 是一个特殊的对象,它在函数被调用时自动创建。通常用来指向当前执行的函数所属的对象。this 的值在函数的每次调用时可能会发生变化,具体取决于函数是如何被调用的。

this 的值可以是以下几种情况之一:

  1. 全局上下文中的 this:在全局作用域中(即在任何函数之外)使用 this,它将指向全局对象(在浏览器环境中是 window 对象)。
  2. 函数调用中的 this:当函数被作为一个方法调用时,this 将指向调用该方法的对象。
  3. 构造函数中的 this:当函数作为构造函数使用 new 关键字创建一个新的实例时,this 将指向新创建的对象。
  4. 显式绑定中的 this:通过使用 call()apply()bind()方法,可以显式地指定一个函数的 this 值。
  5. 箭头函数中的 this:箭头函数没有自己的 this 绑定,它会继承父级作用域的 this 值。 不同情况下 this 的示例代码:
代码语言:javascript
复制
// 全局上下文中的 this
console.log(this); // 输出全局对象(在浏览器环境中是 window 对象)
// 函数调用中的 this
const obj = {
  name: "Alice",
  say: function() {
    console.log("Hello, " + this.name);
  }
};
obj.say(); // 输出 "Hello, Alice"

// 构造函数中的 this
function Person(name) {
  this.name = name;
}
const person = new Person("Alice");
console.log(person.name); // 输出 "Alice"

// 显式绑定中的 this
function sayName() {
  console.log(this.name);
}
const person1 = { name: "Alice" };
const person2 = { name: "John" };
sayName.call(person1); // 输出 "Alice"
sayName.call(person2); // 输出 "John"

// 箭头函数中的 this
const obj = {
  name: "Alice",
  greet: function() {
    setTimeout(() => {
      console.log("Hello, " + this.name);
    }, 1000);
  }
};
obj.greet(); // 输出 "Hello, Alice"

代码中this的常见使用

在代码中,this是一个关键字,代表当前执行代码的对象。它的重要性在于它允许我们在对象内部引用对象自身的属性和方法。 常见的使用this的情况有以下几种:

  1. 在对象方法中使用this:当我们在对象中定义方法时,可以使用this来引用该对象的其他属性和方法。例如:
代码语言:javascript
复制
const person = {
  name: 'John',
  age: 30,
  sayHello: function() {
    console.log(`Hello, my name is ${this.name}. I am ${this.age} years old.`);
  }
};

person.sayHello(); // 输出:Hello, my name is John. I am 30 years old.

在上面的代码中,this.namethis.age引用了person对象的属性。 2. 构造函数中使用this:当我们使用构造函数创建对象时,可以使用this来引用新创建的对象的属性和方法。

代码语言:javascript
复制
function Person(name, age) {
  this.name = name;
  this.age = age;
}

const person = new Person('John', 30);
console.log(person.name); // 输出:John
console.log(person.age); // 输出:30

在上面的扫描中,构造函数Person中的this.namethis.age引用了新创建的对象的属性。 3. 使用callapplybind改变函数中的this指向:有时候我们需要在函数执行时改变函数内部的this指向,可以使用callapplybind方法来实现。

代码语言:javascript
复制
const person1 = {
  name: 'John',
  age: 30,
};

const person2 = {
  name: 'Jane',
  age: 25,
};

function sayHello() {
  console.log(`Hello, my name is ${this.name}. I am ${this.age} years old.`);
}

sayHello.call(person1); // 输出:Hello, my name is John. I am 30 years old.
sayHello.apply(person2); // 输出:Hello, my name is Jane. I am 25 years old.

const sayHelloPerson1 = sayHello.bind(person1);
sayHelloPerson1(); // 输出:Hello, my name is John. I am 30 years old.

在上面的代码中,通过callapplybind方法,我们可以将sayHello函数中的this指向person1person2对象。

this的默认绑定

this的默认绑定是指在没有明确指定this的情况下,函数中的this将会绑定到全局对象(在浏览器环境中,全局对象是window对象)。这种默认绑定可以在全局作用域和独立函数调用中发生。

  1. 在全局作用域中,this的默认绑定指向全局对象。
代码语言:javascript
复制
function sayHello() {
  console.log("Hello, " + this.name);
}

var name = "John";
sayHello(); // 输出:Hello, John

在上面的代码中,当调用sayHello函数时,没有指定this的值,因此this的默认绑定将会指向全局对象,即window对象。由于全局对象中有一个name属性被赋值为"John",所以输出结果为"Hello, John"。 2. 在独立函数调用中,this的默认绑定也指向全局对象。

代码语言:javascript
复制
function sayAge() {
  console.log("I am " + this.age + " years old.");
}

var age = 18;

var obj = {
  age: 25,
  sayAge: sayAge
};

var func = obj.sayAge;
func(); // 输出:I am 18 years old.

在上面的代码中,sayAge函数被赋值给了变量func,并且在独立函数调用时没有指定this的值。因此,this的默认绑定将会指向全局对象。由于全局对象中有一个age变量被赋值为18,所以输出结果为"I am 18 years old."。

所以,在全局作用域和独立函数调用中,如果没有明确指定this的值,this将会默认绑定到全局对象。

this的隐式绑定

this的隐式绑定是指在函数作为对象的方法调用时,this会隐式地绑定到该对象上。这种绑定方式可以让我们在方法内部引用对象自身的属性和方法。

当一个函数作为对象的方法调用时,this会被隐式地绑定到该对象上,使得函数内部可以通过this来访问该对象的属性和方法。

代码语言:javascript
复制
const person = {
  name: 'John',
  age: 18,
  sayHello: function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
};

person.sayHello(); // 输出:Hello, my name is John and I am 18 years old.

在上面的代码中,我们定义了一个名为person的对象,它有两个属性name和age,以及一个方法sayHello。当我们调用person对象的sayHello方法时,this关键字在方法内部被隐式地绑定到person对象上。因此,this.name引用了person对象的name属性,this.age引用了person对象的age属性。

需要注意的是,隐式绑定只会在函数调用时发生,而不是在函数定义时。这意味着如果将一个方法赋值给一个变量,并在变量上调用该方法,那么this将不再被绑定到原来的对象上,而是绑定到全局对象上。

代码语言:javascript
复制
var person = {
  name: "John",
  sayHello: function() {
    console.log("Hello, " + this.name);
  }
};

var greetFunc = person.sayHello;
greetFunc(); // 输出:Hello, undefined

在上面的代码中,将person.sayHello方法赋值给了变量greetFunc,并在greetFunc上调用该方法。由于函数调用时没有指定this的值,因此this的默认绑定将会指向全局对象。由于全局对象中没有name属性,所以输出结果为"Hello, undefined"。

此外,需要注意的是,在箭头函数中,this的绑定方式与普通函数不同。箭头函数的this绑定是词法作用域,即继承自上级作用域,并且不受调用方式的影响。因此,在箭头函数中无法使用隐式绑定。

this的显示绑定

显式绑定是指在函数调用时明确指定函数内部的this值。显式绑定可以通过以下三种方法实现:

  1. 使用call方法:call()方法允许我们调用一个函数,并且显式地设置this的值。它接受一个参数列表,第一个参数是要绑定给this的对象,后面是传递给函数的参数。
  2. 使用apply方法:apply()方法与call()方法类似,只是它接受的参数是一个数组或类数组对象。第一个参数仍然是this的值,第二个参数是一个数组,其中包含函数的参数。
  3. 使用bind方法:bind()方法创建一个新的函数,将指定的对象作为this的值,并返回这个新函数。与call()和apply()不同,bind()方法不会立即执行函数,而是返回一个绑定了this的新函数。

上面三种方法的区别

  1. call方法和apply方法都可以立即调用函数并指定this值,它们的区别仅在于参数的传递方式。call方法使用参数列表,而apply方法使用参数数组。
  2. bind方法与call和apply方法不同,它不会立即调用函数,而是返回一个新的函数,需要在之后手动调用。bind方法常用于创建一个函数的新实例,并将其this值绑定到指定的对象。
代码语言:javascript
复制
// 1:使用call方法显式绑定this
function hello() {
  console.log(`Hello, ${this.name}!`);
}

const person = {
  name: 'John'
};

hello.call(person); // 输出:Hello, John!

// 2:使用apply方法显式绑定this
function sum(a, b) {
  console.log(a + b);
}

const numbers = [1, 2];

sum.apply(null, numbers); // 输出:3

// 3:使用bind方法显式绑定this
const calculator = {
  value: 10,
  add: function(num) {
    console.log(this.value + num);
  }
};

const addFive = calculator.add.bind(calculator, 5);
addFive(); // 输出:15

上面的代码展示了使用call、apply和bind方法显式绑定this的不同方式。第一个示例中,使用call方法将hello函数的this值绑定到person对象上。第二个示例中,使用apply方法将sum函数的this值绑定为null,并通过参数数组传递参数。第三个示例中,使用bind方法创建了一个新的函数addFive,它的this值永久地绑定到calculator对象上,并通过第二个参数传递了5。

this的new绑定

当使用new关键字创建对象时,会发生一种特殊的绑定,称为new绑定。这种绑定方式与显式绑定不同,它是根据构造函数创建新实例时自动发生的。

new绑定的过程如下:

  1. 创建一个新的空对象。
  2. 将这个新对象的原型指向构造函数的prototype属性。
  3. 将构造函数中的this绑定到新对象上,使构造函数内部的this引用这个新对象。
  4. 如果构造函数没有显式返回一个对象,则返回这个新对象。

通过这个过程,我们可以看到,当使用new关键字调用构造函数时,JavaScript会自动将构造函数中的this绑定到新创建的实例上。这使得我们可以在构造函数内部使用this来操作和修改新实例的属性和方法。

代码语言:javascript
复制
function Person(name, age) {
  this.name = name;
  this.age = age;
}

var person1 = new Person("John", 18);
console.log(person1.name); // 输出 "John"
console.log(person1.age); // 输出 18

在上面的代码中,我们定义了一个Person构造函数,它接受两个参数name和age,并将它们赋值给新创建的实例的属性。当使用new关键字创建一个Person对象时,构造函数内部的this会自动绑定到新实例上,因此我们可以通过this来访问和设置新实例的属性。最后,我们可以通过访问person1对象的属性来验证new绑定的效果。

箭头函数中的this

  1. 箭头函数中的this是如何工作的: 在箭头函数中,this的值是在函数定义时确定的,而不是在函数调用时确定的。箭头函数会捕获其所在上下文中的this值,并在函数体内部使用。换句话说,箭头函数的this是词法作用域上下文中的this,而不是动态绑定的。
  2. 箭头函数没有自己的this绑定,而是继承父级作用域的this: 正常的函数在被调用时,this的值是由调用方式决定的,可以通过call、apply或bind方法来显式绑定this的值。但是箭头函数不同,它没有自己的this绑定,会自动继承父级作用域中的this值。这意味着箭头函数中的this与其所在的父级作用域中的this是一样的。
代码语言:javascript
复制
// 1:箭头函数中的this继承父级作用域的this
const obj = {
  name: 'John',
  sayHello: function() {
    setTimeout(() => {
      console.log(`Hello, ${this.name}!`);
    }, 1000);
  }
};

obj.sayHello(); // 输出:Hello, John!

// 2:使用箭头函数作为回调函数
const button = document.querySelector('button');
button.addEventListener('click', () => {
  console.log(this); // 输出:Window对象
});

在上面的第一段代码中,箭头函数作为setTimeout的回调函数,它继承了父级作用域中的this(即obj对象),所以在箭头函数中可以访问到this.name。

在第二段代码中,箭头函数作为addEventListener的回调函数,由于箭头函数没有自己的this绑定,它会继承父级作用域中的this(即全局作用域),所以在箭头函数中输出的this是Window对象。

需要注意的是,由于箭头函数没有自己的this绑定,所以在箭头函数中使用call、apply或bind方法来改变this的值是无效的,this仍然会继承父级作用域中的this。

实际应用中,常见的this指向问题

  1. 在嵌套函数中丢失this:当在一个函数内部定义另一个函数,并在内部函数中使用this时,this的指向会发生变化。可以使用箭头函数或通过在外部函数中将this赋值给一个变量来解决这一问题。
  2. 事件处理函数中的this:在事件处理函数中,this通常指向触发事件的元素。但是,如果事件处理函数是通过addEventListener()方法添加的,this将指向监听器函数所在的对象(通常是触发事件的元素)。可以使用箭头函数、bind()方法,或通过在外部函数中将this赋值给一个变量来解决这一问题。
  3. 回调函数中的this:当将一个函数作为参数传递给另一个函数,并在内部函数中使用this时,this的指向可能会变化。可以使用箭头函数、bind()方法,或通过在外部函数中将this赋值给一个变量来解决这一问题。
  4. 对象方法中的this:在对象方法中,this通常指向调用该方法的对象。但是,如果将该方法赋值给一个变量,并通过变量来调用方法,this将指向全局对象。可以使用bind()方法或箭头函数来解决这一问题。

this使用时建议遵循以下几点:

  1. 确定函数调用的方式,了解this的默认绑定规则。
  2. 使用显示绑定(call()、apply()、bind())或箭头函数来明确指定函数执行时的this值。
  3. 在嵌套函数中,注意this的指向可能会发生变化,可以通过将this赋值给一个变量来解决。
  4. 在事件处理函数、回调函数或对象方法中,使用箭头函数、bind()方法或将this赋值给一个变量来确保this指向正确。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JavaScript中的this关键字
  • 代码中this的常见使用
  • this的默认绑定
  • this的隐式绑定
  • this的显示绑定
  • this的new绑定
  • 箭头函数中的this
  • 实际应用中,常见的this指向问题
  • this使用时建议遵循以下几点:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档