[英]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
属性,因此引擎使用其值。
相反,当我们查看ga
, g
对象有自己的属性a
,因此直接使用该值。
有了这个基础,让我们来看看Student
和Parent
:
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
)。
创建Student
的prototype
属性的更正确的方法,如果我们要从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.