「JS笔记」call、apply、bind用法V04

280 阅读3分钟

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])
  1. 调用 call 、apply的对象,必须是个函数 Function。

  2. call 的第一个参数传this(自动转换为对象)。如果不传,则默认为全局对象 window。

  3. 第二个参数开始,可以接收任意个参数。每个参数会映射到相应位置的 Function 的参数上。但是如果将所有的参数作为数组传入,它们会作为一个整体映射到 Function 对应的第一个参数上,之后参数都为空

  4. apply 只接收两个参数,第一个参数的规则与 call 一致。

  5. 第二个参数,必须是数组或者类数组,它们会被转换成伪数组,传入 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

参考文献