2016-04-09 74 views
3

我通過CodeAcademy JS excercises工作,有一個關於這個例子的問題:JavaScript構造函數,原型附加方法,和「這個」

//Animal class 
function Animal(name) { 
    this.name = name; 
} 

//Attach sayName method to Animal class 
Animal.prototype.sayName = function() { 
    console.log("Hi my name is " + this.name); 
}; 

//create an animal object instance 
var dog = new Animal('Barker'); 

//invoke a method attached to the prototype from the object instance 
dog.sayName(); 

我這個代碼的理解是:

  1. JS創建一個新的動物對象實例var dog指向作爲在調用函數之前使用new關鍵字的結果Animal() - 函數構造函數
  2. var dog對象的原型具有sayName()方法附連到它的行:Animal.prototype.sayName = function()
  3. 由於sayName()附着到類prototype,該方法現可從Animal類通過使用new Animal()功能構造的創建的任何對象

這是正確理解這段代碼發生了什麼?

另外,我也想了解如何this指向動物對象this.name

Animal.prototype.sayName = function() { 
    console.log("Hi my name is " + this.name); 
}; 

Animal.prototype指向一個實際的對象:此Animal對象實例的prototype對象?如果是這樣,this不應該this.name指向Animal.prototype,因爲sayName()實際上是從Animal.prototype被調用?

我對this的上下文的理解是,this總是指向調用該函數的對象。但是,在這種情況下,當dog.sayName()被調用時,this指向Animal,這是this.name等於'Barker'當它被記錄到控制檯時。 我在猜測,要麼我誤解Animal.prototype指向原型對象,要麼JS在「幕後」做一些事情,在將方法附加到prototype的上下文中將dog.sayName()this關聯起來。

在這個小例子中有多個問題,但掌握這裏發生的事情真的會幫助我理解這些基本概念。

+0

當一個構造函數被調用時,它會將其原型賦值給創建的對象的原型,這樣'dog'就可以完全訪問'Animal.prototype'的函數和屬性。你可以看一下http://qr.ae/RO44Vn以獲得關於JS的'this'的詳細信息。 – Redu

回答

2

[點1-3]

這就是與此代碼發生的事情有正確的認識?

是的,聽起來像你理解它。

不Animal.prototype指向一個實際的對象:此Animal對象實例的prototype對象?

是的,prototype對象是一個Object實例。

如果是的話,應該在不thisthis.nameAnimal.prototype,因爲sayName()實際上正在從Animal.prototype調用?

不,因爲您將它稱爲dog的方法。

dog.sayName(); 

如果你把它叫做這樣,那麼是的,this會引用Animal.protoype

Animal.protoype.sayName(); 

但這不會很有用。

我對this的上下文的理解是,this總是指向調用該函數的對象。

不完全。在大多數情況下,this指的是該方法被調用的對象,而不是它所屬的對象。一個方法實際上可以是多個對象的屬性,所以this動態指向它作爲方法調用的對象。

當然,this可以在其他上下文中引用其他內容,例如,當不作爲方法調用時,或在使用.bind的綁定函數中。

+0

所以sayName()是從狗/動物調用的,但實際上並不存在於狗身上。相反,它存在於它的原型對象上,並且當狗調用sayName()時,JS並沒有在那裏找到它,而是沿着原型鏈下來並在Animal.prototype上找到它。這是該方法實際存在的地方。現在,由於狗調用sayName(),'this'引用指向dog,所以新的Animal('Barker')設置this.name ='Barker'。 –

+0

@ lance.parish是的,這就是原型鏈的工作原理。 –

1

你誤會了this。當您創建函數時,未設置this的值,這是一個附加參數。每次調用某個函數時,this的值可能會更改。

在方法的情況下,this值設置爲基礎對象。例如,

dog.sayName(); // `this` is `dog` 
({sayName: dog.sayName}).sayName(); // `this` is this new object 
(0,dog.sayName)(); // `this` is undefined or the global object 
+0

最後一個例子'(foo,bar.baz)()'是一個重要的邊緣案例,它不是立即顯而易見的,很好! –

1

this有在Javascript中兩個不同的特性造成了很多困惑:

  1. 它是唯一的動態範圍的內置
  2. 它當作一個隱含參數
語言的特點

詞法分析器

var i = 0; 
const inc =() => i + 1; 

const inc2 = x => { 
    var i = x; 
    return inc(); 
}; 

inc2(100); // 1 

動態範圍

var o = { 
    i: 0, 
    inc: function() { return this.i + 1 } 
}; 

var p = { 
    i: 100, 
    inc2: o.inc 
}; 

p.inc2(); // 101 

this動態範圍的,因爲它是通過調用上下文設置。

隱含參數

不是傳遞this明確地作爲一個正式的參數的方法,它的隱含處理。因此就需要使用call/apply設定不同的值(即對象),用於this

// Note that s and t are implicitly converted to objects 

const split = (o, x) => o.split(x); 
let s = "1,2,3", t = "4,5,6"; 

// objects are passed explicitly as normal arguments 
split(s, ","); // ["1", "2", "3"] 
split(t, ","); // ["4", "5", "6"] 

// objects (or this) are provided implicitly 
s.split(","); // ["1", "2", "3"] 
s.split.call(t, ",") // ["4", "5", "6"] 

想象this作爲方法的接收對象,它必須作爲第一個參數傳遞。