关于 MDN文档中 原型、继承、对象等知识点的一些疑惑,请大神帮忙解答,谢谢。

hopperhuang 2016-08-14 06:15:13
在谈到继承的时候,MDN上的文档是这么说的

function Person(firstName) {
this.firstName = firstName;
}

// 在Person.prototype中加入方法
Person.prototype.walk = function(){
alert("I am walking!");
};
Person.prototype.sayHello = function(){
alert("Hello, I'm " + this.firstName);
};

// 定义Student构造器
function Student(firstName, subject) {
// 调用父类构造器, 确保(使用Function#call)"this" 在调用过程中设置正确
Person.call(this, firstName);

// 初始化Student类特有属性
this.subject = subject;
};

// 建立一个由Person.prototype继承而来的Student.prototype对象.
// 注意: 常见的错误是使用 "new Person()"来建立Student.prototype.
// 这样做的错误之处有很多, 最重要的一点是我们在实例化时
// 不能赋予Person类任何的FirstName参数
// 调用Person的正确位置如下,我们从Student中来调用它
Student.prototype = Object.create(Person.prototype); // See note below

// 设置"constructor" 属性指向Student
Student.prototype.constructor = Student;

// 更换"sayHello" 方法
Student.prototype.sayHello = function(){
console.log("Hello, I'm " + this.firstName + ". I'm studying " + this.subject + ".");
};

// 加入"sayGoodBye" 方法
Student.prototype.sayGoodBye = function(){
console.log("Goodbye!");
};

// 测试实例:
var student1 = new Student("Janet", "Applied Physics");
student1.sayHello(); // "Hello, I'm Janet. I'm studying Applied Physics."
student1.walk(); // "I am walking!"
student1.sayGoodBye(); // "Goodbye!"

// Check that instanceof works correctly
console.log(student1 instanceof Person); // true
console.log(student1 instanceof Student); // true


其实这上面的,我有点不大懂。
在设置Student.prototype 的时候这样写不可以吗?Student.prototype = new Person ;
这样写在后面将Person类实例化的时候也没有出现不能赋予参数的问题啊。
还有再有一个问题就是:
为什么 Student.constructor一定要指回它本身呢??
我试过把这个句子给注释掉,
下面改变和创建新的方法也没有任何影响啊?
这里为什么要这样做呢??

大神们能帮我解答这个问题吗?
...全文
217 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
天际的海浪 2016-08-16
  • 打赏
  • 举报
回复
constructor的问题可以看看这个 http://www.jb51.net/article/22334.htm
hopperhuang 2016-08-16
  • 打赏
  • 举报
回复
引用 16 楼 jslang 的回复:
constructor的问题可以看看这个 http://www.jb51.net/article/22334.htm
好的,我去看看,谢谢您了。
天际的海浪 2016-08-15
  • 打赏
  • 举报
回复
引用 2 楼 baidu_23010771 的回复:
请问可以举三个例子来说明一下,三个缺点吗??这样说好像理解了,但其实又不大清楚实际情况。
缺点一实例
var arr = [];//想把每次创建的实例对象都自动放到arr数组中,好统一管理
function Parent() {
	arr.push(this);
}

function Sub() {
	this.name = "";
}

Sub.prototype = new Parent();//设置继承

alert(arr.length);//还没有创建实例对象,arr数组中就已经有一个了

var a = new Sub();
var b = new Sub();

alert(arr.length);//创建了两个实例对象,arr数组中还是只有一个
缺点二实例


function Parent() {
	this.offset = {x:0, y:0};
}

function Sub() {
	this.id = 123;
}

Sub.prototype = new Parent();//设置继承

var a = new Sub();
var b = new Sub();

a.offset.x = 200;
alert(b.offset.x);//对a.offset对象的修改,一起反映到b.offset对象上了
缺点三实例

function Parent(n) {
	this.name = n;
}

function Sub(n,a) {
	this.age = a;
}

Sub.prototype = new Parent();//设置继承

var a = new Sub("王五",26);//没有办法在实例化时给name传递参数。
hopperhuang 2016-08-15
  • 打赏
  • 举报
