Javascript原型和通话之间的区别

时间:2013-10-28 09:29:58

标签: javascript

我正在学习javascript并感到困惑。以here为例的示例,其示例如下: -

// 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还继承了所有属性?

1 个答案:

答案 0 :(得分:4)

为了解释它,首先让我们记住构造函数在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表达式完成,其结果是它创建的新对象。

当我们查看g.q时,由于g对象没有名为q拥有属性,因此JavaScript引擎会查看{{1}原型,它(再次)在创建它时被赋值。该原型具有g属性,因此引擎使用其值。

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

有了这个基础,让我们看一下aStudent

Parent

当我们致电function Student() { // Call the parent constructor Person.call(this);// <---- Confusion } 时,在new Student()的调用中,Student(再次)是由this运算符创建的新对象,new运算符Student.prototype }作为其基础原型。但是Parent函数没有机会对这个新对象做任何事情。那么该行的作用是让Parent有机会对它不能通过原型做的新对象做任何事情,就像之前分配给Guide的{​​{1}}函数一样。 。在技​​术术语中,this.a调用Parent.call(this);函数,确保Parent调用中的this是传递给Parent的值(在此case,call调用的this - 例如,新对象)。如果您熟悉基于类的语言,这就像在派生构造函数中执行Student(那是Java,但您明白了):它为基础构造函数提供了初始化对象的机会。

super();

由于// inherit Person Student.prototype = new Person(); //<---- Confusion 应该从Student继承,该代码正在做的是创建将分配给通过Person创建的对象的原型。它创建的对象是new Student对象。

FWIW,该代码没有完全正确地实现构造链(它更频繁地调用Person [在创建Person 时{{1}被称为],并且未能设置Student.prototype)。

如果我们要从Student内拨打constructor,创建Student的{​​{1}}媒体资源的更正确方法如下:

prototype

这样,我们可以根据Parent获得原型,但不会调用Student。这是一个 - 或者要么调用function derive(child, parent) { function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); } derive(Student, Parent); 来创建Parent.prototypeParent内调用Parent,但是不要两者都做。使用构造函数构建层次结构时,通常需要从子构造函数调用父级,而不是在创建子级原型时。当使用直接对象继承(没有构造函数)时,你当然可以采用另一种方式。

如果您对JavaScript中的继承感兴趣,我编写了一个名为Lineage的帮助脚本,您可能希望查看,特别是即使您不使用Student.prototype,{其维基页面上的{3}}可能对理解继承层次结构很有用。