JavaScript 构造函数、原型附加方法和 'this'

JavaScript constructor function, prototype attach method, and 'this'

我正在学习 CodeAcademy JS 练习,对这个例子有疑问:

//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 在调用函数之前使用 new 关键字创建了一个新的 Animal 对象实例,var dog 指向该实例 Animal() - 函数构造函数
  2. var dog 对象的原型在以下行中附加了 sayName() 方法:Animal.prototype.sayName = function()
  3. 因为 sayName() 附加到 class prototype,该方法现在可用于通过使用 Animal class 创建的任何对象new Animal() 函数构造函数

这是对这段代码所发生的事情的正确理解吗?

此外,我正在尝试了解 this 如何指向 this.name 中的 Animal 对象:

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

Animal.prototype 不是指向实际对象:此 Animal 对象实例的 prototype 对象吗?如果是这样,this.name 中的 this 不应该指向 Animal.prototype,因为 sayName() 实际上是从 Animal.prototype 调用的吗?

我对 this 上下文的理解是 this 总是指向调用该函数的对象。但是,在这种情况下,当 dog.sayName() 被调用时,this 指向 Animal,这就是 this.name 等于 'Barker' 时记录到控制台的方式。 我猜想要么我误解了 Animal.prototype 指向原型对象,要么 JS 正在做一些事情 "behind the scenes" 在附加的上下文中将 dog.sayName() 关联到 this prototype 的一种方法。

这个小例子中有多个问题,但准确掌握这里发生的事情将真正帮助我理解这些基本概念。

你误会了thisthis 的值在您创建函数时未设置,它是一个附加参数。每次调用函数时,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

[points 1-3]

Is this a correct understanding of what is happening with this code?

是的,听起来你明白了。

Doesn't Animal.prototype point to an actual object: the prototype object of this Animal object instance?

是的,prototype 对象是一个 Object 实例。

If so, shouldn't this in this.name point to Animal.prototype, since sayName() is actually being invoked from Animal.prototype?

不,因为你调用它作为 dog 的方法。

dog.sayName();

如果你这样称呼它,那么是的,this 会引用 Animal.protoype

Animal.protoype.sayName();

但这不是很有用。

My understanding of the context for this is that this always points to the object that invokes the function.

不完全是。大多数情况下 this 指的是调用方法的对象,而不是它是 属性 的对象。一个方法实际上可以是多个对象的 属性,因此 this 动态指向它作为方法调用的对象。

当然,this 可以在其他上下文中引用其他内容,例如未作为方法调用时,或在使用 .bind.

的绑定函数中

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/applythis:

设置不同的值(即对象)
// 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作为一个方法的接收对象,必须作为第一个参数传递。