关键词:
- call:
- 语法:obj.call(thisObj, arg1, arg2, ...);
- 定义:调用一个对象的一个方法,以另一个对象替换当前对象。
- apply:
- 语法:obj.apply(thisObj, [arg1, arg2, ...]);
- 定义:应用某一对象的一个方法,用另一个对象替换当前对象。
看这样一个例子,搞清楚this的指向问题
function add(a, b){console.dir(this);}
function sub(c, d){console.dir(this);}
add(1,2); // Window
sub(1,2); // Window
add.call(sub, 1, 2); // sub(a, b)
sub.apply(add, [1, 2]); // add(a, b)
我们看到,通过apply和call方法改变了this的指向,但是这么做并不会当前改变函数的执行,我们再来看一个例子。
function add(j, k){
console.log(j+k);
}
function sub(j, k){
console.log(j-k);
}
add(5,3); //8
add.call(sub, 5, 3); //8
add.apply(sub, [5, 3]); //8
sub(5, 3); //2
sub.call(add, 5, 3); //2
sub.apply(add,[5,3]); //2
可以看到,使用call和apply方法对函数的正常执行不会产生任何影响。
那我们用apply和call有什么用,答:实现属性的继承
先来考虑一个问题,能不能实现对象之间继承呢?
var Superior = {
name :"长者",
age: 55
}
var Inferior = {};
console.log(Inferior); //Object {} ,空对象
Superior.call(Inferior); //TypeError:Superior.call is not a function
很遗憾地说,对象是不能使用call方法的,只有函数或函数表达式才可以
var Superior = function(){
this.name = "长者";
this.age = 55;
}
var Inferior = {};
console.log(Inferior); //Object {} ,空对象
Superior.call(Inferior);
console.log(Inferior); //Object {name: "长者", age: 55}
Inferior.name = "雾凇"
console.log(Superior.name);
var s = new Superior;
console.log(s.name); // 长者
这样,我们就把superior的属性传给了inferior,并且这种传递不会对superior造成任何影响。
现在,我们对上面的代码做些改动,我们把inferior写成函数表达式的形式
var Superior = function(){
this.name = "长者";
this.age = 55;
}
console.dir(Superior);
var Inferior = function(){
};
console.log(Inferior); // function (){}
Superior.call(Inferior);
console.log(Inferior); // function (){}
在使用了call和apply方法之后还是个空函数,并没有起作用,那现在我们该怎么办呢?
有一种属性的继承方法叫做构造函数伪装
,我在[面向对象的继承][]中有介绍,让我们再来改动一下吧
[面向对象的继承]:http://www.jianshu.com/p/693332d54ddf
var Superior = function(){
this.name = "长者";
this.age = 55;
}
console.dir(Superior);
var Inferior = function(){
Superior.call(this);
};
var s = new Inferior;
console.dir(s.name); // 长者
运行之后,我们发现inferior成功继承了superior的属性,鼓掌哈哈(o)/~~
为了巩固加深印象,我们在做一个小测试吧
function Animal(name) {
this.name = name;
this.showName = function() {
console.log(this.name);
};
}
function Cat(name) {
Animal.call(this, name);
}
Cat.prototype = new Animal();
function Dog(name) {
Animal.apply(this, name);
}
Dog.prototype = new Animal();
var cat = new Cat("Black Cat"); //call必须是object
var dog = new Dog(["Black Dog"]); //apply必须是array
cat.showName();
dog.showName();
console.log(cat instanceof Animal); //true
console.log(dog instanceof Animal); //true
测试完毕!
call和apply还有一个妙用就是输出数据类型
var a = {};
var b = [];
console.log(Object.prototype.toString.call(a)); // 输出为: "[object Object]"
console.log(Object.prototype.toString.call(b)); // 输出为: "[object Array]"
console.log(Object.prototype.toString.apply(a)); // 输出为: "[object Object]"
console.log(Object.prototype.toString.apply(b)); // 输出为: "[object Array]"
具体有多少种方式能判断数据类型请看我的博客文章[js判断数据类型深度解析][]
[js判断数据类型深度解析]:http://www.jianshu.com/p/ee1faf553e51