2016-11-17 59 views
2

雖然與functionprototype相比,我們對es2016中的class功能有點困惑,但它的行爲在某些情況下是不同的,特別是 - 類不能被稱爲相同的功能,似乎沒有辦法找出函數是類構造函數還是簡單的函數,而不使用toString/^class/RegExp如何識別該函數是類構造函數,以及如何將其作爲函數調用?

假設的例子:

class Foo { 
    constructor() { 
     this.name = 'foo'; 
    } 
} 
function Bar() { 
    this.name = 'bar'; 
} 

function doSmth (anyArg) { 
    if (typeof anyArg === 'function') { 
     var obj = { someProp: 'qux' }; 
     anyArg.call(obj); 
     return obj; 
    } 
    // ... 
} 


doSmth(Bar); 
doSmth(Foo); // Class constructor Foo cannot be invoked without 'new' 

typeof 'function',但不能把它作爲一個功能!尼斯。

這裏是我的2個問題:

  1. 有一些方法我可以調用Foo構造函數一樣Bar與重寫this背景?
  2. 有什麼方法可以檢測到anyArg是一個類的構造函數,因此我可以在我的doSmth函數中以不同方式處理它。沒有toStringRegExp作爲性能損失將是巨大的在這種情況下)。然後,我可以使用Reflect.construct來初始化新實例,並使用Object.assign來擴展我的obj變量與來自實例的值。

謝謝,亞歷克斯

+2

FWIW,這聽起來很瘋狂,而我的)不知道到底是一個什麼樣接收和b)想強迫對象的構造類似。 – deceze

+0

[如何區分箭頭函數,類和普通函數?](http://stackoverflow.com/a/31947622/1048572) – Bergi

回答

0

否這兩個問題。

這裏的1.x中如何角檢測類:

function isClass(func) { 
    // IE 9-11 do not support classes and IE9 leaks with the code below. 
    if (msie <= 11 || typeof func !== 'function') { 
    return false; 
    } 
    var result = func.$$ngIsClass; 
    if (!isBoolean(result)) { 
    // Support: Edge 12-13 only 
    // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/ 
    result = func.$$ngIsClass = /^(?:class\b|constructor\()/.test(stringifyFn(func)); 
    } 
    return result; 
} 

不幸的是,這是最好的解決方案。而且它甚至在Firefox上不起作用。

+0

感謝您提供角度樣本。 Yeap似乎確實是唯一一種檢測類的方法。如果沒有更好的解決方案,有人提供將接受這個答案。 – tenbits

0

我不知道的方式做你在你的第一個問題問什麼。

對於第二個問題,您實際上確定了一種方法來自己區分差異。類構造函數和用作構造函數的函數之間的區別之一是前者在使用關鍵字時出現錯誤,而不使用關鍵字new,而後者則不會。

因此,如果我們用一個try/catch,我們可以粗略地做你想要什麼:

class Foo { 
    constructor() { 
     this.name = 'foo'; 
    } 
} 
function Bar() { 
    this.name = 'bar'; 
} 

function doSmth (anyArg) { 
    if (typeof anyArg === 'function') { 
     var obj = { someProp: 'qux' }; 
     try { 
      anyArg.call(obj); 
     } catch(e) { 
      var x = Reflect.construct(anyArg, []); 
      Object.assign(obj, x); 
     } 
     return obj; 
    } 
} 


doSmth(Bar); 
doSmth(Foo); 

要清楚,我並不是說這是一個好主意,好的代碼,或者說,它有你要找的表現,但我想我會指出這種可能性確實存在。

+0

'try..catch'可能是一個解決方案,但這裏我們不能確定這個異常是由作爲函數調用一個類引起的,而不是由函數內部的某些代碼引起的。從你的例子中,我們應該以某種方式解析異常的消息,但是消息是否跨瀏覽器統一? – tenbits

+0

絕對如此。你要麼必須這樣做,要麼使用更多本地try/catch函數調用函數中的所有代碼,這有其自身的問題。就像我說的,我並沒有聲稱這種方法是完美的(我懷疑你會找到一個完美的解決方案,說實話),只是想提高完整性的可能性,以防萬一它幫助其他人訪問未來的頁面。 – Hecksa

0

如果您擔心RegEx的性能損失,請使用substring()。如果你仍然關心字符串操作的性能,那麼考慮另一種實際區分函數類型的語言。在JavaScript中,他們都是function

class Foo { 
 
    constructor() { 
 
    this.name = 'foo'; 
 
    } 
 
} 
 

 
function Bar() { 
 
    this.name = 'bar'; 
 
} 
 

 
function doSmth(anyArg) { 
 
    if (typeof anyArg === 'function') { 
 
    var obj = { 
 
     someProp: 'qux' 
 
    }; 
 
    if (anyArg.toString().substring(0, 5) === 'class') { 
 
     Object.assign(obj, new anyArg()); 
 
    } else { 
 
     anyArg.call(obj); 
 
    } 
 
    return obj; 
 
    } 
 
    // ... 
 
} 
 

 
var bar = doSmth(Bar); 
 
var foo = doSmth(Foo); 
 

 
console.log(bar); 
 
console.log(foo);

+1

'anyArg.constructor === Function' so'anyArg.constructor()'總是返回一個無操作函數。 – thorn

+0

好點。我更新了它。 –

相關問題