Function
和Function.prototype
都有call()
,为什么有Object.call()
,而Object.prototype
没有call()
? 还有freeze()
等等
Function
和Function.prototype
都有call()
,为什么有Object.call()
,而Object.prototype
没有call()
? 还有freeze()
等等
在计算机语言里,int a;
定义了一个int
类型的变量a
。其中int
是类型的名字,a
是具体的变量。
Javascript 模仿自 Java, 有一部分面向对象编程的部分。在面向对象的编程中,类就是像int
那样是类型,对象就是具体的变量。比如:
class Point {
constructor(x,y){ //构造函数
this.x=x;this.y=y; // 其中的this 就是创建出来的新对象
}
toString(){ return "(" + this.x +"," + this.y + ")";}
};
// 这样就创建了一个叫做`Point`的类,
var p = new Point(1,2); // 调用构造函数生成一个Point类的对象
// 或者说 Point p = new Point(1,2);
// 即定义了一Point类型的变量 p,赋值为某个值。
p.toString();// "(1,2)"
p.x; // 1
可是 Javascript 是若类型,写出了Point
类型又有什么意义呢,又不能写Point p = xx
。于是在JS里面把类型和函数合二为一。当定义了一个函数,那么这个变量名称既是一个函数也是一个类型的名称,并且这个函数是这个类型的构造函数(也是一个普通的函数)。这样做不会出现歧义,因为没有Point p
这种写法,所以除了p instanceof Point
之外,Point
在JS里面永远指一个函数。
下面要解决的是,Point
类型里面的toString
函数。如果
functioin Point(x,y) { // Point类的构造函数,即上面的 constructor
this.x = x; this.y=y;
this.toString = function() { return "(" + this.x +"," + this.y + ")";}
}
var p1 = new Point(1,2);
var p2 = new Point(3,4);
p1.toString === p2.toString; // False
这样定义Point
类是可行的,可是却存在着问题。可以看出方法toString
其实是定义了两个不同的函数,其代码是一样的。也就是说toString
函数在内存中创建了两次,而且代码相同,这样是一种浪费。(由于属性x
在p1
和p2
中保存不同的值,所以创建两个是必须的,可是toString
不一样)
下面是一种解决方法:
var PointMethod = { // 把所有方法放到一个额外的对象中
toString: function() { return "(" + this.x +"," + this.y + ")";}
toValue: function() { return [this.x,this.y];}
}
functioin Point(x,y) {
this.x = x; this.y=y;
this.__method__ = PointMethod;
}
var p1 = new Point(1,2);
var p2 = new Point(3,4);
//当我们要访问一个方法时
p1.__method__.toString(); // 先不考虑this的问题
p1.__method__.toString === p2.__method__.toString; // true
这样有点儿麻烦,所幸的是JS解释器帮我们做了一些东西,让我们方便的写出和上面工作原理一样的如下代码。
function Point(x,y){
this.x = x; this.y = y;
// 当使用 new Point 的时候自动添加如下代码
// this.__proto__ = Point.pototype;
}
Point.prototype = { // PointMethod
toString: function() { return "(" + this.x +"," + this.y + ")";}
toValue: function() { return [this.x,this.y];}
}
var p1 = new Point(1,2);
var p2 = new Point(3,4);
p1.toString(); // 即 p1.toString? p1.toString:p1.__proto__.toString ...
p1.toString == p2.toString; // true;
由于Object
是类型名称,所以他也是函数。Object
是函数,所以他是Function
类的变量,而所有Function
类的变量(函数)都可以被调用,有call
方法。所有函数类型的方法都在Function.prototype
中,所以有Function.prototype.call
。故此Object.call
是可以的,其实就是Object.__proto__.call
。
Function
是类型名称,所以也是函数,所以Function
是Function
类型的变量。(上面说过,函数名可以和类型名重名,或者说故意让他们重名,而不会在代码里有歧义)所以有Function.call
其实也是 Function.__proto__.call
。
所有对象都是Object
类型的(忽略继承先),Object
类变量的方法都在Object.prototype
中,可是不是所有的对象都能想函数那样被调用,所以不能有call
。
Object instanceof Function; // true
Object.__proto__ === Function.prototype; // true
Function.__proto__ === Function.prototype; // true
var obj = {}; // 等价于 var obj = new Object();
obj.__proto__ === Object.prototype; // true;
10 回答11.4k 阅读
4 回答3.3k 阅读✓ 已解决
2 回答2.9k 阅读✓ 已解决
3 回答2.5k 阅读✓ 已解决
3 回答2.3k 阅读✓ 已解决
2 回答2k 阅读✓ 已解决
4 回答2k 阅读✓ 已解决
因为call这个方法是挂载到Function的原型上的, 而所有的 函数 都是由 Function 创造出来的
所以
Function 是由 Function 创造出来的 它是Function的实例 他能调用 Function 原型上的方法
Function.prototype 就不用说了,本来就是他自己的方法
Object 是由 Function 创造出来的的 ...
Object.prototype 不是函数