3. js怎么实现继承?面试
1. 使用原型prototypeapp
这个问题其实以前总结过了……可是面试时候有点忘……主要思想是记得的,可是不会写,仍是基础太不牢靠,写的太少了。一开始由于不知道怎么能继承父类的方法属性,同时又不直接使用其原型,因此先写了一种,子类直接调用父类的原型。可是其中有些过程和方法确定是写错了的……下面是正确的写法:函数
1 var Parent = function(name){
2 this.name = name || "parent"; 3 } 4 Parent.prototype.getName = function(){ 5 return this.name; 6 } 7 8 var Child = function(name){ 9 Parent.apply(this,arguments); //经过apply调用父类的构造函数来进行相同的初始化工做 10 } 11 Child.prototype = Parent.prototype; 12 13 var parent = new Parent("MyParent"); 14 var child = new Child("MyChild"); 15 16 console.log(parent.getName()); //MyParent 17 console.log(child.getName()); //MyChild
//这样咱们就只须要在子类构造函数中执行一次父类的构造函数,同时又能够继承父类原型中的属性,这也比较符合原型的初衷,就是把须要复用的内容放在原型中,咱们也只是继承了原型中可复用的内容。
这里若是按序打印 parent, child, Parent, Child,则输出以下:this
而后面试官又问若是只想改变子类的原型而不影响父类呢……我想了半天不知道怎么写,可是由于以前看过,就讲了下思想,就是用一个中间变量来存储其原型,而后给子类new一个……正确方法以下:es5
//临时构造函数模式(圣杯模式)(别问我为何会有一个名字这么中二的方法我也不知道)
//上面借用构造函数模式最后改进的版本仍是存在问题,它把父类的原型直接赋值给子类的原型,这就会形成一个问题,就是若是对子类的原型作了修改,那么这个修改同时也会影响到父类的原型,进而影响父类对象,这个确定不是你们所但愿看到的。为了解决这个问题就有了临时构造函数模式。
var Parent = function(name){
this.name = name || 'parent' ; } ; Parent.prototype.getName = function(){ return this.name ; } ; Parent.prototype.obj = {a : 1} ; var Child = function(name){ Parent.apply(this,arguments) ;//经过apply调用父类的构造函数来进行相同的初始化工做 } ; var F = new Function(); F.prototype = Parent.prototype ; Child.prototype = new F() ; //经过在父类原型和子类原型之间加入一个临时的构造函数F,切断了子类原型和父类原型之间的联系,这样当子类原型作修改时就不会影响到父类原型。 var parent = new Parent('myParent') ; var child = new Child('myChild') ; console.log(parent.getName()) ; //myParent console.log(child.getName()) ; //myChild
打印结果:spa
能够看到Child的实例child会多嵌套一层。.net
而后我发现其实能够不使用中间变量F,直接Child.prototype = new Parent();也能够。prototype
var Parent = function(name){
this.name = name || 'parent' ; } ; Parent.prototype.getName = function(){ return this.name ; } ; Parent.prototype.obj = {a : 1} ; var Child = function(name){ Parent.apply(this,arguments) ;//经过apply调用父类的构造函数来进行相同的初始化工做 } ; Child.prototype = new Parent() ; Child.prototype.sayHi = function(){ alert("hi!"); } var parent = new Parent('myParent') ; var child = new Child('myChild') ; console.log(parent.getName()) ; //myParent console.log(child.getName()) ; //myChild parent.sayHi(); //not a function 报错。说明子类的prototype不会影响到父类
这样的问题是:父类构造函数被执行了两次,一次是在子类构造函数中,一次在赋值子类原型时,这是不少余的。code
那么是否能够不使用apply,直接var Child = new Function(); Child.prototype = new Parent();呢……这样绝对不能够!对象
//这种方法是错误的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
var Parent = function(name){ this.name = name || 'parent' ; } ; Parent.prototype.getName = function(){ return this.name ; } ; Parent.prototype.obj = {a : 1} ; var Child = new Function(); Child.prototype = new Parent() ; var parent = new Parent('myParent') ; var child = new Child('myChild') ; console.log(parent.getName()) ; //myParent console.log(child.getName()) ; //parent
//child是Function对象,其中并无name属性,因此在new一个Child时,括号内的参数是无效的!!!!
那这种方法不是更容易吗……有什么缺点呢?console.log打印一下parent和child,以及Parent和Child,就会发现问题……
能够看到,打印Parent中是有name属性的,而Child里没有name这一属性。而如果看parent和child两个实例,就能够看到其实例也没有name属性,name是原型的属性,这个意思就是说,若是Child有多个实例,多个实例的name属性都会指向同一个name,而不是私有的。
因此方法就是1和2了
2. 对象冒充
1 function Parent(name){ 2 this.name = name; 3 this.getName = function(){ 4 return this.name; 5 } 6 } 7 function Child(name,password){ 8 //经过如下3步实现将Parent属性和方法追加到Child中,从而实现继承 9 //第一步:this.method是做为一个临时的属性,而且指向Parent所指的对象 10 //第二步:执行this.method方法,即执行Parent所指向的对象函数 11 //第三步:销毁this.method属性,即此时Child就已经拥有了Parent的全部属性和方法 12 this.method = Parent; 13 this.method(name); 14 delete(this.method); 15 16 this.password = password; 17 this.world = function(){ 18 alert(this.password); 19 } 20 } 21 var child = new Child("Mychild","123456"); 22 console.log(child.getName()); //Mychild 23 child.world(); //123456
此外可参考博文:http://blog.csdn.net/james521314/article/details/8645815