原型用于声明一类对象的属性和方法。使用原型的一个优点是它节省了内存,因为类的所有实例都指向原型的属性和方法,这样可以节省内存并有效地允许属性被类的所有实例视为静态。
Prototype用于通过原型链接继承。
我的问题非常简单。为什么在你可以做的时候根本就使用原型:
function car() {
this.engine = "v8";
}
function mustang() {
// nm, no good way to inherit without using prototypes
}
是吗?所以原型的主要目的有三个:
答案 0 :(得分:2)
节省内存
是的,当您创建数百个Car实例并且它们都有自己的函数(具有自己的闭包范围)时,您将消耗更多内存。
无法找到它的参考,但有人建议Chrome优化使用原型的构造函数,而不是构造函数体中的所有构造函数。
提供静态属性
静态更像Date.now()
,每个实例都有原型的成员,但可以在实例上调用。
是引用类型从超类继承的唯一方法
您可以在Child中继承Parent.apply(this,arguments);
,但它会使扩展的Parent函数更复杂,并且不会使childInstance instanceof Parent
成立。该代码所做的是运行父代码,将要创建的Child实例作为调用对象(this
)。继承通常在2个地方完成。
Parent.apply(this,arguments);
中重新使用父初始化代码,并使Parent实例成员成为子实例成员(例如:this.name)。Child.prototype=Object.create(Parent.prototype);Child.prototype.constructor=Child;
的浅层副本这将确保共享父成员在Child实例上可用(如函数getName)。答案 1 :(得分:1)
关于你的三点:
jQuery.extend
),但就引用类型而言,原型是创建继承的唯一方法。答案 2 :(得分:0)
原型设计远不止于此。 您还可以在运行时使用方法和属性扩展类和已存在的对象实例。
这应该以一种非常容易理解的方式解释它:http://javascript.info/tutorial/inheritance
答案 3 :(得分:0)
如果您关注以下约定,以便人们(以及您在路上)真正理解您的代码,那么您不应该将this.engine="v8"
放在构造函数中。 Prototype用于定义每辆汽车的属性,构造函数用于定义单个实例。那么为什么你会在构造函数中为每个实例添加一些真实的东西呢?这属于原型。即使做两件事最终完成相同的事情,也可以说要将东西放在适当的位置。您和其他人可以理解您的代码。
答案 4 :(得分:0)
关于你的观点:
some_instance.foo
来检索信息。 “静态”属性/方法是不同的(见下文)。让我解释一些事情,看看这是否有帮助。在javascript中创建新的“类”是一个相当简单的过程。
var MyClass = new Function();
此时,引擎会知道您的新课程,并在创建“课程”的新实例时知道“该怎么做”(就性能而言)。
var my_instance = new MyClass();
如果你想修改原型,你可以这样做并知道每个实例都会更新,因为它们都共享相同的原型。
MyClass.prototype.name = "default name";
console.log( my_instance.name ); //=> default name
现在引擎知道有一个“name”属性需要一个字符串值...它会将这些资源分配给你的类的所有新的和现有的实例...这是非常的便利。请注意,修改现有“类”的原型是一个昂贵的过程,不应经常执行(但也不要害怕这样做)。
我无法真正说明在实例上声明特殊属性/方法的性能优缺点:
my_instance.foo = function() { /* this is not in the prototype chain */ };
我的猜测是这对引擎来说非常简单,除非你同时为成千上万个对象做这件事,否则没什么大不了的。
使用原型IMO的主要好处是您可以编写代码来扩展方法的功能,并且知道“类”的所有实例都会相应地更新:
var old_foo = MyClass.prototype.foo;
MyClass.prototype.foo = function() {
/* new business logic here */
// now call the original method.
old_foo.apply(this, arguments);
};
关于“静态”属性,您可以在“类”(构造函数)本身上声明它们:
// example static property
MyClass.num_instances = 0;
现在你可以创建这样的init / destroy方法:
MyClass.prototype.init = function() {
this.constructor.num_instances++;
};
MyClass.prototype.destroy = function() {
this.constructor.num_instances--;
};
// and call the init method any time you create a new instance
my_instance.init();
console.log( MyClass.num_instances ); //=> 1
var instance_2 = new MyClass();
instance_2.init();
console.log( MyClass.num_instances ); //=> 2
instance_2.destroy();
console.log( MyClass.num_instances ); //=> 1
希望有所帮助。
答案 5 :(得分:0)
(1)我不认为单独保存内存是使用.prototype的正当理由,除非你在复制对象时变得非常极端。
(2)静态属性的概念并不是使用.prototype(IMHO)的真正原因,因为它的行为不像传统的静态属性。你(据我所知)你总是需要一个对象实例才能访问“静态”属性,这使它根本不是静态的。
function Car() {}
Car.prototype.Engine = "V8";
// I can't access Car.Engine... I'll always need an instance.
alert(new Car().Engine);
// or
var car1 = new Car();
alert(car1.Engine); //you always need an instance.
//unless you wanted to do
alert(Car.prototype.Engine); //this is more like a static property, but has an
//unintended consequence that every instance of Car also receives a .Engine
//behavior, so don't do this just to create a "static property."
应该注意的是,这种“静态”的想法不仅适用于属性,而且适用于所有成员,包括方法(函数),从传统的OO角度来看。
最好将原型(再次,恕我直言)视为注入单例对象,其行为附加到实例对象。 Car()的所有实例都可以拥有自己的实例成员,但Car()的每个实例也会“自动”注入所有Car.prototype的成员/行为。它在技术上并不相同,但我觉得以这种方式考虑原型很方便。
//define Car and Car.GoFast
function Car() {}
Car.prototype.GoFast = function () { alert('vroom!'); };
var car1 = new Car();
var car2 = new Car();
car1.GoFast();
car2.GoFast(); //both call to same GoFast implementation on Car.prototype
//change the GoFast implementation
Car.prototype.GoFast = function () { alert('vvvvvrrrrroooooooooommmmm!!!!!'); };
car1.GoFast();
car2.GoFast(); //both have been "updated" with the new implementation because
//both car1 and car2 are pointing to the same (singleton) Car.prototype object!
Car.prototype的行为类似于单个对象,其成员/行为已被注入Car类型的实例对象中。
(3)原型不应混淆继承。您可以获得似乎是继承的行为,但事实并非如此。原型上的成员/行为保留在原型对象上。它们不会成为派生类的成员/行为,就像真正的继承一样。这就是为什么我将其描述为更像是将“注入”实例的原型。
function Car() {}
Car.prototype.Engine = "V8";
var car1 = new Car();
var car2 = new Car();
alert(car1.Engine); //alerts "V8"
//There is no "Engine" variable defined within the instance scope of 'car1'.
//Javascript searches the scope of car1's Type.prototype object to find 'Engine'.
//Equivalent to: Object.getPrototypeOf(car1).Engine
//But if we create 'Engine' within the scope of car1
car1.Engine = "V6"; //Car.prototype was never accessed or updated
alert(car1.Engine); //we get "V6"
alert(car2.Engine); //we still get "V8"
alert(Object.getPrototypeOf(car1).Engine); //we still get "V8"!
所以直接回答这个问题:使用原型而不是在对象本身上声明属性有什么好处吗?
是,当您想要在给定Type的实例对象之间共享行为实现时。巧合的是,您将减少内存占用,但这并不是单独使用原型的原因。既不是“创建静态属性”(它们不是),也不是继承(它不是)。