首先三者的作用:
首先问个问题,这三个函数的存在意义是什么?答案是改变函数执行时的上下文,再具体一点就是改变函数运行时的this指向。
代码演示
function Star(name) {
this.name = name;
}
Star.prototype = {
constructor: Star,
like: function (...args) {
console.log(`${this.name}喜欢唱歌,传递参数:${args}`);
},
};
var star = new Star("刘德华");
star.like(123);
//刘德华喜欢唱歌,传递参数:123
后台打印的是:刘德华喜欢唱歌,传递参数:123
接下来
const person={
name:'张三'
}
上面代码中有一个对象字面量,他没有所谓like的方法,但是我还是想用?怎么办?此时,call、apply、bind可以帮我们干这件事。
star.like.call(person,1)
star.like.apply(person,[2])
star.like.bind(person,[3])()
// 张三喜欢唱歌,传递参数:1
// 张三喜欢唱歌,传递参数:2
// 张三喜欢唱歌,传递参数:3
可以调用了,这就是它们的作用。
总结一下,就是我们动态改变了对象的上下文,也就是改变了this的指向,复用了另一个对象的方法(属性也可以)。在此可以打印this来看一下,眼见为实。
Star.prototype = {
constructor: Star,
like: function (...args) {
console.log(this);
console.log(`${this.name}喜欢唱歌,传递参数:${args}`);
},
};
可以看到指向的是name为张三的对象
区别
那都是改变this的指向,一个不就好了吗,为何要三个呢,直接上代码,体验区别。
let person1 = {
name: "张三",
age: 12,
say(...args) {
console.log(`姓名:${this.name},年龄:${this.age},参数:${args}`);
},
};
let person2 = {
name: "李四",
age: 14,
};
//call第一个参数: 借用方法的对象,可以传递多个参数
person1.say.call(person2, 123, 2, 5, 3);
//姓名:李四,年龄:14,参数:123,2,5,3
//call第一个参数: 借用方法的对象,允许传递第二个参数必须是数组
person1.say.apply(person2, [2, 3, 4, 5]);
//姓名:李四,年龄:14,参数:2,3,4,5
// bind只是改变了this的指向,但是并没有调用say方法,加一个()执行
person1.say.bind(person2, [1, 2])();
// 姓名:李四,年龄:14,参数:1,2
person1.say.bind(person2, 2, 3, 4)();
// 姓名:李四,年龄:14,参数:2,3,4
简而言之:
call和aplly的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。
call和apply改变了函数的this上下文后便执行该函数,而bind则是返回改变了上下文后的一个函数,并且既可以一个一个参数传入,也可以用数组
应用
- 求数组中的最大和最小值
- 将伪数组转化为数组
- 数组追加
- 判断变量类型
- 实现继承
- 求数组中的最大和最小值
-
const arr = [1,2,3,-3,456,-299,78,22]; Math.max.call(Math,1,2,3,-3,456,-299,78,22) Math.max.apply(Math,arr) //456 //当然es6更简单点 Math.max(...arr)
- 将伪数组转化为数组
-
js中的伪数组(例如通过
document.getElementsByTagName
获取的元素)具有length属性,并且可以通过0、1、2…下标来访问其中的元素,但是没有Array中的push、pop等方法。我们可以利用call、apply来将其转化为真正的数组这样便可以方便地使用数组方法了如querySelectAll, getElementsByClassNmae, arguments等
args =Array.prototype.slice.call(arg,0); //slice方法传入0返回原数组 -
数组追加
-
var arr1 = [1, 2, 3]; var arr2 = [4, 5, 6]; Array.push.apply(arr1, arr2); // arr1 [1, 2, 3, 4, 5, 6] // arr2 [4,5,6] //es6 [...arr1,...arr2]
-
判断变量类型
-
const a=1 const b='1' const c={} const d=[] const e=function(){} console.log(Object.prototype.toString.call(a)); console.log(Object.prototype.toString.call(b)); console.log(Object.prototype.toString.call(c)); console.log(Object.prototype.toString.call(d)); console.log(Object.prototype.toString.call(e)); // [object Number] // [object String] // [object Object] // [object Array] // [object Function]
-
实现继承
-
var Person = function (name, age) { this.name = name; this.age = age; }; var Girl = function (name) { Person.call(this, name); }; var Boy = function (name, age) { Person.apply(this, arguments); }; var g1 = new Girl("ldh"); var b1 = new Boy("lbb", 100);
结尾:网上的教程有很多,最重要的是自己将代码敲一遍。光看不练假把式。