是否可以在不使用 "new" 关键字的情况下使用 Javascript 原型?
Is it possible to using Javascript prototypes without using the "new" keyword?
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()
的情况下使用原型? IE。像这样:
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()
这样的实验功能,这是否可能?
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
方法,而不是每个 class 实例一个方法实例):
function Car() {}
Car.prototype.setModel = function(model) { this.model = model; };
Car.prototype.getModel = function(model) { return this.model; };
即使使用构造函数,您也可以使用 Object.create
来解决 new Car
的奇怪问题:
function Bus {}
Bus.prototype = Object.create(Car);
可以使用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());
原型允许您从其他对象实例创建新的对象实例。新实例独立存在,可以根据需要进行更改。
var bus = Object.clone(Car.prototype);
bus.number = '3345';
bus.route = 'Chicago West Loop';
bus.setModel('A bus');
Crockford 在 The Good Parts.
中有一个关于这个主题的很好的章节
他在其中指出了在构造函数上使用 new
的一大缺陷:
Even worse, there is a serious hazard with the use of constructor functions. If you forget to use the new prefix when calling a constructor function, then this will not be bound to a new object... There is no compile warning, and there is no runtime warning.
(您可能已经意识到这一点,因此您的问题,但值得重申)
他提出的解决方案是推荐一个home rolled Object.create
(The Good Parts比ES5早一点,但是思路和其他答案中提到的原生版本是一样的)
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () { };
F.prototype = o;
return new F();
};
}
Object.create
使用一个对象实例作为原型,returns 一个实例。
使用的示例与您的 "something like this" 示例非常相似(除了 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());
一种方法 - 创建一个 Car 并使用 Object.create 进行复制,然后根据需要扩展 Bus 功能
(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);
}());
为了继承而使用实例作为原型,说明对原型是什么缺乏理解。 Prototype 共享成员,并且 Parent 的可变实例成员在 Child 的原型上会让您出现非常意外的行为。将 Car.prototype 设置为 Object.create(Bus.prototype) 已经被其他人覆盖,如果你想看到构造函数的作用和原型的作用,也许下面的答案可以帮助:
为了演示可能出错的地方,让我们引入一个名为 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 仍然有一个乘客成员没有业务那里。
如果你想防止人们再次忘记 "new",你可以执行以下操作:
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
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()
的情况下使用原型? IE。像这样:
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()
这样的实验功能,这是否可能?
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
方法,而不是每个 class 实例一个方法实例):
function Car() {}
Car.prototype.setModel = function(model) { this.model = model; };
Car.prototype.getModel = function(model) { return this.model; };
即使使用构造函数,您也可以使用 Object.create
来解决 new Car
的奇怪问题:
function Bus {}
Bus.prototype = Object.create(Car);
可以使用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());
原型允许您从其他对象实例创建新的对象实例。新实例独立存在,可以根据需要进行更改。
var bus = Object.clone(Car.prototype);
bus.number = '3345';
bus.route = 'Chicago West Loop';
bus.setModel('A bus');
Crockford 在 The Good Parts.
中有一个关于这个主题的很好的章节他在其中指出了在构造函数上使用 new
的一大缺陷:
Even worse, there is a serious hazard with the use of constructor functions. If you forget to use the new prefix when calling a constructor function, then this will not be bound to a new object... There is no compile warning, and there is no runtime warning.
(您可能已经意识到这一点,因此您的问题,但值得重申)
他提出的解决方案是推荐一个home rolled Object.create
(The Good Parts比ES5早一点,但是思路和其他答案中提到的原生版本是一样的)
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () { };
F.prototype = o;
return new F();
};
}
Object.create
使用一个对象实例作为原型,returns 一个实例。
使用的示例与您的 "something like this" 示例非常相似(除了 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());
一种方法 - 创建一个 Car 并使用 Object.create 进行复制,然后根据需要扩展 Bus 功能
(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);
}());
为了继承而使用实例作为原型,说明对原型是什么缺乏理解。 Prototype 共享成员,并且 Parent 的可变实例成员在 Child 的原型上会让您出现非常意外的行为。将 Car.prototype 设置为 Object.create(Bus.prototype) 已经被其他人覆盖,如果你想看到构造函数的作用和原型的作用,也许下面的答案可以帮助:
为了演示可能出错的地方,让我们引入一个名为 passengers
的特定于实例的可变成员,我们希望 Bus 对其进行初始化,这样我们就不能使用 Jeff 的示例,因为它只处理原型部分。让我们使用构造函数,但为 Car.prototype.
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 仍然有一个乘客成员没有业务那里。
如果你想防止人们再次忘记 "new",你可以执行以下操作:
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