回复
引用 5 楼 KK3K2005 的回复:
如果a.offset.x = 200这样写,等于Sub.offset.x = 200,因此b 作为SUB的实例,b的值也会跟着改变。 不对 对于一个属性分读写2个操作 读:如果当前对象下不存在该 属性 哪么 根据原型链 从当前对象的原型上 查找该属性, 该过程 会一直持续到找到 或者确认不存在为止 写:直接在当前对象下 建立该属性 不会影响原型链 上的属性
好的好的,谢谢。
KK3K2005 2016-08-15
  • 打赏
  • 举报
回复
另外 面向对象的概念 和 具体语言的实现 是不相关的 不要混淆 脚本语言 实现面向对象 和 面向对象语言实现面向对象 实现细节时不一样的 所以面向对象 不用了解细节 了解概念 就可以了 至于实现细节 和语言的语法特性有关系
KK3K2005 2016-08-15
  • 打赏
  • 举报
回复
如果a.offset.x = 200这样写,等于Sub.offset.x = 200,因此b 作为SUB的实例,b的值也会跟着改变。 不对 对于一个属性分读写2个操作 读:如果当前对象下不存在该 属性 哪么 根据原型链 从当前对象的原型上 查找该属性, 该过程 会一直持续到找到 或者确认不存在为止 写:直接在当前对象下 建立该属性 不会影响原型链 上的属性
hopperhuang 2016-08-15
  • 打赏
  • 举报
回复
引用 3 楼 jslang 的回复:
[quote=引用 2 楼 baidu_23010771 的回复:] 请问可以举三个例子来说明一下,三个缺点吗??这样说好像理解了,但其实又不大清楚实际情况。
缺点一实例
var arr = [];//想把每次创建的实例对象都自动放到arr数组中,好统一管理
function Parent() {
	arr.push(this);
}

function Sub() {
	this.name = "";
}

Sub.prototype = new Parent();//设置继承

alert(arr.length);//还没有创建实例对象,arr数组中就已经有一个了

var a = new Sub();
var b = new Sub();

alert(arr.length);//创建了两个实例对象,arr数组中还是只有一个
缺点二实例


function Parent() {
	this.offset = {x:0, y:0};
}

function Sub() {
	this.id = 123;
}

Sub.prototype = new Parent();//设置继承

var a = new Sub();
var b = new Sub();

a.offset.x = 200;
alert(b.offset.x);//对a.offset对象的修改,一起反映到b.offset对象上了
缺点三实例

function Parent(n) {
	this.name = n;
}

function Sub(n,a) {
	this.age = a;
}

Sub.prototype = new Parent();//设置继承

var a = new Sub("王五",26);//没有办法在实例化时给name传递参数。
[/quote] 针对第三个问题,我认为是这样的,您这个例子举的有点不适合。这里不能传递参数并不是继承的方法出现了问题。 而是在构建SUB的原型的时候,没有CALL Paretn。 我通过这样的写法,维持原来的继承方式不变,依然可以传递参数。

function Parent(n) {
    this.name = n;
}
 
function Sub(n,a) {
Parent.call(this,n );
    this.age = a;
}
 
Sub.prototype = new Parent();//设置继承
 
var a = new Sub("test",26);//没有办法在实例化时给name传递参数。

console.log( a.name )//控制台会输出test;
我认为对第三个缺点的解释通过下面的例子是比较合适的。

function Employee () {
  this.name = "test";
  this.dept = "general";
}

function WorkerBee () {
  this.projects = [];
}
WorkerBee.prototype = new Employee;
var amy = new WorkerBee;
Employee.prototype.name = "Unknown"

console.log( amy.name );//控制台输出test而不是"unknown"
第三个缺点是由于WorkerBee.prototype = new Employee;设置继承的时候出现的。 如果改成改成WorkerBee.prototype = Object.create( Employee.prototype );会出现另一种情况。 参数可以传递,但是amy这个实例里面没有name属性。

function Employee () {
  this.name = "test";
  this.dept = "general";
}

function WorkerBee () {
  this.projects = [];
}
WorkerBee.prototype = new Employee;
var amy = Object.create( Employee.prototype ) ;


console.log( amy.name );//控制台输出undefined
Employee.prototype.name = "Unknown"
console.log( amy.name )//控制台输出Unknown

