簡體   English   中英

JavaScript原型和call()

[英]JavaScript prototype and call()

我正在學習js原型,並且想知道以下兩個部分之間是否有任何區別?

細分1:

function SuperType(){
    this.color=["blue","yellow"];
}


function SubType(){

}      
Subtype.prototype = new SuperType();

細分2

function SuperType(){
    this.color=["blue","yellow"];
}

function SubType(){
    SuperType.call(this);
}   

並且如果以上兩個功能做的相同,那么為什么有些代碼會麻煩這樣做:

function SubType(){

        SuperType.call(this); 
        }

SubType.prototype=new SuperType(); 

是的,有差異。

在段1中,子類SubType不會調用SuperType的構造函數,因此它永遠不會執行。 段1不是從另一個對象繼承的正確通用方法。

在段2中,子類SubType確實調用了SuperType的構造函數,因此語句this.color=["blue","yellow"]; 被執行,但是原型設置不當,因此不會繼承SuperType可能擁有的任何原型項。 段2不是從另一個對象繼承的正確通用方法。

如果SuperType構造函數中沒有代碼,則段1將正常工作(在您的示例中不是這種情況)。 如您所示,由於未調用SuperType()構造函數,因此this.color僅在原型中,因此所有實例將共享同一數組,這通常不是您想要的。 正確調用構造函數將為每個實例提供this.color的自己副本,而不是共享副本。

如果沒有向SuperType原型添加任何內容並且沒有SuperType構造函數參數,則第2部分將正常工作(在您的示例中可能是這種情況,但不是很好的常規做法)。

通用的工作方式也不是。


最后一個選擇是正確的通用處理方式,因為它既從原型繼承,又執行繼承對象的構造函數。


最通用的方法還使用.apply(this, arguments)這樣將任何構造函數參數傳遞給繼承的對象.apply(this, arguments)並初始化其自己的原型並設置其構造函數屬性。

// define base object constructor
function SuperType(){
    this.color=["blue","yellow"];
}

// define base object methods on the prototype
SuperType.prototype.foo = function() {};

// ---------------------------------------------------------------------------

// define object that wants to inherit from the SuperType object
function SubType() {
    // call base object constructor with all arguments that might have been passed
    SuperType.apply(this, arguments); 
}

// set prototype for this object to point to base object
// so we inherit any items set on the base object's prototype
SubType.prototype = new SuperType();
// reset constructor to point to this object not to SuperType
SubType.prototype.constructor = SubType;

// define any methods of this object by adding them to the prototype
SubType.prototype.myMethod = function() {};

如果您只支持IE9及更高版本,則應更改以下行:

SubType.prototype = new SuperType();

對此:

SubType.prototype = Object.create(SuperType.prototype);

這避免了為了獲得用於原型的對象而調用SuperType()構造函數。 在大多數情況下,這確實無關緊要,但是在構造函數具有僅初始化其自身屬性之外的副作用的情況下,這很重要。

在第1部分中,原型已正確設置,但從未調用SuperType的構造函數。

在第2段的開頭,將調用SuperType的構造函數,但未設置原型。

最后一個示例是正確的,因為它可以正確設置原型並調用SuperType的構造函數。

function SuperType() {
  // Do some stuff.
}

function SubType() {
  SuperType.apply(this, arguments);
}

SubType.prototype = new SuperType();

你不應該設置原型繼承

 SubType.prototype=new SuperType (); 

因為可能會有問題。

如果您這樣做,SubType的原型也將繼承屬性color作為SubType原型的自己的屬性,因為構造器已完成工作。 然后,每個subType的新實例都具有對原型中color屬性的引用,而不是實例本身的自身屬性,這最終不是您想要的,因為您只想繼承原型。 幸運的是,在調用超級構造函數之后,每個實例都獲得了自己的color屬性,但是color屬性仍然在原型中也定義了。 沒有必要

因此,要真正只繼承原型,您應該使用Object.create或執行類似的解決方法。

function SuperType()
  {
  if (SuperType.doNotConstruct) return;
  this.color=["blue","yellow"];
  }


function SubType()
  {
  SuperType.call (this);
  }      

SuperType.doNotConstruct=true;

SubType.prototype = new SuperType();

SuperType.doNotConstruct=false;

SubType.prototype.constructor=SubType;

第二種方法-更好的方法-因為不需要if構造函數中的Statement

function SuperType()
  {
  this.color=["blue","yellow"];
  }


function SubType()
  {
  SuperType.call (this);
  }      

var CLASS=function () {}
CLASS.prototype=SuperType.prototype;
SubType.prototype=new CLASS ();
SubType.prototype.constructor=SubType;

@blake嘗試以下操作-當人們忘記調用超級構造函數並使用... prototype = new構造函數進行繼承時,這將顯示一個問題

function SuperType()
  {
  this.color=["blue","yellow"];
  }

SuperType.prototype.addColor=function (name)
  {
  this.color.push ("red");
  }


function SubType () {}

SubType.prototype=new SuperType ();

var a=new SubType ();
var b=new SubType ();

a.addColor ("red");

console.log (a.color);
console.log (b.color);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM