call, apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例,也就是每个方法都有call, apply属性.既然作为方法的属性,那它们的使用就当然是针对方法的了.这两个方法是容易混淆的,因为它们的作用一样,只是使用方式不同.
相同点: 两个方法产生的作用是完全一样的, apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性.
不同点: 方法传递的参数不同
Function.apply(obj,args)
Function.apply(obj,args)方法能接收两个参数
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args-->arguments)
Function.call(obj,[param1[,param2[,…[,paramN]]]])
Function.call(obj,[param1[,param2[,…[,paramN]]]])
obj:这个对象将代替Function类里this对象
params:这个是一个参数列表
使用场景:(参数数量是不是固定)
当你的参数是明确知道数量时,用 call;
而不确定的时候,用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时;
函数内部也可以通过 arguments 这个数组来遍历所有的参数。
foo.call(this, arg1,arg2,arg3)
== foo.apply(this, arguments)
== this.foo(arg1, arg2, arg3)
function people(){}
people.prototype={
name:"Tom",
say: function(){alert("my name is "+this.name);}
}
var Tom = new people;
Tom.say();
如果我们有一个对象Li = {name:”Li”},我们不想对它重新定义say方法,那么我们可以通过 call() 或 apply() 用 Tom 的say方法:
var Li = {name:"Li"}
Tom.say.call(Li);
call 和 apply 是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。
应用场景:
通过document.getElementsByTagName选择的dom 节点是一种类似array的array。它不能应用Array下的push,pop等方法。
我们可以通过:
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"),0);
这样domNodes就可以应用Array下的所有方法了。
猫吃鱼,狗吃肉,奥特曼打小怪兽。
有天狗想吃鱼了
猫.吃鱼.call(狗,鱼)
狗就吃到鱼了
猫成精了,想打怪兽
奥特曼.打小怪兽.call(猫,小怪兽)
ECMAScript6 引入了一套新的关键字用来实现 class。
JavaScript 仍然基于原型。这些新的关键字包括 class, constructor,static,extends 和 super。
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
class Square extends Polygon {
constructor(sideLength) {
super(sideLength, sideLength);
}
get area() {
return this.height * this.width;
}
set sideLength(newLength) {
this.height = newLength;
this.width = newLength;
}
}
var square = new Square(2);
性能
在原型链上查找属性比较耗时,另外,试图访问不存在的属性时会遍历整个原型链。
要检查对象是否具有自己定义的属性,而不是其原型链上的某个属性,则必须使用所有对象从Object.prototype继承的 hasOwnProperty 方法。
扩展内置原型的唯一理由是支持JavaScript 引擎的新特性,如Array.forEach。