因为在本地获得的是projects ,从__proto__中的WokderBee.prototype继承来的是Employee.prototype;而Employee.prototype并没有任何设置,所以amy并没有name这个属性,因为他没有从employee中继承到name。 至于第二个例子我可以这样理解吗?? a = new Sub(); a对象对象从本地中得到的是ID属性,offset属性是从__proto__继承来的。 a.__proto__ == Sub.prototype; Sub.prototype = new Parent; 所以Sub.prototype 的本地中就存有offset属性。 a.offset.x = 200语句中,js首先会寻找a本地有没有offset属性,显然是没有的,所以他会到__proto__,也就是Sub.prototype里面寻找。而Sub.prototype本地中存放了offset属性。所以,如果a.offset.x = 200这样写,等于Sub.offset.x = 200,因此b 作为SUB的实例,b的值也会跟着改变。 请问,对于例子二我这样的理解正确吗?? 对于例子一,我想我还需要消化一下。
hopperhuang 2016-08-15
  • 打赏
  • 举报
回复
引用 14 楼 jslang 的回复:
[quote=引用 12 楼 baidu_23010771 的回复:] [quote=引用 8 楼 jslang 的回复:] 其实在 Sub() 中用 Parent.call(this,n); 调用父类的构造函数。就可以解决缺点二和缺点三的问题。 在使用了Parent.call(this,n)之后,再来看缺点一的问题,这不就在Sub.prototype = new Parent();设置继承的时候多执行了一次父类的构造函数么? 那么只要想办法在不执行父类的构造函数情况下,得到一个有着Parent.prototype为原型的对象就解决了啊 解决方法最简单的当然就是 Sub.prototype = Object.create(Parent.prototype); 不过Object.create()要ie9才支持。对于ie8以下还可以用。 Sub.prototype = {}; Sub.prototype.__proto__ = Parent.prototype; 或者 function NullFun() { } NullFun.prototype = Parent.prototype; Sub.prototype = new NullFun();
我在说说我的理解吧,不对的话请您指正。从您给出的例子,加上我自己的思考,我觉得在继承的时候这样操作会比较合理。 如果该语句或者说属性是需要在实例化的时候每次都运行的,比如您的例子一,需要对属性进行保护的,比如例子二,想要传递参数,比如说例子三,在创建新的类的时候,最好的方法是利用CALL方法,调用前一个类(或者说目标类),这样能对某些属性存在本地,起到保护作用,又可以传递参数。而想要更原始的类去修改某个特别的属性的时候,把这个属性放到原型链的上去继承,显然更有效果。 比如我下面举的这个例子

function Employee () {
  this.dept = "general";
}
Employee.prototype.name = "test"; 
 
function WorkerBee () {
  Employee.call(this);
  this.projects = [];
}
WorkerBee.prototype = Object.create( Employee.prototype );
var amy =  new WorkerBee ;
 
 
console.log( amy.name );//控制台输出test
Employee.prototype.name = "Unknown"
console.log( amy.name )//控制台输出Unknown
amy.name  = "foryou";
console.log(amy.name )//控制台输出FORYOU
[/quote] 呵呵,你有没有发现你这个例子与你主楼发的MDN上的例子是一样的。 对。这就是最完善的写法[/quote] 嗯嗯,谢谢大神的指点了,现在我已经更加理解JS的原型链和继承机制了。在我提的两个问题提中,通过跟您的讨论与自己的思考,我已经理解的比较多。关于第二个Constructor的问题,能不能跟第一个例子一样写几个例子来说说Constructor的一些实际应用和方法。
天际的海浪 2016-08-15
  • 打赏
  • 举报
