5

我最近一直在深入研究 JavaScript 以完全理解该语言,并且有一些我似乎无法找到答案的唠叨问题(特别是处理面向对象的编程)。

假设以下代码:

function TestObject()
{
    this.fA = function()
    {
        // do stuff
    }

    this.fB = testB;

    function testB()
    {
        // do stuff
    }
}

TestObject.prototype = {
    fC : function 
    {
        // do stuff
    }
}

函数fA和 和有什么不一样fB?他们的行为范围和潜在能力是否完全相同?它只是惯例还是技术上更好或更合适的一种方式?

如果在任何给定时间只有一个对象的实例,那么在原型中添加一个函数fC是否值得?这样做有什么好处吗?只有在处理对象或继承的许多实例时,原型才真正有用吗?

从技术上讲,以我上面的方式或TestObject.prototype.functionName = function(){}每次调用的方式向原型添加方法的“正确”方式是什么?

我希望保持我的 JavaScript 代码尽可能干净和可读,但我也对语言中对象的正确约定非常感兴趣。我来自 Java 和 PHP 背景,我试图不对 JavaScript 的工作方式做出任何假设,因为我知道它与基于原型的非常不同。

4

4 回答 4

6

函数 fA 和 fB 有什么区别

在实践中,什么都没有。函数表达式 (fA) 和函数声明 (fB) 之间的主要区别在于创建函数的时间(声明的函数在执行任何代码之前可用,而函数表达式在表达式实际执行之前不可用)。您可能会偶然发现与函数表达式相关的各种怪癖。

在示例中,我将使用函数表达式,仅仅是因为声明一个函数表达式,然后分配结果似乎有点抽象。但是,这两种方法都没有“正确”或“错误”之分。

如果在任何给定时间只有一个对象的实例,那么在原型中添加一个函数(例如 fC)是否值得?

不。几乎每个继承继承的人都发现普通对象通常更简单,因此“更好”。不过,原型继承对于修补内置对象非常方便(例如,在不存在的地方添加 Array.prototype.each)。

从技术上讲,向原型添加方法的“正确”方式是什么……</p>

没有一个。用其他对象替换默认原型似乎有点浪费,但是分配由文字创建的对象可能更整洁,更容易阅读顺序分配。对于一两个任务,我会使用:

 Constructor.prototype.method = function(){…}

但是对于很多方法,我会使用对象文字。有些人甚至使用经典的扩展​​功能并执行以下操作:

myLib.extend(Constructor.prototype, {
    method: function(){…}
});

如果已经定义了一些方法,这对于添加方法很有用。

看看一些库并决定你喜欢什么,一些混合搭配。做任何适合特定情况的事情,通常只是获得足够多的代码以使所有代码看起来都一样,那么无论您选择什么模式,它都会看起来很整洁。

于 2012-09-07T05:36:25.757 回答
3

fA并且fB实际上是相同的,这只是惯例问题。

如果只有一个对象的实例,我什至不会使用构造函数,而只是使用对象文字,例如:

var o = {
   fA: function () { ... },
   fB: function () { ... },
   fC: function () { ... }
};

至于将其添加到实例或原型中,如果您只有一个实例,则实例比将其添加到原型中效率稍高,但正如我所说,请改用文字。

我避免在构造函数中声明函数,因为构造函数的每次调用都会创建代表每个函数的新对象。这些对象不是很大,如果创建了许多对象,它们往往会加起来。如果函数可以移动到原型中,这样做会更有效率。

至于添加到原型中,我赞成

TestObject.prototype.functionName = function () { };

风格,但这是一个偏好问题。我喜欢上面的内容,因为无论您是扩展原型还是创建初始原型,它看起来都一样。

于 2012-09-07T05:29:04.790 回答
0

我回答第一部分:没有区别,当你声明函数不是变量时,它的声明在块中上升,所以

...
func();
...    
function func () { ... }

等于

var func = function () { ... };
...
func();
...

所以你的代码

function TestObject () {
  this.fA = function() { // do stuff };   
  this.fB = testB;    
  function testB() { // do stuff }
}

等于

function TestObject () {
    var testB = function () { // do stuff };    
    this.fA = function () { // do stuff };
    this.fB = testB;
}
于 2012-09-07T05:26:32.143 回答
0

还有关于 JavaScript 如何在低级别运行的任何明确的 JavaScript 样式指南或文档吗?

该死的任何 javascript 程序员都不应该错过“面向 Web 开发人员的专业 JavaScript”。这是一本神奇的书,深入人心。它解释了对象、类仿真、函数、作用域等等。它也是一个 JS 参考。

从技术上讲,以我上面的方式向原型添加方法或每次调用 TestObject.prototype.functionName = function(){} 的“正确”方式是什么?

至于定义类的方式,我建议看看各种 JS MVC 框架(比如 Spine.js,它是轻量级的)。您不需要全部,只需要它们的类仿真库。主要原因是JS没有类的概念,而是纯粹由对象和原型组成。另一方面,可以完美地模拟类(请不要使用模拟这个词,因为它缺少一些东西)。由于这需要程序员的一些纪律,最好有一个类仿真库来完成这项工作并使您的代码更清晰。

程序员应该期望的类仿真库的标准方法是:

// define a new Class
var AClass = Class.create({
   // Object members (aka prototype), 
   // usually an initialize() method is called if it is defined 
   // as the "constructor" function when a class object is created
}, {
   // Static members
}); 

// create a child class that inherits methods and attributes from parent
var ChildClass = AClass.extend({
   // Child object members
},{
   // Child static members
}); 

AClass.include({
   // Object amendments (aka mixin), methods and attributes 
   //   to be injected to the class object
},{
  // Statics amendments, methods and attributes to be 
  //  injected as class static members
});


// check object type
var aObj = new AClass();
aObj instanceof AClass; //  true
aObj instanceof ChildClass; //  false


var cObj = new ChildClass();
cObj instanceof AClass; //  true
cObj instanceof ChildClass; //  true
于 2012-09-07T09:02:37.737 回答