apply、call、bind的区别和应用
作用:改变函数体内部的this
指向
- apply/call
// case1 改变this指向
var color = 'red';
var obj = {
color: 'green',
sayColor: function () {
return this.color
}
};
console.log(obj.sayColor()); // green
// this的指向和定义的位置无关,只和执行的环境有关
var c1 = obj.sayColor;
console.log(c1());
// 使用bind,将this的指向改回到obj对象
var c2 = obj.sayColor.bind(obj);
console.log(c2());
// 使用apply改变this指向
var c3 = obj.sayColor.apply(obj);
console.log("c3:" + c3); // green
// 使用call改变this指向
var c4 = obj.sayColor.call(obj);
console.log("c4:" + c4); // green
- bind
// case1 改变this指向
var color = 'red';
var obj = {
color: 'green',
sayColor: function () {
return this.color
}
};
console.log(obj.sayColor()); // green
// this的指向和定义的位置无关,只和执行的环境有关
var c1 = obj.sayColor;
console.log(c1()); // red
// 使用bind,将this的指向改回到obj对象
var c2 = obj.sayColor.bind(obj);
console.log(c2()); // green
区别:
call
和apply
改变了函数的this
后便执行该函数;而bind
则是返回改变了this
后的一个函数, 需要的时候执行。call
和aplly
的第一个参数都是要改变this
指向的对象,而call
从第二个参数开始以参数列表的形式展现,apply
则是把除了改变上下文对象的参数放在一个数组里面
ps. bind()这个方法在ie6~8下不兼容
let arr1 = [1, 2, 19, 6];
//例子:求数组中的最值
console.log(Math.max.call(null, 1,2,19,6)); // 19
console.log(Math.max.apply(null, arr1)); // 19 直接可以用arr1传递进去
应用
- 将伪数组转化为数组
js中的伪数组(例如通过document.getElementsByTagName获取的元素、含有length属性的对象)具有length属性,并且可以通过0、1、2…下标来访问其中的元素,但是没有Array中的push、pop等方法。就可以利用call,apply来转化成真正的数组,就可以使用数组的方法了
// DOM节点处理
<div class="div1">1</div>
<div class="div1">2</div>
<div class="div1">3</div>
let div = document.getElementsByTagName('div');
console.log(div); // HTMLCollection(3) [div.div1, div.div1, div.div1] 里面包含length属性
let arr2 = Array.prototype.slice.call(div);
console.log(arr2); // 数组 [div.div1, div.div1, div.div1]
// 处理arguments
function foo(){
return Array.prototype.slice.call(arguments);
}
console.log(foo(1,2,3,4,5)); // [1,2,3,4,5]
- 数组拼接、添加
let arr1 = [1,2,3];
let arr2 = [4,5,6];
//数组的concat方法:返回一个新的数组
let arr3 = arr1.concat(arr2);
console.log(arr3); // [1, 2, 3, 4, 5, 6]
console.log(arr1); // [1, 2, 3] 不变
console.log(arr2); // [4, 5, 6] 不变
// 用 apply方法
[].push.apply(arr1,arr2); // 给arr1添加arr2
console.log(arr1); // [1, 2, 3, 4, 5, 6]
console.log(arr2); // 不变
- 判断数据类型
let arr1 = [1,2,3];
let str1 = 'string';
let obj1 = {name: 'thomas'};
//
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
console.log(fn1(arr1)); // true
// 判断类型的方式,这个最常用语判断array和object,null(因为typeof null等于object)
console.log(Object.prototype.toString.call(arr1)); // [object Array]
console.log(Object.prototype.toString.call(str1)); // [object String]
console.log(Object.prototype.toString.call(obj1)); // [object Object]
console.log(Object.prototype.toString.call(null)); // [object Null]
- 利用call和apply作继承
function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}
function Cat(name){
Animal.call(this, name);
}
// Animal.call(this) 的意思就是使用this对象代替Animal对象,那么
// Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了
var cat = new Cat("TONY");
cat.showName(); //TONY
- 函数借用
var arr = [1,2,3,4,5,6];
var max = Math.max.apply(null, arr);
var min = Math.min.apply(null, arr);
console.log(max); // 6
console.log(min); // 1