回复
引用 12 楼 baidu_23010771 的回复:
[quote=引用 8 楼 jslang 的回复:] 其实在 Sub() 中用 Parent.call(this,n); 调用父类的构造函数。就可以解决缺点二和缺点三的问题。 在使用了Parent.call(this,n)之后,再来看缺点一的问题,这不就在Sub.prototype = new Parent();设置继承的时候多执行了一次父类的构造函数么? 那么只要想办法在不执行父类的构造函数情况下,得到一个有着Parent.prototype为原型的对象就解决了啊 解决方法最简单的当然就是 Sub.prototype = Object.create(Parent.prototype); 不过Object.create()要ie9才支持。对于ie8以下还可以用。 Sub.prototype = {}; Sub.prototype.__proto__ = Parent.prototype; 或者 function NullFun() { } NullFun.prototype = Parent.prototype; Sub.prototype = new NullFun();
我在说说我的理解吧,不对的话请您指正。从您给出的例子,加上我自己的思考,我觉得在继承的时候这样操作会比较合理。 如果该语句或者说属性是需要在实例化的时候每次都运行的,比如您的例子一,需要对属性进行保护的,比如例子二,想要传递参数,比如说例子三,在创建新的类的时候,最好的方法是利用CALL方法,调用前一个类(或者说目标类),这样能对某些属性存在本地,起到保护作用,又可以传递参数。而想要更原始的类去修改某个特别的属性的时候,把这个属性放到原型链的上去继承,显然更有效果。 比如我下面举的这个例子

function Employee () {
  this.dept = "general";
}
Employee.prototype.name = "test"; 
 
function WorkerBee () {
  Employee.call(this);
  this.projects = [];
}
WorkerBee.prototype = Object.create( Employee.prototype );
var amy =  new WorkerBee ;
 
 
console.log( amy.name );//控制台输出test
Employee.prototype.name = "Unknown"
console.log( amy.name )//控制台输出Unknown
amy.name  = "foryou";
console.log(amy.name )//控制台输出FORYOU
[/quote] 呵呵,你有没有发现你这个例子与你主楼发的MDN上的例子是一样的。 对。这就是最完善的写法
天际的海浪 2016-08-15
  • 打赏
  • 举报
回复
引用 11 楼 baidu_23010771 的回复:
[quote=引用 10 楼 jslang 的回复:] [quote=引用 9 楼 baidu_23010771 的回复:] [quote=引用 7 楼 baidu_23010771 的回复:] [quote=引用 5 楼 KK3K2005 的回复:] 如果a.offset.x = 200这样写,等于Sub.offset.x = 200,因此b 作为SUB的实例,b的值也会跟着改变。 不对 对于一个属性分读写2个操作 读:如果当前对象下不存在该 属性 哪么 根据原型链 从当前对象的原型上 查找该属性, 该过程 会一直持续到找到 或者确认不存在为止 写:直接在当前对象下 建立该属性 不会影响原型链 上的属性
好的好的,谢谢。[/quote] 请问例子一是改写成这样吗?

var arr = [];//想把每次创建的实例对象都自动放到arr数组中,好统一管理
function Parent() {
    arr.push(this);
}
 
function Sub() {
    this.name = "";
}
 
Sub.prototype = Object.create(Parent.prototype);//设置继承
 
alert(arr.length);//还没有创建实例对象,arr数组中就已经有一个了
 
var a = new Sub();
var b = new Sub();
 
alert(arr.length);//创建了两个实例对象,arr数组中还是只有一个
如果是这写的话,控制台输出的arr.length两次都是0。得不到我们想要的效果。[/quote] 用Sub.prototype = Object.create(Parent.prototype);//设置继承时就需要在Sub() 中使用 Parent.call(this); 与之配合[/quote] 我发现这样也是可以的。把Sub.prototype = Object.create( Parent.prototype );这局注释掉。加上CALL方法。就想下面这样写。在创建新的实例的时候也会将对象加入到ARR当中去。

var arr = [];//想把每次创建的实例对象都自动放到arr数组中,好统一管理
function Parent() {
    arr.push(this);
}
  
function Sub() {
Parent.call(this);
    this.name = "";
}
  
//Sub.prototype = Object.create(Parent.prototype);//设置继承
  
console.log(arr.length);//还没有创建实例对象,arr数组中就已经有一个了
  
var a = new Sub();
var b = new Sub();
  
