伪古典与“JavaScript方式”

时间:2009-04-26 16:26:10

标签: javascript

刚读完Crockford的“ JavaScript: The Good Parts ”,我对他在伪古典与原型方法上的立场有疑问。其实我对他的立场并不感兴趣;我只是想了解他的论点,所以我可以建立自己的立场。

在书中,Crockford似乎推断构造函数和“所有爵士乐”不应该在JavaScript中使用,他提到了'new'关键字是如何被严格实现的 - 即非构造函数可以用'new'关键字,反之亦然(可能导致问题)。

我以为我知道他来自哪里,但我想我不知道。

当我需要创建一个新模块时,我通常会这样开始:

function MyModule(something) {
    this.something = something || {};
}

然后我会在原型中添加一些方法:

MyModule.prototype = {
    setSomething : function(){},
    getSomething : function(){},
    doSomething : function(){}
}

我喜欢这个模特;这意味着我可以在需要时创建一个新实例,它有自己的属性和方法:

var foo = new MyModule({option1: 'bar'});
// Foo is an object; I can do anything to it; all methods of the "class"
// are available to this instance.

我的问题:如何使用更适合JavaScript的方法实现上述目标?换句话说,如果“JavaScript”是一个人,她会建议什么?

另外:当Crockford说某个特定的设计模式“比另一个更具表现力”时,他的意思是什么?

4 个答案:

答案 0 :(得分:10)

请参阅:Is JavaScript's “new” Keyword Considered Harmful?

重要的是要记住,像许多其他JavaScript程序员一样,Crockford首先接触该语言,着眼于“修复”它 - 使其更像其他(所谓的“经典”)OO语言。所以编写了大量的结构代码,构建了库和框架......然后他们开始意识到它并不是真正必要的;如果你按照自己的条件接近JS,你就可以相处得很好。

答案 1 :(得分:4)

您所拥有的示例的原型变体在我的理解中看起来如下:

Object.beget = function (o) { /* Crockfords replacement for the new */ }

var myModule = {
    something : null,
    getSomething : function () {},
    setSomething : function () {},
    doSomething : function () {}
};

然后你可以这样做:

var foo = Object.beget(myModule);
foo.something = bar;

UPDATE:您还可以使用构建器模式替换如下构造函数:

var myModuleBuilder = {
    buildMyModule : function (something) {
        var m = Object.beget(myModule);
        m.something = something || {};
        return m;
    }
}

所以你可以这样做:

var foo = myModuleBuilder.buildMyModule(something);

答案 2 :(得分:2)

你的实现是有问题的,因为你正在替换整个原型对象,丢失了继承的函数原型的属性,并且它也会破坏,或者至少使它变得更加困难,如果你以后使用继承的能力以同样的方式写了其他类。

更适合Javascript的方法是:

var MyClass = function (storeThis) {
 this.storage = storeThis
}

MyClass.prototype.getStorage = function (){
   return this.storage;
}

MyClass.prototype.setStorage = function (newStorage){
  this.storage = newStorage;
}

使用它:

var myInstance = new MyClass("sup");
alert("myInstance storage: " + myInstance.getStorage());
myInstance.setStroage("something else");

关于'new'关键字和Crawford的问题,我无法回答,因为我还没有读过这本书,但我可以通过调用任何函数来看看如何创建一个新对象关键字,包括应该是类的方法的函数。

当有人说某些东西(例如设计模式)更具“表现力”时,他或她通常意味着设计模式清晰易懂,了解其实现的目标和方式。

答案 3 :(得分:0)

Javascript不是一个人,因此她无法真正建议你做什么。

上面的答案都没有提到普通的功能继承方式,我倾向于发现它是最简单的。

function myModuleMaker(someProperty){
  var module = {}; //define your new instance manually

  module.property = someProperty; //set your properties

  module.methodOne = function(someExternalArgument){
    //do stuff to module.property, which you can, since you have closure scope access
  return module;
  }
}

现在创建一个新实例:

var newModule = myModuleMaker(someProperty);

您仍然可以通过这种方式获得伪经典的所有好处,但是您遇到的一个缺点是,每次实例化时,您都会制作所有实例方法的新副本。当你开始有数百个(或者实际上是数千个)实例时,这可能只会很重要,这是大多数人很少遇到的问题。如果您正在创建真正庞大的数据结构或使用许多很多实例进行硬核动画,那么您最好使用伪经典。

我认为很难说任何一种方法都是"糟糕的做法"本身。