一、了解call、apply、bind

a. 字面上理解 call(调用)、apply(应用)、bind(绑定);
b. 举例子理解一下,比如我们要磨豆腐的话,我们不可能去买一头驴和一台石磨,那怎么办呢?我们可以去邻居家里借用一下, 这样我们就不用自己去造轮子,还节省成本。 驴和石磨就相当于这三个函数 call、apply、bind, 磨豆腐用的豆子就相当于我们的上下文对象。驴和石磨转圈圈下来,把豆子干成了豆腐,赤裸裸的改变了豆子的命运。同理call、apply、bind会改变对象的上下文。


二、call、apply、bind从哪里冒出来的?

call、apply、bind本质是三个函数,都是继承Function.prototype

console.log(Function.prototype.hasOwnProperty("call")); //true
console.log(Function.prototype.hasOwnProperty("apply")); //ture
console.log(Function.prototype.hasOwnProperty("bind"));  //true

这里说一点题外话,其实我们平时开发中,也是可以模仿这三个方法的特点,来写自己工具类方法。


三、使用上的区别

fn.call(obj, params1, params2, params3, ...);
fn.apply(obj, [params1, params2, params3, ...]);
fn.bind(obj, params1, params2, params3, ...)();

call和apply都是直接返回结果,bind是返回一个函数;
传参方面call和bind是一样的,apply则是传入一个数组。


四、应用

1、将伪数组(arguments 、获取dom元素数组)转化成真正的数组等,也可以自己写一个伪数组测试,

const pseudo = {
  0: "zh",
  1: "cn",
  length: 2
}
console.log(Array.isArray(pseudo)) //false
const arr = Array.prototype.slice.call(pseudo);
console.log(arr); // ["zh", "cn"]
console.log(Array.isArray(arr)) //true

IE8兼容写法:

function listToArray(list) {
  let ary = [];
  try {
    //IE8不支持 slice
    ary = Array.prototype.slice.call(list)
  } catch (e) {
    for (let i = 0, item; item = list[i++];) {
      ary[ary.length] = item;
    }
  }
  return ary;
}

2、apply的第二参数是数组的形式,可以用来向数组里添加另一个数组,或者结合Math工具类使用;

let list1 = [1, 2, 3], list2 = [4, 5, 6];
Array.prototype.push.apply(list1, list2); 
console.log(list1);
//[1,2,3,4,5,6]

当然也可以用es6的写法 list1.push(...list2);

var arr = [1, 2, 34]
console.log(Math.max.apply(arr)); // 34
console.log(Math.min.apply(arr)); // 1

3、常见的使用,改变this指向

var obj = {
  name: "zhangshan",
  sayName() {
    console.log(this.name);
  }
}
var kobj = {
  name: "lisi"
}
console.log(obj.sayName.call(kobj)); //lisi

George
2 声望0 粉丝