call、apply、bind 的用法分别是什么
call、apply用法
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。 注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。
function obj1() {}
obj1.prototype = {
name: "hhh",
sayHi: function() {
console.log("My name is " + this.name);
}
}
let obj2 = new obj1;
boj2.sayHi(); // My name is hhh
obj3 = {
name: "ks"
}
obj2.sayHi.call(obj3); // My name is ks
obj2.sayHi.apply(obj3); // My name is ks
使用apply和call的最大好处就是,对象不需要与方法有任何耦合关系,可以使用xxx.sayHi.call(xxx),手动把xxx传到函数里,作为this。
call、apply区别
注意apply传递的参数是数组,而call是按参数顺序传递
let age1 = function(iterm1, iterm2) {
return iterm1 + iterm2
};
age1.call(this, iterm1, iterm2);
age1.apply(this, [iterm1, iterm2])
-
调用 call 、apply的对象,必须是个函数 Function。
-
call 的第一个参数传this(自动转换为对象)。如果不传,则默认为全局对象 window。
-
第二个参数开始,可以接收任意个参数。每个参数会映射到相应位置的 Function 的参数上。但是如果将所有的参数作为数组传入,它们会作为一个整体映射到 Function 对应的第一个参数上,之后参数都为空。
-
apply 只接收两个参数,第一个参数的规则与 call 一致。
-
第二个参数,必须是数组或者类数组,它们会被转换成伪数组,传入 Function 中,并且会被映射到 Function 对应的参数上。这也是 call 和 apply 之间,很重要的一个区别。
什么是伪数组?
数组可以通过角标调用,如 array[0];具有长度属性length;具有数组的原型(push、toString...),可以通过 for 循环或forEach方法,进行遍历。
let array1 = {
0: 1,
1: 2,
2: 3,
length: 3
};
- 伪数组 array1 可以通过角标进行调用,具有length属性,同时也可以通过 for 循环进行遍历。
- 伪数组无法使用 forEach、splice、push 等数组原型链上的方法(因为它没有数组的原型),可以通过 Array.form(fn) 把任何不适数组的变成数组。
apply 、 call 用法示例
- 数组间追加
var array1 = [12 , "foo" , {name "Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 值为 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */
- 获取数组中的最大值和最小值
var numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers), //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
- 验证是否是数组(前提是toString()方法没有被重写过)
functionisArray(obj){
returnObject.prototype.toString.call(obj) === '[object Array]' ;
}
类(伪)数组使用数组方法
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
面试题
//使用 log 代理 console.log
function log(msg) {
console.log(msg);
}
log(1);
log(1,2);
//优雅的方法
function log(){
console.log.apply(console, arguments);
};
log(1);
log(1,2);
//添加一个 (app) 前缀
function log(){
var args = Array.prototype.slice.call(arguments);
args.unshift('(app)');
console.log.apply(console, args);
};
bind
- bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
- 使用 .bind 可以让this不被改变
function f1(p1, p2) {
console.log(this. p1. p2)
}
let f2 = f1.bind({name: 'hhh'}) // f2就是f1绑定了this之后的函数
f2() // 等价于f1.call(name: 'hhh')
- .bind 还可以绑定其他参数
let f3 = f1.bind({name:'hhh'}, 'hi')
f3() // 等价于f1.call({name: 'hhh'}, hi)
call、apply、bind 比较
let obj = {
x: 99,
};
let foo = {
getX: function() {
return this.x;
}
}
console.log(foo.getX.bind(obj)()); // 99
console.log(foo.getX.call(obj)); // 99
console.log(foo.getX.apply(obj)); // 99