关于这三个方法,很多大神已经总结的非常到位了。但是呢,俗话说“好记性不如烂笔头”。而且,我发现我学习了一个东西,然后自己敲一篇博客出来之后,就会进一步加深自己对它的理解,所以我还是准备把它写下来。以后也会一直写博客,一直将自己学习的东西记录下去~
关于call()、apply()和bind()这三个方法的学习,我是从一个个例子入手的:
var name = '小明',age = 18;
var obj = {
name: '小红',
objAge: this.age,
myFun: function(){
console.log("姓名:" + this.name + ";" + "年龄:" + this.age);
}
}
obj.objAge;
运行结果:
18
obj.myFun();
运行结果:
姓名:小红;年龄:undefined
这个例子中,myFun 中的 this 指向的是 obj,所以,而 obj 没有 age 属性,所以,this.age 是undefined。
var name = '小明',age = 18;
function myFun(){
console.log("姓名:" + this.name + ";" + "年龄:" + this.age);
}
myFun();
运行结果:
姓名:小明;年龄:18
这个例子中,myFun 中的 this 指向的是 window 对象。
加入了call()、apply()和bind()之后:
var name = '小明',age = 18;
var obj = {
name: '小红',
objAge: this.age,
myFun: function(){
console.log("姓名:" + this.name + ";" + "年龄:" + this.age);
}
}
var args = {
name: '小华',
age: 20
}
obj.myFun.call(args);
运行结果:
姓名:小华;年龄:20
obj.myFun.apply(args);
运行结果:
姓名:小华;年龄:20
obj.myFun.bind(args)();
运行结果:
姓名:小华;年龄:20
可以看出,call()、apply()、bind() 的作用是:重定义 this 对象。
区别在于,bing() 返回的是一个新的函数,必须调用才能被执行。如下所示:
var name = '小明',age = 18;
var obj = {
name: '小红',
objAge: this.age,
myFun: function(){
console.log("姓名:" + this.name + ";" + "年龄:" + this.age);
}
}
var args = {
name: '小华',
age: 20
}
obj.myFun.bind(args);
运行结果:
ƒ (){
console.log("姓名:" + this.name + ";" + "年龄:" + this.age);
}
可以看到,返回了一个函数。
所以,call()、apply()、bind() 区别在于:bind()是返回一个新函数,供以后调用,而 apply() 和 call() 是立即调用。
var name = '小明',age = 18;
var obj = {
name: '小红',
objAge: this.age,
myFun: function(arg,fav){
console.log("姓名:" + this.name + " 年龄:" + this.age + " 年级:" + arg + " 喜欢:" + fav);
}
}
var args = {
name: '小华',
age: 20
}
obj.myFun.call(args,'大二','苹果');
运行结果:
姓名:小华 年龄:20 年级:大二 喜欢:苹果
obj.myFun.apply(args,['大二','苹果']);
运行结果:
姓名:小华 年龄:20 年级:大二 喜欢:苹果
obj.myFun.bind(args,'大二','苹果')();
运行结果:
姓名:小华 年龄:20 年级:大二 喜欢:苹果
obj.myFun.bind(args,['大二','苹果'])();
运行结果:
姓名:小华 年龄:20 年级:大二,苹果 喜欢:undefined
上面的例子可以看出:
(1)call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象;
(2)call 的参数直接放进去,第二、第三、第 n 个参数之间用逗号分隔;
(3)apply 的参数必须放在一个数组里面传进去。
三个方法的应用:
call():
1)求数组中的最大值和最小值
let maxNum = Math.max.call(Math,5,29,15,46,26,44,23,10,2,71);
console.log(maxNum);
运行结果:
71
let minNum = Math.min.call(Math,5,29,15,46,26,44,23,10,2,71);
console.log(minNum );
运行结果:
2
2)调用对象的原生方法:
var testObj = {};
console.log(testObj.hasOwnProperty('toString'));
testObj.hasOwnProperty = function() {
return true;
}
console.log(testObj.hasOwnProperty('toString'));
console.log(Object.prototype.hasOwnProperty.call(testObj, 'toString'));
运行结果:
false
true
false
3)判断变量的类型:
function isArr(obj){
if(Object.prototype.toString.call(obj) == '[object Array]'){
return true;
}
return false;
}
isArr([]);
isArr('dhj');
isArr("");
isArr({});
运行结果:
true
false
false
false
apply():
1)求数组中的最大值和最小值
let arr = [5,29,15,46,26,44,23,10,2,71];
let maxNum = Math.max.apply(Math,arr);
console.log(maxNum);
运行结果:
71
let minNum = Math.min.apply(Math,arr);
console.log(minNum);
运行结果:
2
2)追加数组:
let arr1 = [23,3,12,14,4,90];
var arr2 = [2,59,21,20,63,47];
Array.prototype.push.apply(arr1,arr2);
console.log(arr1);
console.log(arr2);
运行结果:
[23, 3, 12, 14, 4, 90, 2, 59, 21, 20, 63, 47]
[2, 59, 21, 20, 63, 47]
3)利用Array构造函数将数组的空元素变成undefined
let arr = Array.apply(null, [1, , 3]);
console.log(arr);
运行结果:
[1, undefined, 3]
4)实现继承:
function Father(name,age){
this.name = name;
this.age = age;
this.setName = function(){
console.log(this.age);
}
}
function Son(){
Father.apply(this,arguments);
}
let obj = new Son('merry',15);
console.log(obj.name);
console.log(obj.age);
运行结果:
merry
15
bind():
1)将函数绑定新的this
指向并且固定传入几个变量
let arg = {};
function myFun(...args){
console.log(args)
}
let obj = myFun.bind(arg,'小明', '小红');
obj('小华', '小丽');
运行结果:
["小明", "小红", "小华", "小丽"]
这个例子在绑定时候传入了两个参数,之后调用新函数再传入别的参数,调用时传入的参数会排在后面。
对于三个方法的选取原则:
(1)不关心具体有多少参数被传入函数,用apply();
(2)确定函数可接收多少个参数,并且想一目了然表达形参和实参的对应关系,用call();
(3)想要将来再调用方法,不需立即得到函数返回结果,用bind()。