JavaScript:处理this

JavaScript:处理this

    • 普通函数this指向
    • 箭头函数this指向
    • 修改this
      • call()
      • apply()
      • bind()


普通函数this指向

在JavaScript中,普通函数的this指向规则是根据函数的调用方式来确定的。以下是几种常见的调用方式和对应的this指向:

  1. 默认绑定规则:当函数作为独立函数调用时,即没有通过任何对象调用时,this指向全局对象(浏览器环境下为window对象,Node.js环境下为global对象)。
function test() {
  console.log(this); // this 指向 window 或 global 对象
}

test();

此时this 指向 windowglobal 对象。

  1. 隐式绑定规则:当函数作为对象的方法调用时,this指向调用该函数的对象。
var obj = {
  name: 'Alice',
  sayHello: function() {
    console.log('Hello, ' + this.name); // this 指向 obj 对象的 name 属性
  }
};

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

此时this指向obj


箭头函数this指向

JavaScript的箭头函数具有一种特殊的this规则,与普通函数不同。在箭头函数内部,this的值取决于函数被创建时的上下文,而不是被调用时的上下文。这意味着箭头函数的this值在声明时就被确定,并且无法通过call()apply()bind()等方法来改变(后续讲解这三个函数)。

下面是一个具体的示例来说明箭头函数的this规则:
首先看一段代码:

const obj = {
  name: 'Alice',
  sayHi: function() {
    setTimeout(function ()  {
      console.log(`Hi, I'm ${this.name}`);
    }, 1000);
  }
};

在这段代码中,this.namethis 指向的是 setTimeout 函数的上下文,也就是全局对象 window(或 global)。这是因为 setTimeout 的回调函数是在全局作用域中执行的,而不是在 obj 对象中执行的。因此,this.name 将是 undefined

接下来我们将回调函数从普通函数改为箭头函数:

const obj = {
  name: 'Alice',
  sayHi: function() {
    setTimeout(() => {
      console.log(`Hi, I'm ${this.name}`);
    }, 1000);
  }
};

obj.sayHi(); // 输出: Hi, I'm Alice

在上面的示例中,我们定义了一个对象obj,其中包含一个方法sayHi。在sayHi方法中,我们使用箭头函数来定义setTimeout的回调函数。由于箭头函数的特殊this规则,箭头函数内部的this值将继承自外部的sayHi方法的this值,即对象obj。因此,当调用obj.sayHi()时,输出的结果将是Hi, I'm Alice


修改this

JavaScript其实还给我们提供了一些方法来主动修改this:

call()

JavaScript中的call()方法是函数对象的一个方法,用于通过指定的this值和可选的参数来调用函数。call()方法的作用是改变函数的作用域。

call()方法的语法如下:

function.call(thisArg, arg1, arg2, ...)

其中,thisArg是要在函数中使用的this值,arg1, arg2, ...是要传递给函数的参数。

具体来说,call()方法会立即调用函数,并将指定的对象作为函数执行时的this值。通过这种方式,函数可以在不属于其原始对象的上下文中被调用。

示例:

// 示例1
const obj1 = {
  name: 'Alice',
  greet: function() {
    console.log(`Hello, ${this.name}!`);
  }
};

const obj2 = {
  name: 'Bob'
};

obj1.greet.call(obj2); // 输出:Hello, Bob!

在示例1中,我们有两个对象obj1obj2obj1具有一个greet方法,用于向控制台输出一个问候语。通过调用call()方法并传递obj2作为thisArg参数,我们可以将obj1.greet方法以obj2的上下文来执行,从而使输出为"Hello, Bob!"

// 示例2
function sayHello() {
  console.log(`Hello, ${this.name}!`);
}

const obj3 = {
  name: 'Carl'
};

sayHello.call(obj3); // 输出:Hello, Carl!

在示例2中,我们有一个名为sayHello的函数,它不属于任何特定的对象。然而,通过调用call()方法并传递obj3作为thisArg参数,我们可以在sayHello函数中将this值设置为obj3,从而使输出为"Hello, Carl!"

这个示例显示了call()方法如何允许我们在不同的上下文中重用或共享函数。可以通过改变thisArg参数的值来改变函数的执行上下文。


apply()

apply()call()的机制完全一致,唯一的区别在于参数的传递:
语法:

function.apply(thisArg, [arg1, arg2, ...])

对比以下call()的语法:

function.call(thisArg, arg1, arg2, ...)

call()apply()都是JavaScript中的方法,用于调用函数。它们的主要区别在于传递参数的方式不同。

call()方法接受一个或多个参数列表作为参数。第一个参数是要调用的函数的this值(即函数在哪个对象上执行)。剩余的参数是函数的参数。

示例:

function greet(name) {
  console.log("Hello, " + name);
}

greet.call(null, "John");

在上面的示例中,我们使用call()方法来调用greet函数,并将null作为this值传递给函数。剩余的参数是"John",作为greet函数的参数。输出结果为"Hello, John"。

apply()方法接受一个数组作为参数。第一个元素是要调用的函数的this值,剩余的元素是函数的参数。

示例:

function greet(name, age) {
  console.log("Hello, " + name + ". You are " + age + " years old.");
}

greet.apply(null, ["John", 25]);

在上面的示例中,我们使用apply()方法来调用greet函数,并将null作为this值传递给函数。数组["John", 25"]greet函数的参数。输出结果为"Hello, John. You are 25 years old."。

总结:

  • call()方法接受一个或多个参数列表,而apply()方法接受一个数组作为参数。
  • call()方法在将参数单独传递给函数时更方便,而apply()方法在将参数作为数组传递给函数时更方便。

需要注意的是,如果函数不需要this值,可以将null或undefined作为参数传递给call()或apply()方法


bind()

在JavaScript中,bind()方法用于创建一个新函数,该新函数的this值会被绑定到bind()方法的第一个参数,并且在调用新函数时,新函数的参数列表会在绑定的参数列表之后。

bind()的语法为

function.bind(thisArg[, arg1[, arg2[, ...]]])

示例一:

const person = {
  firstName: 'John',
  lastName: 'Doe',
  fullName: function() {
    return this.firstName + ' ' + this.lastName;
  }
}

const logFullName = function() {
  console.log('Full name:', this.fullName());
}

const boundLogFullName = logFullName.bind(person); // 将logFullName函数绑定到person对象上

boundLogFullName(); // 输出:Full name: John Doe

在这个示例中,bind()方法将logFullName函数绑定到person对象上,使得logFullName函数在被调用时,其内部的this值指向person对象。因此,调用boundLogFullName()函数会输出person对象的全名。

示例二:

function multiply(a, b) {
  return a * b;
}

const multiplyByTwo = multiply.bind(null, 2); // 将multiply函数绑定到null上,并将参数a绑定为2

console.log(multiplyByTwo(5)); // 输出:10

在这个示例中,bind()方法将multiply函数绑定到null上,并将参数a绑定为2。因此,调用multiplyByTwo函数时,实际上是调用了multiply函数,并传入参数25。结果为10

总结:

  • bind方法是创建一个新函数,并以指定的上下文执行对象调用这个新函数。
  • apply方法是将函数作为指定的对象的方法来调用,并传入一个数组作为参数。
  • call方法是将函数作为指定的对象的方法来调用,并传入逐个的参数。

这三种方法都可以用于改变函数的执行上下文,并且在实际应用中具有灵活性和常用性。


你可能感兴趣的:(前端开发,javascript,开发语言,ecmascript)