是否可以在不使用“new”关键字的情况下使用Javascript原型?

时间:2015-02-17 22:41:26

标签: javascript oop prototype

Javascript使用函数创建对象的事实起初让我很困惑。像这样的例子通常用于突出原型在Javascript中的工作方式:

function Car(){
  this.setModel=function(model){
    this.model=model;
  }
  this.getModel=function(){
    return this.model;
  }
}

function Bus(){}
Bus.prototype=new Car();

var obj=new Bus();
obj.setModel('A Bus');
alert(obj.getModel('A Bus');

是否可以在不使用new FunctionName()的情况下使用原型?即像这样的东西:

var Car={
  setModel:function(model){
    this.model=model;
  },
  getModel:function(){
    return this.model
  }
}

var Bus={
  prototype:Car;
};

var obj=Bus;
obj.setModel('A Bus');
alert(obj.getModel());

这不使用函数和new来创建对象。相反,它直接创建对象。

这可能没有Object.__proto__等已弃用的功能或Object.setPrototypeOf()等实验性功能吗?

6 个答案:

答案 0 :(得分:2)

Object.create为您提供所需的行为,但您必须将其称为new而不是

// Using ES6 style methods here
// These translate directly to
// name: function name(params) { /* implementation here */ }
var Car = {
 setModel(model) {
    this.model = model;
  },
  getModel() {
    return this.model
  }
};

var Bus = Object.create(Car);

var obj = Object.create(Bus);
obj.setModel('A Bus');
alert(obj.getModel());

或者,您可以使用new ES 2015's __proto__ property在声明时设置原型:

var Bus = {
  __proto__: Car
};

// You still need Object.create here since Bus is not a constructor
var obj = Object.create(Bus);
obj.setModel('A Bus');
alert(obj.getModel());

一些附加说明

除非你需要私有状态,否则你应该将方法添加到Car.prototype而不是构造函数内部(这样只有setModel方法的一个实例,而不是每个类实例的方法的一个实例):

function Car() {}
Car.prototype.setModel = function(model) { this.model = model; };
Car.prototype.getModel = function(model) { return this.model; };

即使使用构造函数,也可以使用new Car绕过Object.create奇怪:

function Bus {}
Bus.prototype = Object.create(Car);

答案 1 :(得分:1)

Crockford在The Good Parts中对这个主题有很好的篇章。

在其中,他指出了在构造函数上使用new的一个重大缺陷:

  

更糟糕的是,使用构造函数存在严重的危险。如果在调用构造函数时忘记使用新前缀,那么这将不会绑定到新对象...没有编译警告,也没有运行时警告。

(你可能已经意识到这一点,因此你的问题,但值得重申)

他建议的解决方案是推荐一个主页Object.create(好的部分比ES5早一点,但这个想法与其他答案中提到的原生版本相同)。

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        var F = function () { };
        F.prototype = o;
        return new F();
    };
}

Object.create获取一个对象的实例作为原型并返回一个实例。

使用的例子非常类似于你的“像这样的例子”(除了Crocky使用哺乳动物和猫而不是汽车和公共汽车):

var car = {
  setModel:function(model){
    this.model=model;
  },
  getModel:function(){
    return this.model
  }
};

var bus = Object.create(car);

bus.setModel('A Bus');
alert(bus.getModel());

答案 2 :(得分:0)

您可以使用Object.create()来实现。以下是使用此原型继承的原始示例:

// Car constructor
var Car = function() {};
Car.prototype = {
    setModel: function(){},
    getModel: function(){}
};

// Bus constructor
var Bus = function() {
    Car.call(this); // call the parent ctor
};

Bus.prototype = Object.create(Car.prototype); // inherit from Car

var my_bus = new Bus(); // create a new instance of Bus
console.log(my_bus.getModel());

答案 3 :(得分:0)

Prototypes允许您从其他对象实例创建新的对象实例。新实例独立存在,可以根据需要进行更改。

var bus = Object.clone(Car.prototype);
bus.number = '3345';
bus.route = 'Chicago West Loop';
bus.setModel('A bus');

答案 4 :(得分:0)

一种方法 - 创建Car并使用Object.create制作副本,然后根据需要扩展总线功能

(function () {

  "use strict";
  
   var setModel = function (model) {
    this.model = model;
  };

  var getModel = function () {
    return this.model;
  };

  var iAmBus = function () {
    alert("only a bus!");
  };

  var Car = {
      setModel: setModel,
      getModel: getModel
    };

  var Bus = Object.create(Car);

  // own bus property, not in the car
  Bus.iAmBus = iAmBus;

  var bus = Object.create(Bus);
  bus.setModel('A Bus');
  alert(bus.getModel());

  var car = Object.create(Car);
  car.setModel('A Car');
  alert(car.getModel());

  //inspect bus and car objects, proving the different object structure
  console.log(bus);
  console.log(car);
  console.log(Bus);
  console.log(Car);

}());

答案 5 :(得分:0)

使用实例作为原型以继承显示缺乏对原型的理解。 Prototype在Child的原型上共享成员和Parent的可变实例成员会让您意想不到的行为。将Car.prototype设置为Object.create(Bus.prototype)已经被其他人所覆盖,如果你想看到构造函数的角色和原型的角色,可能以下答案可能有所帮助:https://stackoverflow.com/a/16063711/1641941

为了演示可能出现的问题,让我们介绍一个名为passengers的实例特定的可变成员,我们希望Bus初始化这个,所以我们不能只使用Jeff的例子照顾原型部分。让我们使用构造函数,但为Car.prototype创建一个Bus实例。

var Bus = function Bus(){
  this.passengers=[];
}
var Car = function Car(){};
Car.prototype = new Bus()
var car1=new Car();
var car2=new Car();
car1.passengers.push('Jerry');
console.log(car2.passengers);//=['Jerry']
  //Yes, Jerry is a passenger of every car you created 
  //and are going to create

可以通过重新使用Parent构造函数(Bus.call(此...稍后提供)来遮蔽实例属性来解决此错误,但Car.prototype仍然有一个没有业务的乘客成员。

如果你想保护人们忘记"新"你可以做到以下几点:

function Car(){
  if(this.constructor!==Car){
    return new Car();
  }
  //re use parent constructor
  Bus.call(this);
}
//Example of factory funcion
Car.create=function(arg){
  //depending on arg return a Car
  return new Car();
};
Car.prototype = Object.create(Bus.prototype);
Car.prototype.constructor = Car;

var car1 = Car();//works
var car2 = new Car();//works
var car3 = Car.create();//works