作为前端,call和apply再熟悉不过,今天我们就来谈谈这两个东西~
1. call和apply的区别
call和apply的用途是一样的,只是它们接收参数的方式不同
- apply 接受两个参数,第一个指定了函数体内this的指向,第二个参数为
带下标的集合,可以是数组或类数组
- call 同样接受两个参数,第一个为函数体内this的指向,从第二个参数开始往后,参数依次被传入函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14var func1 = function(a,b,c){
console.log( [a,b,c] );
}
func1.apply( null,[1,2,3] ) //[1,2,3]
func1.apply( null,[1,2,3,4] ) //[1,2,3]
func1.apply( null,[1,2] ) //[1,2,undefined]
var func2 = function( a,b,c ){
console.log( [a,b,c] );
};
func2.call( null,1,2,3 ) //[1,2,3]
func2.call( null,1,2,3,4 ) //[1,2,3]
func2.call( null,1,2 ) //[1,2,undefined]
JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时,用 call,而不确定的时候,用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来便利所有的参数。
call和apply的第一个参数为null时1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 在使用call或apply时,如果第一个参数传入的是null,函数体的this就会指向默认的宿主对象,在浏览器中是window
var func1 = function( a, b, c){
console.log( this === window );
}
func1.apply( null, [1,2,3] ) //true
// 在严格模式下this还是指向null
var func2 = function( a ,b ,c ){
"use strict"
console.log(this);
};
func2.apply( null, [1,2,3] ); //null
func2.apply( this, [1,2,3] ); //window
func2.apply( [1,2,3] ); //[1,2,3]
2. call和apply的用途
改变this指向
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var obj1 = {
name : 'zhu'
};
var obj2 = {
name : 'wang'
};
window.name = 'mo';
var getName = function(){
console.log( this.name );
}
getName(); //mo
getName.call( obj1 ); //zhu
getName.call( obj2 ); //wang
document.getElementById( 'div1' ).onclick = function(){
var func = function(){
console.log( this.id );
}
func.call( this );
}Function.prototype.bind
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35Function.prototype.bind = function( obj ){
var self = this; //保存原函数
return function(){ //返回新函数
return self.apply( obj, arguments) //修改新函数里的this,使它指向传进来的对象
}
}
var obj1 = {
name : 'zhu'
}
var func = function(){
console.log( this.name )
}.bind( obj1 );
func();
Function.prototype.bind = function(){
var self = this;
var obj = [].shift.apply( arguments ); //找出需要绑定的上下文 obj2
var args = [].slice.apply( arguments ); //[1,2]
return function(){
return self.apply(obj,[].concat.call( args, [].slice.apply( arguments ) ) )
}
}
var obj2 = {
name : 'sun'
};
var func5 = function( a , b , c , d ){
console.log( this.name );
console.log( [a,b,c,d] );
}.bind( obj2, 1,2 );
func5( 4, 5 );
3. 借用其他对象的方法:
1 | //1) 借用构造函数,实现一些类似继承的效果 |
通过这次学习,发现了一下问题:
- [].shift.apply( arguments )这里直接将this指向arguments,等价于
arguments.shift()
; Array.prototype
.push.call()和[].prototype
.push.call()的区别???
[]没有prototype属性,构造函数才有这个属性,一般对象是没有的。要用也应该是[].push.call(…)。要说区别的话,[].push方法就是从Array.prototype继承来的,所以是等价的。不过前者浪费了一个[]对象,更耗一点内存。1
console.log( [] instanceof Array ) //true
B如何使用apply来继承A原型里面的方法??