console.log(arr.length);//创建了两个实例对象,arr数组中还是只有一个
//console.log( Parent.prototype );
console.log(arr);
我说说我的理解吧,不对的话请您指正。在SUB的构造函数里面调用PARENT的构造函数,使得SUB对象本地就有了这个语句 arr.push(this);,所以在实例化的时候,每实例化一次,就会有一个新的实例被PUSH进去ARR里面。 我觉得Sub.prototype = Object.create(Parent.prototype);这个语句并不起作用。 我试着输出了这个结果console.log( Sub.prototype ); 这个语句返回的结果是:Parent{} ,说明了SUB从PARENT原型链上并没有继承得到任何的东西。 我增加了一个语句,Parent.prototype.test = "test"; 然后输出console.log( Sub.prototype );输出结果是 Parent {test: "test"} ; 所以,我认为在不设置Parent.prototype 的情况下,我们写Sub.prototype = Object.create( Parent.prototype ),是没有意义的,因为SUB从原型链上继承不了任何东西。 真正起作用的是CALL语句。 [/quote] 不写Sub.prototype = Object.create( Parent.prototype ), 对象实例a 就不属于 Parent类的了; console.log(a instanceof Parent);
hopperhuang 2016-08-15
  • 打赏
  • 举报
回复
引用 8 楼 jslang 的回复:
其实在 Sub() 中用 Parent.call(this,n); 调用父类的构造函数。就可以解决缺点二和缺点三的问题。 在使用了Parent.call(this,n)之后,再来看缺点一的问题,这不就在Sub.prototype = new Parent();设置继承的时候多执行了一次父类的构造函数么? 那么只要想办法在不执行父类的构造函数情况下,得到一个有着Parent.prototype为原型的对象就解决了啊 解决方法最简单的当然就是 Sub.prototype = Object.create(Parent.prototype); 不过Object.create()要ie9才支持。对于ie8以下还可以用。 Sub.prototype = {}; Sub.prototype.__proto__ = Parent.prototype; 或者 function NullFun() { } NullFun.prototype = Parent.prototype; Sub.prototype = new NullFun();
我在说说我的理解吧,不对的话请您指正。从您给出的例子,加上我自己的思考,我觉得在继承的时候这样操作会比较合理。 如果该语句或者说属性是需要在实例化的时候每次都运行的,比如您的例子一,需要对属性进行保护的,比如例子二,想要传递参数,比如说例子三,在创建新的类的时候,最好的方法是利用CALL方法,调用前一个类(或者说目标类),这样能对某些属性存在本地,起到保护作用,又可以传递参数。而想要更原始的类去修改某个特别的属性的时候,把这个属性放到原型链的上去继承,显然更有效果。 比如我下面举的这个例子

function Employee () {
  this.dept = "general";
}
Employee.prototype.name = "test"; 
 
function WorkerBee () {
  Employee.call(this);
  this.projects = [];
}
WorkerBee.prototype = Object.create( Employee.prototype );
var amy =  new WorkerBee ;
 
 
console.log( amy.name );//控制台输出test
Employee.prototype.name = "Unknown"
console.log( amy.name )//控制台输出Unknown
amy.name  = "foryou";
console.log(amy.name )//控制台输出FORYOU
hopperhuang 2016-08-15
  • 打赏
  • 举报
回复
引用 10 楼 jslang 的回复:
[quote=引用 9 楼 baidu_23010771 的回复:] [quote=引用 7 楼 baidu_23010771 的回复:] [quote=引用 5 楼 KK3K2005 的回复:] 如果a.offset.x = 200这样写,等于Sub.offset.x = 200,因此b 作为SUB的实例,b的值也会跟着改变。 不对 对于一个属性分读写2个操作 读:如果当前对象下不存在该 属性 哪么 根据原型链 从当前对象的原型上 查找该属性, 该过程 会一直持续到找到 或者确认不存在为止 写:直接在当前对象下 建立该属性 不会影响原型链 上的属性
好的好的,谢谢。[/quote] 请问例子一是改写成这样吗?

var arr = [];//想把每次创建的实例对象都自动放到arr数组中,好统一管理
function Parent() {
    arr.push(this);
}
 
function Sub() {
    this.name = "";
}
 
Sub.prototype = Object.create(Parent.prototype);//设置继承
 
alert(arr.length);//还没有创建实例对象,arr数组中就已经有一个了
 
var a = new Sub();
var b = new Sub();
 
alert(arr.length);//创建了两个实例对象,arr数组中还是只有一个
如果是这写的话,控制台输出的arr.length两次都是0。得不到我们想要的效果。[/quote] 用Sub.prototype = Object.create(Parent.prototype);//设置继承时就需要在Sub() 中使用 Parent.call(this); 与之配合[/quote] 我发现这样也是可以的。把Sub.prototype = Object.create( Parent.prototype );这局注释掉。加上CALL方法。就想下面这样写。在创建新的实例的时候也会将对象加入到ARR当中去。

var arr = [];//想把每次创建的实例对象都自动放到arr数组中,好统一管理
function Parent() {
    arr.push(this);
}
  
function Sub() {
Parent.call(this);
    this.name = "";
}
  
//Sub.prototype = Object.create(Parent.prototype);//设置继承
  
console.log(arr.length);//还没有创建实例对象,arr数组中就已经有一个了
  
var a = new Sub();
var b = new Sub();
  
console.log(arr.length);//创建了两个实例对象,arr数组中还是只有一个
//console.log( Parent.prototype );
console.log(arr);
我说说我的理解吧,不对的话请您指正。在SUB的构造函数里面调用PARENT的构造函数,使得SUB对象本地就有了这个语句 arr.push(this);,所以在实例化的时候,每实例化一次,就会有一个新的实例被PUSH进去ARR里面。 我觉得Sub.prototype = Object.create(Parent.prototype);这个语句并不起作用。 我试着输出了这个结果console.log( Sub.prototype ); 这个语句返回的结果是:Parent{} ,说明了SUB从PARENT原型链上并没有继承得到任何的东西。 我增加了一个语句,Parent.prototype.test = "test"; 然后输出console.log( Sub.prototype );输出结果是 Parent {test: "test"} ; 所以,我认为在不设置Parent.prototype 的情况下,我们写Sub.prototype = Object.create( Parent.prototype ),是没有意义的,因为SUB从原型链上继承不了任何东西。 真正起作用的是CALL语句。
天际的海浪 2016-08-15
  • 打赏
  • 举报
回复
引用 9 楼 baidu_23010771 的回复:
[quote=引用 7 楼 baidu_23010771 的回复:] [quote=引用 5 楼 KK3K2005 的回复:] 如果a.offset.x = 200这样写,等于Sub.offset.x = 200,因此b 作为SUB的实例,b的值也会跟着改变。 不对 对于一个属性分读写2个操作 读:如果当前对象下不存在该 属性 哪么 根据原型链 从当前对象的原型上 查找该属性, 该过程 会一直持续到找到 或者确认不存在为止 写:直接在当前对象下 建立该属性 不会影响原型链 上的属性
好的好的,谢谢。[/quote] 请问例子一是改写成这样吗?

var arr = [];//想把每次创建的实例对象都自动放到arr数组中,好统一管理
function Parent() {
    arr.push(this);
}
 
function Sub() {
    this.name = "";
}
 
Sub.prototype = Object.create(Parent.prototype);//设置继承
 
alert(arr.length);//还没有创建实例对象,arr数组中就已经有一个了
 
var a = new Sub();
var b = new Sub();
 
alert(arr.length);//创建了两个实例对象,arr数组中还是只有一个
如果是这写的话,控制台输出的arr.length两次都是0。得不到我们想要的效果。[/quote] 用Sub.prototype = Object.create(Parent.prototype);//设置继承时就需要在Sub() 中使用 Parent.call(this); 与之配合
hopperhuang 2016-08-15
  • 打赏
  • 举报
回复
引用 7 楼 baidu_23010771 的回复:
[quote=引用 5 楼 KK3K2005 的回复:] 如果a.offset.x = 200这样写,等于Sub.offset.x = 200,因此b 作为SUB的实例,b的值也会跟着改变。 不对 对于一个属性分读写2个操作 读:如果当前对象下不存在该 属性 哪么 根据原型链 从当前对象的原型上 查找该属性, 该过程 会一直持续到找到 或者确认不存在为止 写:直接在当前对象下 建立该属性 不会影响原型链 上的属性
好的好的,谢谢。[/quote] 请问例子一是改写成这样吗?

var arr = [];//想把每次创建的实例对象都自动放到arr数组中,好统一管理
function Parent() {
    arr.push(this);
}
 
function Sub() {
    this.name = "";
}
 
Sub.prototype = Object.create(Parent.prototype);//设置继承
 
