2015-04-12 64 views
1

我的理解是,Object.hasOwnProperty方法檢查對象是否具有它自己的屬性名稱,即非繼承屬性。這意味着,只要屬性a就應該返回false。 b。不存在b。如果它被繼承,則爲JavaScript:爲什麼Object.hasOwnProperty方法的行爲如此?

如果我錯了,請糾正我,但除非這不使用經典繼承,否則bar在下面的代碼中繼承自Foo?爲什麼當propname屬性是繼承的屬性時hasOwnProperty方法返回true?我在這裏弄錯了什麼?

另外,如何使用Foo對象上的hasOwnProperty?在檢查Foo對象時,此處的代碼返回false

function Foo() { 
    this.propname = 'test'; 
} 

var bar = new Foo(); 

console.log(bar.hasOwnProperty('propname')); // returns true 
console.log(Foo.hasOwnProperty('propname')); // returns false 
+0

的這條線2 ===欄上,沒有原型屬性這裏設置。通過設置Foo.prototype.propname = ...添加原型。# – Douglas

+1

Bar是Foo的一個實例,而不是後代。 – joews

+0

@Douglas請你詳細說明一下嗎?爲什麼這需要原型呢?該方法正在檢查屬性... – shmuli

回答

3

最初的代碼示例等價於:

function Foo() { 
} 

var bar = new Foo(); 
bar.propname = 'test'; 

console.log(bar.hasOwnProperty('propname')); // returns true 
console.log(Foo.hasOwnProperty('propname')); // returns false 

這就是爲什麼bar.hasOwnProperty('propname')真(物業已經欄對象上明確設置),並Foo.hasOwnProperty('propname')返回false(該屬性尚未設置Foo,Foo對象本身和原型都沒有)。

hasOwnProperty檢查,通常使用這樣的:

function Foo() { 
    this.propname = 'test'; 
} 
Foo.prototype.inheritedprop = 'test'; 

var bar = new Foo(); 

console.log(bar.hasOwnProperty('propname')); // returns true 
console.log(bar.hasOwnProperty('inheritedprop')); // returns false 
+0

爲什麼沒有在'Foo'上設置屬性? – shmuli

+0

讓我再說一遍:爲什麼當'this'關鍵字或'prototype'被使用時,爲什麼不是實際設置在'Foo'上的屬性?在'Foo'上下文中,不應該使用'this'關鍵字來設置屬性?爲什麼這不起作用:'function Foo(){Foo.propname ='test';}'。我想這完全是同一個問題。爲什麼只有當我在函數的外面寫'Foo.propname ='test';'時才起作用? – shmuli

+0

示例中有三個不同的對象:bar,Foo和Foo.prototype。 hasOwnProperty方法檢查屬性的特定對象,因此如果僅在三個對象中的一個上設置了propname,那麼只有該對象纔會爲'obj.hasOwnProperty(「propname」)'返回true。 '函數Foo(){Foo.propname ='test';}'將在Foo上設置propname,但只有當Foo被調用時它纔會被設置。 – Douglas

2

沒有,propname實際上是設置在實例Foonew創建,基於Foo.prototype(即this)。構造模式的另一個近似清楚(ER)是怎麼回事:

var FooPrototype = {}; 
var bar = Object.create(FooPrototype); 
bar.propname = "test"; 
5

的障礙在這裏的一點是,JavaScript使用原型繼承。你所看到的並不是真正的繼承。如果物業

hasOwnProperty將返回false

  1. 不存在。
  2. 存在但只在原型鏈上。

代碼中的'class'與繼承無關,它只是一個設置對象某些屬性的函數。

該對象恰好是一個新的空對象的實例,因爲您用new關鍵字調用函數,這可能是混淆來自何處。

想象重寫功能,因爲這:

function foo() { 
    var bar = {}; 
    bar.propname = 'test'; 
    return bar; 
} 

var baz = foo(); 

你會想到baz.hasOwnProperty('propname')返回true?當然,因爲我們明確定義了對象上的屬性。

聲明財產的另一種方法是宣佈它在Foo的原型上。

function Foo() { 
    this.bar = 'baz'; 
} 

Foo.prototype.propname = 'test'; 

var baz = new Foo(); 

baz.propname; // 'test' 
baz.hasOwnProperty('propname'); // false 

再次,這裏發生的神奇的東西都是關鍵字new。當您使用new調用函數時,該函數將this的值賦值爲一個新對象,並將該對象的原型設置爲與您要調用的函數的原型相同。

也許解釋了這個問題最簡單的辦法是,有上bar一個hasOwnProperty方法,但是如果你調用bar.hasOwnProperty('hasOwnProperty')它將返回false

這是因爲hasOwnProperty方法居住在原型鏈的最頂端Object.prototype。 Javascript中的每個對象都從這裏繼承,這就是爲什麼每個對象都有一個hasOwnProperty方法。

有一個good article爲什麼new在Javascript中使面向對象編程變得困難。

+0

這也許就是爲什麼Addy Osmani在「學習JavaScript設計模式」(http://addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript)中建議不要使用基本構造函數模式,而是使用原型模式?他說構造函數模式「使繼承困難」,但沒有進一步闡述。確切地說, – shmuli

+0

。與Doug Crock沒有使用新的理由一樣(儘管他不再使用Object.create)花費一些時間用另一種語言進行原型繼承(我可以推薦Lua和Io),這對於理解原型很有幫助。在感覺古典的語法下,它們會略微丟失。 –

1

當你第一次寫Foo時,你只是定義了一個稍後使用的函數。

「酒吧」實例化該功能,實質上激活裏面的一切。

看看這個搗鼓這些console.logs

console.log(Foo) 
console.log(bar) 

https://jsfiddle.net/7pzwcrjo/

1

你首先必須初始化Foo類的新對象。

這個JS斌進一步說明這一點:http://jsbin.com/zaredowive/2/edit?js,console,output

正如你可以看到當你實例化類Foo的一個新的對象,在這種情況下,是一個叫巴變量構造函數只調用。您正在調用函數Foo的hasOwnProperty。該功能不包含任何屬性。

相關問題