我正在学习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
还继承了所有属性?
答案 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
,因此直接使用该值。
有了这个基础,让我们看一下a
和Student
:
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.prototype
,或在Parent
内调用Parent
,但是不要两者都做。使用构造函数构建层次结构时,通常需要从子构造函数调用父级,而不是在创建子级原型时。当使用直接对象继承(没有构造函数)时,你当然可以采用另一种方式。
如果您对JavaScript中的继承感兴趣,我编写了一个名为Lineage
的帮助脚本,您可能希望查看,特别是即使您不使用Student.prototype
,{其维基页面上的{3}}可能对理解继承层次结构很有用。