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()
等实验性功能吗?
答案 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