使用原型的优点,vs直接在构造函数中定义方法?
我想知道是否有任何其他的优势,我应该走哪条路?
构造方法:
var Class = function () { this.calc = function (a, b) { return a + b; }; };
原型方法:
var Class = function () {}; Class.prototype.calc = function (a, b) { return a + b; };
我不喜欢这样,使用原型,方法定义是从类中分离出来的,我不知道是否有任何特定的原因,我应该只用第一种方法。
另外,是否有利用函数文字来定义一个“类”,而不仅仅是函数定义:
var Class = function () {};
VS
function Class () {};
谢谢!
通过原型链继承的方法可以针对所有实例进行通用更改,例如:
function Class () {} Class.prototype.calc = function (a, b) { return a + b; } // Create 2 instances: var ins1 = new Class(), ins2 = new Class(); // Test the calc method: console.log(ins1.calc(1,1), ins2.calc(1,1)); // -> 2, 2 // Change the prototype method Class.prototype.calc = function () { var args = Array.prototype.slice.apply(arguments), res = 0, c; while (c = args.shift()) res += c; return res; } // Test the calc method: console.log(ins1.calc(1,1,1), ins2.calc(1,1,1)); // -> 3, 3
注意如何改变应用于两个实例的方法? 这是因为ins1
和ins2
共享相同的calc()
函数。 为了使用在构建过程中创建的公共方法来做到这一点,您必须将新方法分配给已经创建的每个实例,这是一个尴尬的任务。 这是因为ins1
和ins2
会自己创建calc()
函数。
在构造函数中创建方法的另一个副作用是性能较差。 每次构造函数运行时,都必须创建每个方法。 原型链上的方法被创建一次,然后被每个实例“继承”。 在硬币的另一面,公共方法可以访问“私有”变量,这对于继承的方法来说是不可能的。
至于你的function Class() {}
vs var Class = function () {}
问题,前者在执行前被“悬挂”到当前范围的顶部。 对于后者,变量声明被提起,而不是赋值。 例如:
// Error, fn is called before the function is assigned! fn(); var fn = function () { alert("test!"); } // Works as expected: the fn2 declaration is hoisted above the call fn2(); function fn2() { alert("test!"); }
原型方法的优点是效率。 在所有的Class
对象之间共享一个calc()
函数对象(我的意思是通过调用Class
构造函数创建的对象)。 另一种方法(在构造函数中分配方法)为每个Class
对象创建一个新的函数对象,在调用Class
构造函数时使用更多的内存并花费更多的处理时间。 但是,这种方法确实有一个好处: calc()
方法可以访问构造函数中的局部变量,这可以使用你的优势:
function Class() { var calcCallCount = 0; this.calc = function (a, b) { ++calcCallCount; alert("Calc called " + calcCallCount + " times"); return a + b; }; };
关于var Class = function() {...}
与function Class() {...}
,我通常更喜欢后者是因为它意味着该函数有一个名称,这在调试时可能是有用的。 另一个区别是后一个版本(一个函数声明 )被挂起,这意味着它在所定义的范围内的任何地方都是可用的,而不是在定义之后。 但是, 有些人更喜欢到处使用前者(一个函数表达式 )。
var YourClass = function(){ var privateField = "somevalue"; this.publicField = "somevalue"; this.instanceMethod1 = function(){ //you may access both private and public field from here: //in order to access public field, you must use "this": alert(privateField + "; " + this.publicField); }; } YourClass.prototype.instanceMethod2 = function(){ //you may access only public field 2 from this method, but not private fields: alert(this.publicField); //error: drawaback of prototype methods: alert(privateField); };
原型方法的优点:
-
当您通过原型定义方法时,它们将在所有YourClass实例中共享。 因此,这样的实例的总大小<如果你在构造函数中定义方法; 有些测试显示了如何通过原型定义方法来减少html页面的总体大小,从而加快了加载速度。
-
通过原型定义的方法的另一个优点是当您使用继承的类时,您可以重写这些方法,并且在派生类的overriden方法中,您可以调用具有相同名称的基类方法,但是使用在构造函数中定义的方法,你不可以做这个。
首先你应该使用像这样的对象字面值:
var Class = { calc: function (a, b) { return a + b; } };
这个符号更清晰,也很明显,在Javascript对象中,只有哈希不是从配方支持的东西,比如预定义的类。
定义之间的区别在于,如果将方法添加到原型中,则将只有一个方法在内存中为所有实例创建。 所以,如果你有一个通用的方法和在多个实例中创建/使用的对象,你应该添加方法到原型。