alert(arr.length);//还没有创建实例对象,arr数组中就已经有一个了
 
var a = new Sub();
var b = new Sub();
 
alert(arr.length);//创建了两个实例对象,arr数组中还是只有一个
如果是这写的话,控制台输出的arr.length两次都是0。得不到我们想要的效果。
天际的海浪 2016-08-15
  • 打赏
  • 举报
回复
其实在 Sub() 中用 Parent.call(this,n); 调用父类的构造函数。就可以解决缺点二和缺点三的问题。 在使用了Parent.call(this,n)之后,再来看缺点一的问题,这不就在Sub.prototype = new Parent();设置继承的时候多执行了一次父类的构造函数么? 那么只要想办法在不执行父类的构造函数情况下,得到一个有着Parent.prototype为原型的对象就解决了啊 解决方法最简单的当然就是 Sub.prototype = Object.create(Parent.prototype); 不过Object.create()要ie9才支持。对于ie8以下还可以用。 Sub.prototype = {}; Sub.prototype.__proto__ = Parent.prototype; 或者 function NullFun() { } NullFun.prototype = Parent.prototype; Sub.prototype = new NullFun();
hopperhuang 2016-08-14
  • 打赏
  • 举报
回复
引用 1 楼 jslang 的回复:
Student.prototype = new Person() 这是一个比较常见继承方法,它是通过把子类的原型对象(prototype)设置成父类的一个实例来进行继承的。 但是只简单的这样设置继承有三个缺点:   缺点一:执行上面代码会发现父类的构造函数不是像JAVA中那样在给子类进行实例化时执行的,而是在设置继承的时候执行的,并且只执行一次。这往往不是我们希望的,特别是父类的构造函数中有一些特殊操作的情况下。   缺点二:由于父类的构造函数不是在子类进行实例化时执行,在父类的构造函数中设置的成员变量到了子类中就成了所有实例对象公有的公共变量。由于JavaScript中继承只发生在“获取”属性的值时,对于属性的值是String,Number和Boolean这些数据本身不能被修改的类型时没有什么影响。但是Array和Object类型就会有问题。   缺点三:如果父类的构造函数需要参数,我们没有办法在实例化时传递参数。 constructor问题: 有的人喜欢用constructor来判断对象的类型。 但子类原本的原型对象被替换了,子类本身的constructor属性就没有了。在类的实例取它的constructor属性时,取得的是从父类中继承的constructor属性,从而constructor的值是父类而不是子类。 这样在用constructor来判断对象的类型时就会出错。 所以需要把子类的constructor属性设置回来。 当然,你说你从不使用constructor属性。那就不用设置回来了。
请问可以举三个例子来说明一下,三个缺点吗??这样说好像理解了,但其实又不大清楚实际情况。
天际的海浪 2016-08-14
  • 打赏
  • 举报
回复
Student.prototype = new Person() 这是一个比较常见继承方法,它是通过把子类的原型对象(prototype)设置成父类的一个实例来进行继承的。 但是只简单的这样设置继承有三个缺点:   缺点一:执行上面代码会发现父类的构造函数不是像JAVA中那样在给子类进行实例化时执行的,而是在设置继承的时候执行的,并且只执行一次。这往往不是我们希望的,特别是父类的构造函数中有一些特殊操作的情况下。   缺点二:由于父类的构造函数不是在子类进行实例化时执行,在父类的构造函数中设置的成员变量到了子类中就成了所有实例对象公有的公共变量。由于JavaScript中继承只发生在“获取”属性的值时,对于属性的值是String,Number和Boolean这些数据本身不能被修改的类型时没有什么影响。但是Array和Object类型就会有问题。   缺点三:如果父类的构造函数需要参数,我们没有办法在实例化时传递参数。 constructor问题: 有的人喜欢用constructor来判断对象的类型。 但子类原本的原型对象被替换了,子类本身的constructor属性就没有了。在类的实例取它的constructor属性时,取得的是从父类中继承的constructor属性,从而constructor的值是父类而不是子类。 这样在用constructor来判断对象的类型时就会出错。 所以需要把子类的constructor属性设置回来。 当然,你说你从不使用constructor属性。那就不用设置回来了。

87,904

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