javascript的中call、apply、bind
在js
中,call
、apply
、bind
是三个很重要的函数方法,它们主要用于改变函数的执行上下文(context)和传参。其作用是类似的,但有些细节上是不同的。下面我将用几个小例子讲解它们的区别和用法。
call
call()
方法在一个对象上调用另一个对象的方法。在调用时,将 this
关键字设置为指定的值,并且可以传递参数作为一个列表。
语法:function.call(thisArg, arg1, arg2, ...)
thisArg
:传递给函数的对象,可以设置为 null 或 undefined。arg1, arg2, ...
:传递给函数的参数列表。
例子:
const person = {
name: "jack",
age: "18",
sayHello: function () {
console.log(`Hello, my name is ${this.name}`);
},
};
const alice = { name: "Alice" };
person.sayHello()
person.sayHello.call(alice); // Hello, my name is Alice
在这个例子中,定义了一个 person
对象和sayHello()
函数,它会输出一个问候语。然后创建了一个对象 alice
,它有一个 name
属性。然后使用 call()
方法来调用 person
对象的sayHello()
函数并设置 this
关键字为 alice
对象。这样,它会输出 Hello, my name is Alice!
。
使用 call()
方法实现类继承的功能的例子:
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function() {
console.log(`My name is ${this.name}.`);
};
function Cat(name, color) {
Animal.call(this, name);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
const cat = new Cat('Kitty', 'white');
cat.sayName(); // My name is Kitty.
在这个例子中,定义了一个 Animal
类和一个 Cat
类。Animal
类有一个 sayName()
方法,输出动物的名字。Cat
类继承自 Animal
类,并在构造函数中调用了 Animal
类的构造函数,并传递了 this
和 name
参数。然后,将 Cat
类的原型对象设置为 Animal
类的原型对象的一个新实例,并将 constructor
属性设置为 Cat
。这样,Cat
类就具有了 Animal
类的 sayName()
方法。
apply
apply()
方法与 call()
方法类似,都是用来调用函数并改变函数的执行上下文和传递参数。不同之处在于,apply()
方法接受一个参数数组作为函数的参数,而 call()
方法则是将每个参数都显式地传递给函数。
语法:function.apply(thisArg, [argsArray])
thisArg
:传递给函数的对象,可以设置为 null 或 undefined。argsArray
:传递给函数的参数
例子:
function sayHello(msg1, msg2) {
console.log(`${message}, ${this.name}${punctuation}`);
}
const person = {
name: 'jack'
};
sayHello.apply(person, ['Hello', '!']); // Hello, jack!
在这个例子中,定义了一个 sayHello()
函数,它接受两个参数:msg1
和 msg2
。然后,创建了一个对象 person
,它有一个 name
属性。接着,使用 apply()
方法来调用 sayHello()
函数并设置 this
关键字为 person
对象,并将 msg1
和 msg2
参数作为一个数组传递给函数。这样当 sayHello()
函数执行时,它会输出 Hello, jack!
。
下面是一个例子,将一个数组的最大值传递给 Math.max()
函数:
const num = [1,2,3,4,5,6,7];
const max = Math.max.apply(null, num);
console.log(max); // 7
在这个例子中,使用 apply()
方法将 numbers
数组的值作为参数传递给 Math.max()
函数。在这里将 null
作为第一个参数传递给 apply()
方法,因为 Math.max()
函数不需要使用 this
关键字。
bind
bind()
方法不会立即调用函数,而是创建一个新的函数,其 this
关键字设置为指定的值,可以传递一些参数作为默认值。
语法:function.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
:传递给函数的对象,可以设置为 null 或 undefined。arg1, arg2, ...
:传递给函数的参数列表。
例子:
function sayHello(msg) {
console.log(`${msg}, ${this.name}!`);
}
const person = {
name: 'jack'
};
const greetPerson = sayHello.bind(person, 'Hello');
greetPerson(); // Hello, jack!
在这个例子中,定义了一个 sayHello()
函数和一个 person
对象。然后,使用 bind()
方法创建了一个新函数 greetPerson
,其 this
关键字设置为 person
对象,并将 message
参数设置为 Hello
。最后,调用 greetPerson()
函数,并输出 Hello, jack!
。
下面是一个例子,可以使用它将一个回调函数绑定到一个对象:
const obj = {
count: 0,
increment: function() {
this.count++;
}
};
const incrementCount = obj.increment.bind(obj);
incrementCount();
console.log(obj.count); // 1
bind()
方法将 obj
对象作为第一个参数传递给 increment()
方法,返回一个新函数 incrementCount
,其 this
关键字设置为 obj
对象。最后,调用 incrementCount()
函数,该函数会调用 increment()
方法,并将 obj.count
的值自增1
。
区别及优缺点
call()
、apply()
和 bind()
方法都可以用于动态设置函数内部的 this
关键字,使函数在不同的上下文中运行。
call()
和 apply()
方法非常相似,它们都立即调用函数,并将函数的 this
关键字设置为传递的对象。不同之处在于,call()
方法的参数是一个一个地传递,而 apply()
方法将参数作为一个数组传递。
bind()
方法不会立即调用函数,而是创建一个新函数,并将函数的 this
关键字设置为传递的对象。它还可以传递一些参数作为默认值。由于 bind()
方法不会立即调用函数,因此它可以方便地用于创建一个新函数,该函数可以稍后调用。
使用这些方法时需要注意的一点是,它们在性能上可能会有所影响。由于这些方法都是动态绑定 this
关键字的,因此它们的执行速度可能会比直接调用函数慢。此外,这些方法会创建新的函数对象,可能会占用更多的内存。
使用场景:
- 如果有了一个数组,想将其作为一个参数传递给函数,那么使用
apply()
方法。 - 如果需要动态绑定
this
关键字并立即调用函数,那么使用call()
方法。 - 如果需要动态绑定
this
关键字,但是不需要立即调用函数,那么使用bind()
方法。
总结
call()
和 apply()
方法能够立即调用函数并传递参数,但可能会影响性能;bind()
方法可以动态绑定 this
关键字并创建一个新函数,但不会立即调用函数,可能会占用更多内存,具体可以根据场景选择使用。