简体   繁体   English

Javascript原型和通话之间的区别

[英]Javascript Difference between prototype and call

I am learning javascript and got puzzled. 我正在学习javascript并感到困惑。 An example over here which has example as below:- 这里有一个例子如下: -

// define the Person Class
function Person() {}

Person.prototype.walk = function(){
  alert ('I am walking!');
};
Person.prototype.sayHello = function(){
  alert ('hello');
};

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);// <---- Confusion
}

// inherit Person
Student.prototype = new Person(); //<---- Confusion

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student');
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

Now, I am confused ( <---- ) in these two lines. 现在,我在这两行中感到困惑( <---- )。 When I say Person.call(this); 当我说Person.call(this); , this is simply stating to Inherit properties of Person class... Right? ,这只是说明继承Person类的属性......对吗?

Then what is this doing? 那是做什么的?

  // inherit Person
    Student.prototype = new Person(); //<---- Confusion

As per my knowledge, .prototype also inherits all properties? 据我所知, .prototype还继承了所有属性?

To explain it, first let's remember how constructor functions work in JavaScript: 为了解释它,首先让我们记住构造函数在JavaScript中是如何工作的:

function Guide(a) {
    this.a = a;
}
Guide.prototype.q = "Life, the Universe, and Everything";

var g = new Guide(42);
console.log(g.q); // "Life, the Universe, and Everything"
console.log(g.a); // 42

When we do new Guide(42) , the new operator creates a new object and assigns it a prototype using the Guide.prototype property. 当我们执行new Guide(42)new运算符会创建一个新对象,并使用Guide.prototype属性为其分配原型 Then new calls Guide , passing in that new object as this . 然后, new电话Guide ,传递新的对象作为this Guide uses this to add properties to the new object that aren't on its prototype. Guide使用this将属性添加到新的对象,不在它的原型。 Then the new expression completes and its result is the new object that it created. 然后new表达式完成,其结果是它创建的新对象。

When we look at gq , since the g object doesn't have its own property called q , the JavaScript engine looks at g 's prototype, which (again) it got assigned when it was created. 当我们查看gq ,由于g对象没有自己的属性q ,JavaScript引擎会查看g的原型,它(再次)在创建时分配了它。 That prototype has a q property, and so the engine uses its value. 该原型具有q属性,因此引擎使用其值。

In contrast, when we look at ga , the g object has its own property called a , and so the value is used directly. 相反,当我们查看gag对象有自己的属性a ,因此直接使用该值。

With that foundation in place, let's look at Student and Parent : 有了这个基础,让我们来看看StudentParent

function Student() {
  // Call the parent constructor
  Person.call(this);// <---- Confusion
}

When we call new Student() , within the call to Student , this is (again) the new object created by the new operator, which has Student.prototype as its underlying prototype. 当我们调用new Student() ,在对Student的调用中, this是(再次)由new运算符创建的新对象,它具有Student.prototype作为其底层原型。 But the Parent function hasn't had a chance to do anything with this new object. 但是Parent函数没有机会对这个新对象做任何事情。 So what that line does is give Parent a chance to do whatever it needs to do to new objects that it can't do via the prototype, like our Guide function earlier assigning to this.a . 那么该行的作用是让Parent有机会对它不能通过原型做的新对象做任何事情,就像之前指定给this.a Guide函数一样。 In technical terms, Parent.call(this); 在技​​术方面, Parent.call(this); calls the Parent function, ensuring that this within the call to Parent is the value passed into call (which is, in this case, the this of the call to Student — eg, the new object). 调用Parent功能,确保this调用中Parent是传递到值call (这是在这种情况下, this调用的Student -例如,新的对象)。 If you're familiar with class-based languages, this is like doing super(); 如果你熟悉基于类的语言,这就像做super(); (that's Java, but you get the idea) in a derived constructor: It gives the base constructor a chance to initialize the object. (这是Java,但你明白了)在派生的构造函数中:它为基础构造函数提供了初始化对象的机会。

// inherit Person
Student.prototype = new Person(); //<---- Confusion

Since Student is supposed to inherit from Person , what that code is doing is creating the prototype that will be assigned to objects created via new Student . 由于Student应该从Person继承,因此该代码正在创建的原型将分配给通过new Student创建的对象。 The object it's creating is a Person object. 它创建的对象是Person对象。

FWIW, that code isn't quite implementing the construction chain correctly (it's calling Person more often than it should [both when creating Student.prototype and when Student is called], and failing to set constructor ). FWIW,该代码并没有完全正确地实现构造链(它更频繁地调用Person [创建Student.prototype 调用Student时],并且没有设置constructor )。

The more correct way to create Student 's prototype property, if we're going to call Parent from within Student , looks like this: 创建Studentprototype属性的更正确的方法,如果我们要从Student调用Parent ,看起来像这样:

function derive(child, parent) {
    function ctor() { this.constructor = child; }
    ctor.prototype = parent.prototype;
    child.prototype = new ctor();
}

derive(Student, Parent);

That way, we get a prototype based on Parent.prototype but without calling Parent . 这样,我们得到一个基于Parent.prototype的原型,但没有调用Parent It's an either-or: Either call Parent to create Student.prototype , or call Parent within Student , but don't do both. 它是一个 - 或者: 要么调用Parent来创建Student.prototype要么Student调用Parent ,但不要同时执行这两个操作。 When building hierarchies with constructor functions, typically you want to call the parent from the child constructor, rather than when creating the child prototype. 使用构造函数构建层次结构时,通常需要从子构造函数调用父级,而不是在创建子级原型时。 When using direct object inheritance (without constructor functions), of course you do it the other way. 当使用直接对象继承(没有构造函数)时,你当然是以另一种方式做到这一点。

If you're interested in inheritance in JavaScript, I've written a helper script called Lineage you might want to look at, and in particular even if you don't use Lineage , this discussion on its wiki page may be useful for understanding inheritance hierarchies. 如果您对JavaScript中的继承感兴趣,我编写了一个名为Lineage的帮助脚本,您可能希望查看,特别是即使您不使用Lineage ,在其Wiki页面上进行此讨论可能对理解继承有用层次结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM