繁体   English   中英

Javascript原型和通话之间的区别

[英]Javascript Difference between prototype and call

我正在学习javascript并感到困惑。 这里有一个例子如下: -

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

现在,我在这两行中感到困惑( <---- )。 当我说Person.call(this); ,这只是说明继承Person类的属性......对吗?

那是做什么的?

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

据我所知, .prototype还继承了所有属性?

为了解释它,首先让我们记住构造函数在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

当我们执行new Guide(42)new运算符会创建一个新对象,并使用Guide.prototype属性为其分配原型 然后, new电话Guide ,传递新的对象作为this Guide使用this将属性添加到新的对象,不在它的原型。 然后new表达式完成,其结果是它创建的新对象。

当我们查看gq ,由于g对象没有自己的属性q ,JavaScript引擎会查看g的原型,它(再次)在创建时分配了它。 该原型具有q属性,因此引擎使用其值。

相反,当我们查看gag对象有自己的属性a ,因此直接使用该值。

有了这个基础,让我们来看看StudentParent

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

当我们调用new Student() ,在对Student的调用中, this是(再次)由new运算符创建的新对象,它具有Student.prototype作为其底层原型。 但是Parent函数没有机会对这个新对象做任何事情。 那么该行的作用是让Parent有机会对它不能通过原型做的新对象做任何事情,就像之前指定给this.a Guide函数一样。 在技​​术方面, Parent.call(this); 调用Parent功能,确保this调用中Parent是传递到值call (这是在这种情况下, this调用的Student -例如,新的对象)。 如果你熟悉基于类的语言,这就像做super(); (这是Java,但你明白了)在派生的构造函数中:它为基础构造函数提供了初始化对象的机会。

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

由于Student应该从Person继承,因此该代码正在创建的原型将分配给通过new Student创建的对象。 它创建的对象是Person对象。

FWIW,该代码并没有完全正确地实现构造链(它更频繁地调用Person [创建Student.prototype 调用Student时],并且没有设置constructor )。

创建Studentprototype属性的更正确的方法,如果我们要从Student调用Parent ,看起来像这样:

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

derive(Student, Parent);

这样,我们得到一个基于Parent.prototype的原型,但没有调用Parent 它是一个 - 或者: 要么调用Parent来创建Student.prototype要么Student调用Parent ,但不要同时执行这两个操作。 使用构造函数构建层次结构时,通常需要从子构造函数调用父级,而不是在创建子级原型时。 当使用直接对象继承(没有构造函数)时,你当然是以另一种方式做到这一点。

如果您对JavaScript中的继承感兴趣,我编写了一个名为Lineage的帮助脚本,您可能希望查看,特别是即使您不使用Lineage ,在其Wiki页面上进行此讨论可能对理解继承有用层次结构。

暂无
暂无

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

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