两者之间有什么区别

var A = function () {
    this.x = function () {
        //do something
    };
};

and

var A = function () { };
A.prototype.x = function () {
    //do something
};

当前回答

当您使用原型时,函数只会被加载到内存中一次(取决于您创建的对象数量),并且您可以随时重写该函数。

其他回答

让我给你一个我在JavaScript培训课程中学到的更全面的答案。

大多数答案已经提到了这一点,即当原型化时,功能与所有(未来)实例共享。而在类中声明函数将为每个实例创建一个副本。

总的来说,没有对错之分,更多的是品味或设计决定,取决于您的需求。然而,原型是用于以面向对象的方式进行开发的技术,我希望您会在答案的结尾看到。

你的问题显示了两种模式。我将尝试再解释两个,并尝试解释相关的差异。随意编辑/扩展。在所有示例中,它都是关于一个具有位置并可以移动的汽车对象。

对象装饰器图案

不确定这种模式现在是否仍然适用,但它确实存在。知道这一点很好。您只需将对象和属性传递给decorator函数。装饰器返回带有属性和方法的对象。

var carlike = function(obj, loc) {
    obj.loc = loc;
    obj.move = function() {
        obj.loc++;
    };
    return obj;
};

var amy = carlike({}, 1);
amy.move();
var ben = carlike({}, 9);
ben.move();

功能类别

JavaScript中的函数是一个专门的对象。除了被调用外,函数还可以像其他任何对象一样存储财产。

在本例中,Car是一个函数(也称为对象),可以按照您的习惯进行调用。它有一个属性方法(这是一个带有移动函数的对象)。当调用Car时,会调用extend函数,这会产生一些魔力,并使用方法中定义的方法扩展Car函数(think对象)。

这个例子虽然不同,但最接近问题中的第一个例子。

var Car = function(loc) {
    var obj = {loc: loc};
    extend(obj, Car.methods);
    return obj;
};

Car.methods = {
    move : function() {
        this.loc++;
    }
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

原型类

前两种模式允许讨论使用技术来定义共享方法或使用在构造函数主体中内联定义的方法。在这两种情况下,每个实例都有自己的移动功能。

原型模式不适合同样的检查,因为通过原型委托共享功能是原型模式的目标。正如其他人所指出的,预计它的内存占用量会更好。

然而,有一点值得注意:每个原型对象都有一个方便的属性构造函数,它指向它所附加的函数(think对象)。

关于最后三行:

在本例中,Car链接到原型对象,该对象通过构造函数链接到Car本身,即Car.prototype.constructor是Car本身。这允许您确定哪个构造函数构建了某个对象。

amy.constructor的查找失败,因此被委托给Car.prototype,它确实具有构造函数属性。所以我的结构是Car。

此外,amy是Car的一个例子。instanceof运算符的工作方式是查看右操作数的原型对象(Car)是否可以在左操作数的模型(amy)链中的任何位置找到。

var Car = function(loc) {
    var obj = Object.create(Car.prototype);
    obj.loc = loc;
    return obj;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

console.log(Car.prototype.constructor);
console.log(amy.constructor);
console.log(amy instanceof Car);

一些开发人员一开始可能会感到困惑。参见以下示例:

var Dog = function() {
  return {legs: 4, bark: alert};
};

var fido = Dog();
console.log(fido instanceof Dog);

instanceof运算符返回false,因为在fido的原型链中的任何位置都找不到Dog的原型。fido是一个用对象文字创建的简单对象,即它只委托给object.prototype。

伪经典模式

这实际上只是简化形式的原型模式的另一种形式,对于用Java编程的人来说更为熟悉,因为它使用了新的构造函数。

它确实和原型模式一样,它只是原型模式的句法糖份。

然而,主要区别在于JavaScript引擎中实现的优化仅在使用伪经典模式时适用。把伪经典模式想象成原型模式的更快版本;两个示例中的对象关系相同。

var Car = function(loc) {
    this.loc = loc;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = new Car(1);
amy.move();
var ben = new Car(9);
ben.move();

最后,实现面向对象的编程应该不会太难。有两个部分。

定义原型(链)中常见财产/方法的一个部分。

在另一节中,您放置了区分对象的定义(示例中的loc变量)。

这就是允许我们在JavaScript中应用超类或子类等概念的原因。

可以随意添加或编辑。一旦完成,我可能会把它变成一个社区维基。

第一个示例仅更改该对象的接口。第二个示例更改该类的所有对象的接口。

当您使用原型时,函数只会被加载到内存中一次(取决于您创建的对象数量),并且您可以随时重写该函数。

每个对象都链接到原型对象。当试图访问不存在的属性时,JavaScript将在对象的原型对象中查找该属性,如果该属性存在,则返回该属性。

函数构造函数的prototype属性引用使用new时使用该函数创建的所有实例的原型对象。


在第一个示例中,您将向使用a函数创建的每个实例添加属性x。

var A = function () {
    this.x = function () {
        //do something
    };
};

var a = new A();    // constructor function gets executed
                    // newly created object gets an 'x' property
                    // which is a function
a.x();              // and can be called like this

在第二个示例中,您将向原型对象添加一个属性,所有使用a创建的实例都指向该属性。

var A = function () { };
A.prototype.x = function () {
    //do something
};

var a = new A();    // constructor function gets executed
                    // which does nothing in this example

a.x();              // you are trying to access the 'x' property of an instance of 'A'
                    // which does not exist
                    // so JavaScript looks for that property in the prototype object
                    // that was defined using the 'prototype' property of the constructor

总之,在第一个示例中,函数的副本被分配给每个实例。在第二个示例中,所有实例共享函数的单个副本。

我知道这已经得到了答案,但我想展示一个速度差异的实际例子。

直接作用于对象:

函数ExampleFn(){this.print=函数(){console.log(“正在调用打印!”);}}var对象=[];控制台时间('x');for(设i=0;i<2000000;i++){objects.push(new ExampleFn());}console.timeEnd('x');//x: 1151.960693359375毫秒

原型上的功能:

函数ExampleFn(){}ExampleFn.prototype.print=函数(){console.log(“正在调用打印!”);}var对象=[];控制台时间('y');for(设i=0;i<2000000;i++){objects.push(new ExampleFn());}console.timeEnd('y');//x: 617.866943359375毫秒

在这里,我们使用Chrome中的打印方法创建了2000000个新对象。我们将每个对象存储在一个数组中。在原型上打印大约需要1/2的时间。