函数和函数原型上的方法问题

FunctionFunction.prototype都有call(),为什么有Object.call(),而Object.prototype没有call()? 还有freeze()等等

clipboard.png

阅读 2.2k
4 个回答

因为call这个方法是挂载到Function的原型上的, 而所有的 函数 都是由 Function 创造出来的

所以

  • Function 是由 Function 创造出来的 它是Function的实例 他能调用 Function 原型上的方法

  • Function.prototype 就不用说了,本来就是他自己的方法

  • Object 是由 Function 创造出来的的 ...

  • Object.prototype 不是函数

在计算机语言里,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函数在内存中创建了两次,而且代码相同,这样是一种浪费。(由于属性xp1p2中保存不同的值,所以创建两个是必须的,可是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是类型名称,所以也是函数,所以FunctionFunction类型的变量。(上面说过,函数名可以和类型名重名,或者说故意让他们重名,而不会在代码里有歧义)所以有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;

因为Object.prototype是个Object对象,而Object是个函数。

图片描述

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题