属性访问器可以在Javascript中使用原型

时间:2017-05-10 08:36:21

标签: javascript

我的问题遵循以下代码示例:

// Factory Constructor
function CarFactory() {
}

CarFactory.prototype.info = function () {
    console.log("This car has " + this.doors + " doors and a " + this.engine_capacity + " liter engine");
};

// the static factory method
CarFactory.make = function (type) {
    var constr = type;
    var car;
    CarFactory[constr].prototype = new CarFactory();
    // create a new instance
    car = new CarFactory[constr]();
    return car;
};

CarFactory.Compact = function () {
    this.doors = 4;
    this.engine_capacity = 2;
};

CarFactory.Sedan = function () {
    this.doors = 2;
    this.engine_capacity = 2;
};

CarFactory.SUV = function () {
    this.doors = 4;
    this.engine_capacity = 6;
};

var golf = CarFactory.make('Compact');
var vento = CarFactory.make('Sedan');
var touareg = CarFactory.make('SUV');
golf.info(); //"This car has 4 doors and a 2 liter engine"

我理解如何使用prototype属性为函数添加其他属性。但是,在此代码示例中,我发现特殊的代码行是:

CarFactory[constr].prototype = new CarFactory();

这里,CarFactory [constr]是一个属性访问者。这可能是这样写的:

CarFactory.Sedan.prototype = new CarFactory();

此示例中的Sedan是一个属性。但是到目前为止我见过的大多数示例都是直接在主对象上附加新属性或函数。例如:

CarFactory.prototype.manufacturer = new Manufacturer();

因此,声明prototype属性用于向现有属性或函数添加新属性或函数是真的吗?

1 个答案:

答案 0 :(得分:2)

CarFactory.SedanCarFactory.CompactCarFactory.SUV都是构造函数(如CarFactory本身就是)。所以他们有一个名为prototype的属性,它引用了将用作通过new CarFactory.Sedan等创建的对象原型的对象。

这些函数(SedanCompactSUV)也通过CarFactory上的属性引用的事实对它们是构造函数的事实没有任何影响。

  

因此,声明prototype属性用于向现有属性或函数添加新属性或函数是真的吗?

确实,构造函数的prototype属性指的是将用作通过new使用该函数创建的对象原型的对象。因此,添加到该对象会添加通过原型继承可用于这些对象的功能。

但是,该代码存在一些问题,特别是在make函数中:

  1. 每次调用CarFactory时,重新创建新的CarFactory[constr].prototype对象并将其分配给make是没有意义的。它为make创建的每个对象创建了一个新原型,这是毫无意义的。原型的主要目的是重用。
  2. 通常,使用new Xyz创建一个对象以放置另一个构造函数的prototype属性通常是反模式的一部分。 (在这种情况下它是无害的,CarFactory没有采取任何参数;在一般情况下,它的做法很差。)
  3. 我完全设置了汽车类型(Sedan等),而不是部分设置它们,然后重复使用它们。以下是最低更改:

    
    
    var CarFactory = (function() {
        // Factory Constructor
        function CarFactory() {
        }
    
        // Prototype methods
        CarFactory.prototype.info = function() {
            console.log("This car has " + this.doors + " doors and a " + this.engine_capacity + " liter engine");
        };
    
        // The static factory method
        CarFactory.make = function(type) {
            var ctor = CarFactory[type];
            if (!ctor) {
                throw new Error("Unknown type '" + type + "'");
            }
            return new ctor();
        };
    
        // Function to create types of cars
        function makeCarType(ctor) {
            ctor.prototype = Object.create(CarFactory.prototype);
            ctor.prototype.constructor = ctor;
            return ctor;
        }
    
        // Types
        CarFactory.Compact = makeCarType(function() {
            this.doors = 4;
            this.engine_capacity = 2;
        });
    
        CarFactory.Sedan = makeCarType(function() {
            this.doors = 2;
            this.engine_capacity = 2;
        });
    
        CarFactory.SUV = makeCarType(function() {
            this.doors = 4;
            this.engine_capacity = 6;
        });
    
        return CarFactory;
    })();
    
    var golf = CarFactory.make('Compact');
    var vento = CarFactory.make('Sedan');
    var touareg = CarFactory.make('SUV');
    golf.info(); //"This car has 4 doors and a 2 liter engine"
    vento.info(); //"This car has 2 doors and a 2 liter engine"
    touareg.info(); //"This car has 4 doors and a 6 liter engine"
    
    
    

    更重要的更改可能是使用ES2015 + class语法并完全取消CarFactory.make