2013-06-12 39 views
2

我現在正在學習JavaScript,看起來像美麗的函數式語言對我來說,這是來自PHP的美妙動作,我應該早些做過。雖然,我不明白這一個:調用時分配給變量或函數參數的對象方法失敗

var v1 = (/[abc]/).test; 
v1('a'); 

test method called on incompatible undefined,我試圖存儲正則表達式爲可變的測試方法和以後調用它。

,但它與我自己的功能:

function foo(){ 
    return 'I\'m foo'; 
} 

var f = foo; 
f(); // returns I'm foo 

應該對方法的工作也是如此,因爲函數只是父對象的方法呢,對吧?

最後,我想這樣做的原因是爲了能夠寫出這樣的事:

var a = ['a', 'b', 'c']; 
a.every((/[abc]/).test); 

檢查每個數組成員針對該正則表達式。

爲什麼不能正常工作?它傳遞內置函數的限制嗎?或者我只是做錯了什麼?

PS:如果你現在和消音一些關於不良做法磨牙齒,擰好做法,我只是玩。但我也想聽到他們的消息。

回答

3

它與我自己的功能

您不使用this函數內部。考慮下面這個例子:

var obj = { 
    foo: 42, 
    bar: function() { 
     alert(this.foo); 
    } 
}; 
var f = obj.bar; 
f(); // will alert `undefined`, not `42` 

應該對方法的工作也是如此,因爲函數只是父對象的方法呢,對吧?

「方法」只是分配給對象屬性的函數的通俗術語。功能是獨立的價值。沒有連接到函數分配給的對象。這怎麼可能,因爲一個函數可以分配給多個對象?

爲什麼不能正常工作?

指的是什麼this函數內部在運行時確定。所以,如果你分配的功能給一個變量,後來

var v1 = (/[abc]/).test; 
v1('a'); 

this把它裏面的功能將參考window,而不是正則表達式對象。

你可以做的是使用.bind[MDN]明確綁定this爲特定值:

var a = ['a', 'b', 'c']; 
var pattern = /[abc]/; 
a.every(pattern.test.bind(pattern)); 

不過請注意,由於.bind返回功能,在使用函數表達式的唯一的好處是,它是一點點寫得更短。


它是在傳遞周圍內置功能的限制?

不,每個方法/功能都存在問題,因爲這就是函數的工作方式。內置函數的好處在於,他們經常明確地告訴你什麼時候this指的是錯誤類型的對象(通過拋出錯誤)。


Learn more about this.

+0

非常棒的答案,非常感謝! – enrey

+0

不客氣! –

+1

請注意,在嚴格模式下,'this'應該是未定義的。 – RobG

3

如果你剛剛保存的方法,它不與它送到你對象的引用 - 它只是存儲參考.test方法,但沒有特定對象。請記住,一個方法是「只是」一個對象的屬性,並且存儲對方法的引用不會將其綁定到該對象,它只會存儲對該方法的引用。

要在特定對象上調用該方法,必須使用該對象調用該方法。

你可以讓自己的函數調用這樣期望的對象上的方法:

var v1 = function(x) { 
    return /[abc]/.test(x); 
} 

然後,當你這樣做:

v1('a'); 

它會在執行這個相當於你的函數:

/[abc]/.test('a'); 

但是,它並不完全清楚爲什麼你這樣做,你也可以只定義了正則表達式和調用。測試()就可以了幾次:

var myRegex = /[abc]/; 
console.log(myRegex.test('a')); 
console.log(myRegex.test('b')); 
console.log(myRegex.test('z')); 
+0

我知道匿名函數,但我希望這樣做沒有在其包裝函數,因爲jQuery本身就是功能包裝的瘋狂。 – enrey

+0

@ enrey-這個包裝來源於不修改你不擁有的對象的哲學,這意味着不要修改主機或內置對象。這被認爲是一件好事,因爲它意味着你的代碼可以很好地與其他人的代碼一起玩(只要他們採取了相同的方法)。 – RobG

+1

@enrey - 您必須創建另一個將您的方法調用與適當對象關聯的函數。你可以像這樣自己做,也可以使用'.bind()'並讓框架爲你做。僅供參考,'.bind()'與此完全相同(創建一個將對象和方法調用綁定在一起的函數包裝器),因此它基本相同。無論哪種情況,對於像這樣的方法來說,它都必須以'object.method()'的形式被調用。你不能只調用'method()',並期望它有正確的對象與它關聯。 – jfriend00

0

你的方法引用已經失去了它的知識它是一種方法。 這不像JS的工作方式那麼好。

你可以這樣做:

var v1 = /[abc]/; 
v1.test('a');  

如果必須封裝測試方法,那麼你可以做:

var v1 = function(str){ 
    return /[abc]/.test(str); 
}; 
v1('a'); 
0

我不知道這是一個可以接受的解決方案,但你可以這樣做:

v1 = function(exp) { return (/[abc]/).test(exp); } 
v1('a'); 
1

test函數期望this是正則表達式。表達式/[abc]/.test給出了一個未綁定的函數(它不記得它屬於/[abc]/)。當你像你一樣調用它時,this將爲undefined,該功能將失敗。

您可以使用bind使功能記住對象屬於:

var v1 = /[abc]/.test.bind(/[abc]/); 

var v1 = RegExp.prototype.test.bind(/[abc]/); 
相關問題