2013-12-22 109 views
1
function Person(firstName, lastName) { 
    this.firstName = firstName; 
    this.lastName = lastName; 
} 
Person.prototype.talk = function() { 
    return this.firstName + " " + this.lastName; 
} 
//creating a Person object for extension 
var manager = new Person('jon', 'doe'); 
console.log(manager.talk()); 
//Manager prototype..but doesn't inherit Person methods 
function Manager(firstName, lastName, accessCode) { 
    //shared properties 
    this.firstName = firstName; 
    this.lastName = lastName; 

    this.accesscode = accessCode; 
} 
function personChecker(person) { 
    var returnCode = 0; 
    if (person instanceof Person) { 
     returnCode = 1; 
    } 
    else if (person instanceof Manager) { 
     returnCode = 2; 
    } 
    return returnCode; 
} 
console.log(personChecker(manager)); 

是否可以共享原型並具有不同的構造函數?我想有經理從Person繼承一切(然後擴展它),並且對原型的功能開關,並做視不同的東西傳遞給personChecker功能使用JavaScript的原型繼承鏈

+0

是的,這是可能的,但'instanceof'可能無法正常工作。你究竟想要做什麼?這個「功能開關」聽起來不太好。你確定你不想「子類」人嗎? – Bergi

+0

@Bergi我想要一些功能,我有一個方法,可以採取一個經理,看門人和總統對象,從Person繼承。我應該如何區分這些類型?我應該使用'hasOwnProperty'而不是切換原型嗎? – wootscootinboogie

+0

從Person繼承三次聽起來像是正確的事情 - 但他們沒有相同的原型(「分享」)。通過調用他們自己的方法來區分這些實例還是通過實例來檢查它們應該是另一個問題。 – Bergi

回答

2

在JavaScript中,繼承通常進行這樣的:

Manager.prototype = Object.create(Person.prototype); 

Object.create創建具有在其原型鏈的第一個參數傳遞的對象的新對象。

如果您需要支持沒有Object.create舊的瀏覽器,你可以做「原型的舞蹈」,而不是:

function F(){} 
F.prototype = Person.prototype; 
Manager.prototype = new F(); 

在任何情況下,避免代碼調用構造函數來獲得這樣一個對象(這是一個衆所周知的反模式,只要你的構造函數依賴於它的任何參數(並且導致其他更微妙的問題),它就會中斷。

+0

有趣的是,我認爲這是我真正想做的。這種反模式引起的一些更微妙的問題是什麼? – wootscootinboogie

+1

我認爲最常見的問題是,構造函數用'this'做的任何事情都會發生在你的新原型對象上,當時可能假設'this'只是一個實例對象。 –

+0

謝謝,這是我遇到的最好的解釋! – Sukima

1

使用以下參數:

function Person(firstName, lastName) { 
    this.firstName = firstName; 
    this.lastName = lastName; 
} 
Person.prototype.talk = function() { 
    return this.firstName + " " + this.lastName; 
} 

function Manager(firstName, lastName, accessCode) { 
    //shared properties 
    this.firstName = firstName; 
    this.lastName = lastName; 

    this.accesscode = accessCode; 
} 
Manager.prototype = new Person('jon', 'doe'); 

function personChecker(person) { 
    var returnCode = 0; 
    if (person instanceof Manager) { 
     returnCode = 2; 
    } 
    else if (person instanceof Person) { 
     returnCode = 1; 
    } 
    return returnCode; 
} 

請注意,我已經改變了條件句的順序,因爲Manager一個實例是Person實例太:

var per = new Person('A', 'B'); 
per.talk();    // 'A B' 
per instanceof Person; // true 
per instanceof Manager; // false 
personChecker(per);  // 1 

var man = new Manager('A', 'B'); 
man.talk();    // 'A B' 
man instanceof Person; // true !!!! 
man instanceof Manager; // true !!!! 
personChecker(man);  // 2 

如果你想這樣做的好辦法,而不是

Manager.prototype = new Person('jon', 'doe'); 

使用

Manager.prototype = Object.create(Person.prototype, {constructor: {value: Manager}}); 

,但它並沒有在舊瀏覽器。

+2

-1爲什麼你所有的經理都叫jon doe? [不要使用'new'繼承](http://stackoverflow.com/q/12592913/1048572)! – Bergi

+0

@Bergi我以爲wootscootinboogie想要「jon doe」作爲默認名稱 – Oriol

+0

謝謝,但沒有理由不使用「好方法」:-) – Bergi

2

典型的方式來支持這種繼承:

// create a blank function to pass the prototype 
var blank = function() {}; 

// assign the prototype to inherit to the blank constructor 
blank.prototype = Person.prototype; 

// pass an instance of the prototype as the Manager prototype 
Manager.prototype = new blank(); 

var person = new Person('John', 'Doe'); 
var manager = new Manager('Greg', 'Smith', 'access1234'); 

manager.talk(); // Greg Smith 
person.talk(); // John Doe 

這裏是一個小提琴:http://jsfiddle.net/XF28r/

注意一個經理也是人,所以你需要切換左右的檢查。

function personChecker(person) { 
    var returnCode = 0; 
    if (person instanceof Manager) { 
     returnCode = 2; 
    } else if (person instanceof Person) { 
     returnCode = 1; 
    } 
    return returnCode; 
} 

雖然注意到我會把這一個輔助方法:

function extend(parent, child) { 

    var blank = function() {}; 
    blank.prototype = parent.prototype; 
    child.prototype = new blank(); 
} 

,那麼你可以簡單地使用它:

extend(Person, Manager); 

由於BERGI在評論中已經提到的,這可也可減至:

function extend(parent, child) { 
    child.prototype = Object.create(parent.prototype); 
} 

(工作IE 9向上)

+0

Downvoter,謹慎解釋? –

+0

我認爲這是一個很好的潛在解決方案。 – wootscootinboogie

+0

而不是輔助函數,你應該使用Object.create或者它的一個墊片(@DaggNabbit:這裏沒關係,因爲他明確使用了'blank',儘管一些解釋會有所幫助) – Bergi