2012-01-29 64 views
7

參考:http://ejohn.org/blog/simple-class-instantiation/約翰Resig的簡單的類實例化和「使用嚴格」

// 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在嚴格模式下不推薦使用。

回答

4

據我瞭解,arguments.callee不是已棄用在嚴格模式,在這種情況下,你可以繼續使用它;相反,它已被刪除並嘗試使用將(或應該)拋出異常。

解決方法是使用命名匿名函數,如果你會原諒矛盾修飾詞。真的,我應該說"named function expressions"。舉個例子:

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將被替換爲我的例子。

1

John Resig的原始代碼失敗,出現無參數構造函數。

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); 
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