存在call和apply的意义
function cat(){
}
cat.prototype={
food:"fish",
say: function(){
console.log("I love "+this.food);
}
}
var blackCat = new cat;
blackCat.say() //I love fishI love fish
我们定义了一个构造函数cat,又在cat的原型里边定义了一个方法say,实例化了一个对象blackcat,调用原型里边的say方法
但是如果我们有一个对象whiteDog = {food:"bone"},我们不想对它重新定义say方法,那么我们可以通过call或apply用blackCat的say方法:blackCat.say.call(whiteDog);
function cat(){
}
cat.prototype={
food:"fish",
say: function(){
console.log("I love "+this.food);
}
}
var blackCat = new cat;
blackCat.say() //I love fishI love fish
var whiteDog = {food:"bone"},
blackCat.say.call(whiteDog) //I love bone
所以,可以看出call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作
定义
call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向apply([thisObj [,argArray] ])
调用一个对象的一个方法,另一个对象替换当前对象
apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组
//例1
<script>
window.number = 'one';
document.number = 'two';
var s1 = {number: 'three' };
function changeColor(){
console.log(this.number);
}
changeColor.apply(); //one (默认传参)
changeColor.apply(window); //one
changeColor.apply(document); //two
changeColor.apply(this); //one
changeColor.apply(s1); //three
</script>
//例2
function Pet(words){
this.words = words;
this.speak = function () {
console.log( this.words)
}
}
function Dog(words){
//Pet.call(this, words); //结果: Wang
Pet.apply(this, arguments); //结果: Wang
}
var dog = new Dog('Wang');
dog.speak();
call([thisObject[,arg1 [,arg2 [,…,argn]]]])
应用某一对象的一个方法,用另一个对象替换当前对象
call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来
<script>
window.color = 'red';
document.color = 'yellow';
var s1 = {color: 'blue' };
function changeColor(){
console.log(this.color);
}
changeColor.call(); //red (默认传递参数)
changeColor.call(window); //red
changeColor.call(document); //yellow
changeColor.call(this); //red
changeColor.call(s1); //blue
</script>
//例2
var Pet = {
words : '...',
speak : function (say) {
console.log(say + ''+ this.words)
}
}
Pet.speak('Speak'); // 结果:Speak...
var Dog = {
words:'Wang'
}
//将this的指向改变成了Dog
Pet.speak.call(Dog, 'Speak'); //结果: SpeakWang
区别
call对象后面的参数是参数列表,而apply对象后面的参数是数组
function add(c,d){
return this.a + this.b + c + d;
}
var s = {a:1, b:2};
console.log(add.call(s,3,4)); // 1+2+3+4 = 10
console.log(add.apply(s,[5,6])); // 1+2+5+6 = 14
类数组
这里把符合以下条件的对象称为类数组
1.具有length属性
2.按索引方式存储数据
3.不具有数组的push,pop等方法
常见类数组有 arguments,NodeList
(function(){
Array.prototype.push.call(arguments,4);
console.log(arguments);//[1, 2, 3, 4]
})(1,2,3)
这样就往arguments中push一个4进去了
Array.prototype.push 页可以实现两个数组合并
同样push方法没有提供push一个数组,但是它提供了push(param1,param,…paramN) 所以同样也可以通过apply来装换一下这个数组,即
var arr1=new Array("1","2","3");
var arr2=new Array("4","5","6");
Array.prototype.push.apply(arr1,arr2);
console.log(arr1);//["1", "2", "3", "4", "5", "6"]
也可以这样理解,arr1调用了push方法,参数是通过apply将数组装换为参数列表的集合
再比如我想求类数组中的最大值
(function(){
var maxNum = Math.max.apply(null,arguments);
console.log(maxNum);//56
})(34,2,56);
判断类型
console.log(Object.prototype.toString.call(123)) //[object Number]
console.log(Object.prototype.toString.call('123')) //[object String]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
console.log(Object.prototype.toString.call(true)) //[object Boolean]
console.log(Object.prototype.toString.call({})) //[object Object]
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call(function(){})) //[object Function]