call、apply、bind作用是改变函数执行是的上下文,也就是改变函数运行时的this指向
let obj = {name:"cyy"};
function Child(name){
this.name = name;
}
Child.prototype = {
constructor:Child,
showName:function(){
console.log(this.name);
}
}
var child = new Child("kiruthika");
child.showName(); //kiruthika
// call,apply,bind使用
child.showName.call(obj)
child.showName.apply(obj)
let bind = child.showName.bind(obj) //返回一个函数
bind() // cyy
bind方法是事先把fn的this改变为其我们提供想要的结果,并且把对应的参数值准备好,以后要用到了,直接的执行即可,也就是说bind同样可以改变this的指向,但和apply、call不同就是不会马上执行
- call、apply与bind的区别
call和apply改变了函数的this上下文后便执行该函数,而bind则是返回改变了上下文后的一个函数。
- call、apply的区别
call与apply存在与参数的差别,call和apply的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为他的第二个参数
let arr = [1,3,5,24,6];
console.log(Math.max.call(null,1,3,5,24,6))//24
console.log(Math.max.call(null,arr))//NAN
console.log(Math.max.apply(null,arr))//24 apply可以直接用数组arr传递进去
function fn(){
console.log(this)
}
fn.call()// 普通模式下this是window,在严格模式下this是undefined
fn.call(null)// 普通模式下this是window,在严格模式下this是null
fn.call(undefined)// 普通模式下this是window,在严格模式下this是undefined
项目应用:
将伪数组转化为数组(含有length属性的对象,dom节点,函数的参数arguments)
js中的伪数组具有length属性,并且可以通过0,1, 2…下标来访问其中的元素,但是没有Array中的push、unshift等方法。就可以利用call、apply来转化成真正的数组,就可以使用其数组中的方法了
<div class="content">1</div>
<div class="content">2</div>
<div class="content">3</div>
以下写法不适用于IE6-8 , 会报错:Array.prototype.slice:‘this’ 不是 Javascript对象
let contents = document.getElementsByClassName("content");
console.log(contents)//callApplyBind.html:53 HTMLCollection(3) [div.content, div.content, div.content]0: div.content1: div.content2: div.contentlength: 3__proto__: HTMLCollection
console.log(contents.length)
let contentsArr = Array.prototype.slice.call(contents)
console.log(contentsArr)//callApplyBind.html:58 (3) [div.content, div.content, div.content]
在IE6-8写法:
let ary = []
for(var i =0; i < contents.length; i++){
ary[ary.length] = contents[i]
}
//基于IE6-8和标准浏览器中的区别,抽取出类数组对象转化为数组的工具类:
function listToArray(likeAry) {
let ary = [];
try{
ary = Array.prototype.slice.call(likeAry)
} catch(e){
for(var i = 0; i < likeAry.length; i++){
ary[ary.length] = likeAry[i]
}
}
return ary;
}
对于arguments借用数组的方法是不存在任何兼容性问题的
function toArray() {
return Array.prototype.slice.call(arguments)
}
console.log(toArray(1,4,45,465,65))//callApplyBind.html:82 (5) [1, 4, 45, 465, 65]
- 含有length属性的对象
let anyObj = {
0:3,
1:'haier',
2:44,
length:3
};
console.log(Array.prototype.slice.call(anyObj))//callApplyBind.html:90 (3) [3, "haier", 44]
- 数组拼接,添加
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = arr1.concat(arr2);
console.log(arr3)//callApplyBind.html:96 (6) [1, 2, 3, 4, 5, 6]
console.log(arr1);// [1, 2, 3]
console.log(arr2);// [4, 5, 6]
[].push.apply(arr1,arr2); // 给arr1添加arr2
console.log(arr1);//[1, 2, 3, 4, 5, 6]
console.log(arr2);// [4, 5, 6]
- 判断变量类型
let ary1 = [1,2,4];
let str1 = 'str';
let obj1 = {name:'holmes'};
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]'
}
console.log(isArray(ary1)) // true
console.log(Object.prototype.toString.call(ary1))//callApplyBind.html:116 [object Array]
console.log(Object.prototype.toString.call(str1))//callApplyBind.html:116 [object String]
console.log(Object.prototype.toString.call(obj1))//callApplyBind.html:116 [object Object]
console.log(Object.prototype.toString.call(null))//callApplyBind.html:119 [object Null]
- 利用call和apply做继承
function Animal(name) {
this.name = name;
this.showName = function () {
console.log(this.name)
}
}
function Cat(name) {
Animal.call(this,name);
}
let cat = new Cat('mimi');
cat.showName();//mimi
- 多继承
function Class1(a,b){
this.showclass1 = function(a,b){
console.log(`class1:${a},${b}`)
}
}
function Class2(a,b){
this.showclass2 = function(a,b){
console.log(`class2:${a},${b}`);
}
}
function Class3(a,b,c){
Class1.call(this);
Class2.call(this);
}
let ary0 = [5,6];
let demo = new Class3();
demo.showclass1.call(this,1);//class1:1,undefined
demo.showclass1.call(this,1,2);//class1:1,2
demo.showclass2.apply(this,ary0);//class2:5,6