2016-04-09 73 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作为方法的接收对象,它必须作为第一个参数传递。