约翰·雷西格的简单类实例化和"use strict"

7

参考:http://ejohn.org/blog/simple-class-instantiation/

本文介绍了一种简单的JavaScript类实例化方法。这种方法使用了一个init函数来代替构造函数,并且使用了原型链来继承属性和方法。此外,该方法还可以方便地创建子类。
// makeClass - By John Resig (MIT Licensed)
function makeClass(){
  return function(args){
    if ( this instanceof arguments.callee ) {
      if ( typeof this.init == "function" )
        this.init.apply( this, args.callee ? args : arguments );
    } else
      return new arguments.callee( arguments );
  };
}

我在想,是否有任何符合ECMAScript 5标准的方法来实现相同的功能。问题是,在严格模式下访问arguments.callee已被弃用。

3个回答

4
据我所知,在严格模式下,arguments.callee并非被弃用,而是被移除,尝试使用它会(或应该)抛出异常。
解决方法是使用命名的匿名函数,如果你能原谅这个矛盾的词组。实际上,我应该说"命名函数表达式"。以下是一个示例:
function someFunc(){
  return function funcExpressionName(args){
    if (this instanceof funcExpressionName) {
      // do something
    } else
      return new funcExpressionName( arguments );
  };
}

你提供的名称,在我的例子中是funcExpressionName,不应该在函数之外的任何地方被访问,但不幸的是IE有其他想法(如果你Google it,就能看到)。
对于你问题中的例子,我不确定如何处理args.callee,因为我不知道它是如何由调用函数设置的,但使用arguments.callee将按照我的例子进行替换。

2

nnnnnn提出的上述想法相当不错。为了避免IE问题,我建议采用以下解决方案。

function makeClassStrict() {
    var isInternal, instance;

    var constructor = function(args) {
        // Find out whether constructor was called with 'new' operator.
        if (this instanceof constructor) {
            // When an 'init' method exists, apply it to the context object.
            if (typeof this.init == "function") {
                // Ask private flag whether we did the calling ourselves.
                this.init.apply( this, isInternal ? args : arguments ); 
            }
        } else {
            // We have an ordinary function call.

            // Set private flag to signal internal instance creation.
            isInternal = true;                                           
            instance = new constructor(arguments);
            isInternal = false;                                         
            return instance;
        }
    };

    return constructor;
}

请注意我们在// do something部分避免引用args.callee,而是使用一个内部标志。

1
约翰·雷西格的原始代码在没有参数的构造函数下失败。
var Timestamp = makeClass();
Timestamp.prototype.init = function() {
    this.value = new Date();
};

// ok
var timestamp = Timestamp();
alert( timestamp.value );  

// TypeError: args is undefined
var timestamp = new Timestamp();
alert( timestamp.value );   

但可以使用以下行进行修复。
this.init.apply( this, args && args.callee ? args : arguments );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接