`

js原型链继承的几个细节问题

阅读更多

1.怎样实现只继承prototype

先看下面的代码:

function A(){
 this.name="李可可";
 this.age=21;
}
A.prototype.eat=function(){ console.log("I can eat") }
function B(){}
B.prototype=new A;//B继承了A

var cc=new B;
cc.eat();//I can eat
cc.name;//"李可可"

我们可以看到的是,A继承了B的所有属性,那如果我们只想让B继承A.prototype属性,不想要A上面的name和age等一大堆没用的东西,那该怎么办?

有人可能就说了,直接像下面这样不就完了吗:

B.prototype=A.prototype;
var cc=new B;
cc.eat();//I can eat
cc.name;//undefined

哟,好像很完美?继续来看

B.prototype.fuck=function(){console.log("I fuck you!")}
var cc=new B,dd=new A;
cc.fuck();//I fuck you!
dd.fuck();//I fuck you!
//哦买噶的,怎么两个人都学会骂人了
//当子类B的prototype发生变化时也会影响到A的prototype(当然反过来也是),原因也很简单,因为我们让A.prototype指向了B的prototype

 解决办法:

构建一个函数,里面创建一个空的对象,并且让该空对象的prototype指向要继承的父对象,最终返回该对象的实例,代码如下

Object.createPro=function(pro){
  function F(){}
  F.prototype=pro;
  return new F;
}

 我们可以测试来一下:

function A(){
 this.name="李可可";
 this.age=21;
}
A.prototype.eat=function(){ console.log("I can eat") }
function B(){}
B.prototype=Object.createPro(A.prototype);//B只继承了A的prototype属性

var cc=new B;
cc.eat();//I can eat
cc.name;//
B.prototype.fuck=function(){console.log("I fuck you!")}//我们现在改变B的prototype
var dd=new A;
dd.fuck();//报错TypeError
//说明B.prototype的改变并没有影响到A的任何属性

 但是这样做也太麻烦了吧,我们可以直接使用Object自带的一个静态方法create():

function A(){
 this.name="李可可";
 this.age=21;
}
A.prototype.eat=function(){ console.log("I can eat") }
function B(){}
B.prototype=Object.create(A.prototype);//只会继承A的prototype

 在继承的同时也可以给B添加一些特有的属性如下:

function A(){
 this.name="李可可";
 this.age=21;
}
A.prototype.eat=function(){ console.log("I can eat") }
function B(){}
B.prototype=Object.create(A.prototype,{ 
 p: { value: 42, writable: false, enumerable: true }//添加一个属性p,并且是不可写的,但可枚举
});
var pp=new B;
pp.p;//42
pp.name;//undefined
pp.eat();//I can eat
pp.p=666;
pp.p;//42 (不可写)

 其中第二个参数很像Object.defineproperties()可以在里面配置多个属性并且给一些特殊的权限标签

 当然,想通过此方法继承A的所有属性也是可以的像下面

B.prototype=Object.create(new A);

或者我们可以自己模拟一个,就像上面的Object.createPro方法

 

2.关于constructor指向问题以及constructor的可枚举性

在第一个问题中,我们使用了Object.create方法实现了不同类之间的继承,然而这样做的话却存在一个问题,如下:

function A(){
 this.name="李可可";
 this.age=21;
}
A.prototype.eat=function(){ console.log("I can eat") }
function B(){}
B.prototype=Object.create(A.prototype);

var cc=new B;
cc.constructor;//A  (这里我们期望的值是B,而实际上变成了A)

 那么如何解决上面的问题呢?

//我们最容易想到的是手动设置constructor属性,像下面这样
B.prototype.constructor=B;

 那么问题又来了,请看下面:

B.prototype.propertyIsEnumerable("constructor");//true (我们设置的constructor属性是可枚举的)

当然我们并不希望是这样,那怎么做呢?

//使用Object.defineProperty或Object.defineProperties方法设置constructor的enumerable为false
Object.defineProperty(B.prototype,"constructor",{
 value:B,
 enumerable:false//不可枚举
});
cc.constructor;//B
B.prototype.propertyIsEnumerable("constructor");//false

 有类似问题的还有使用对象字面量重写类的prototype的时候,就像下面这样

function C(){}
C.prototype={}
var pp=new C;
pp.constructor;//Object  (我们期望的是C)
C.prototype.constructor=C;
C.prototype.propertyIsEnumerable("constructor");//true (同样是可枚举的)
//这里也可以使用上面的方法解决

 当然,还有一种办法就是你不要去重写它,只需要往上面添加属性就行,像下面这样:

function D(){}
D.prototype.x=1;
var gg=new D;
gg.constructor; //D
D.prototype.propertyIsEnumerable("constructor");//false

 诸如此类问题在我的js笔记也有简要的描述(点此进入)

1
1
分享到:
评论

相关推荐

    【JavaScript源代码】JavaScript中的几种继承方法示例.docx

    原型链继承  原理: 子类原型指向父类实例对象实现原型共享,即Son.prototype = new Father()。 这里先简单介绍下原型 js中每个对象都有一个__proto__属性,这个属性指向的就是该对象的原型。js中每个函数都有一个...

    史上最为详细的javascript继承(推荐)

    为大家分享js中最常见最详细的继承方式,接下来将一下面的几个维度进行展示说明 文章有点长,请耐心阅读:beaming_face_with_smiling_eyes:,有什么错误理解的地方希望留言指出来 产生原因 代码实现 基本原理 ...

    javascript 中的继承实例详解

    javascript 中的继承实例详解 阅读目录 原型链继承 ...原型链继承实现的本质是重写原型对象,代之以一个新类型的实例。代码如下: function SuperType() { this.property = true; } SuperType.prototype.

    对于JS继承详细介绍( 原型链,构造函数,组合,原型式,寄生式,寄生组合,Class extends)

    说实在话,以前我只需要知道“寄生组合继承”是最好的,有个祖传代码...其中,原型链继承和原型式继承有一样的优缺点,构造函数继承与寄生式继承也相互对应。寄生组合继承基于Object.create, 同时优化了组合继承,成

    JavaScript原型和继承

    前几天看了《再谈js面向对象编程》...在了解原型链之前我们先来看看一个函数在创建过程中做了哪些事情,举一个空函数的例子:functionA(){};当我们在代码里面声明这么一个空函数,js解析的本质是(肤浅理解有待深入):

    JS原形与原型链深入详解

    但是其实这样的理解是片面的,下面通过本文来了解原型与原型链的细节,再顺便谈谈继承的几种方式。 原型 在讲到原型之前,我们先来回顾一下JS中的对象。在JS中,万物皆对象,就像字符串、数值、布尔、数组等。ECMA-...

    javascript的几种继承方法介绍

    1.原型链继承:构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。确认原型和实例之间的关系用instanceof。 原型链继承...

    JavaScript继承模式粗探

    Javascript原型继承是一个被说烂掉了的话题,但是自己对于这个问题一直没有彻底理解,今天花了点时间又看了一遍《Javascript模式》中关于原型实现继承的几种方法,下面来谈谈JS中比较简单的继承方法,如果大家有不同...

    JavaScript中的几种继承方法示例

    1.原型链继承 原理: 子类原型指向父类实例对象实现原型共享,即Son.prototype = new Father()。 这里先简单介绍下原型 js中每个对象都有一个__proto__属性,这个属性指向的就是该对象的原型。js中每个函数都有一个...

    JS 类的创建继承 与 new原理实现

    原型链继承 构造继承 实例继承 拷贝继承 组合继承 寄生组合继承 3. new 的原理实现 学习和参考于: JS定义类的六种方式详解 JS实现继承的几种方式 JavaScript深入之创建对象的多种方式以及优缺点 js new一个对象的...

    JavaScript 继承详解及示例代码

    几个月前,抱着《JavaScript 高级程序设计(第三版)》,啃完创建对象,就开始啃起了 继承 ,然而啃完 原型链 就实在是看不下去了,脑子越来越乱,然后就把它扔一边了,继续看后面的。现在利用这个暑假搞懂了这个...

    JavaScript继承学习笔记【新手必看】

    原型链继承 function Person() { //被继承的函数叫做超类型(父类,基类) this.name='mumu'; this.age='18'; } Person.prototype.name='susu';//当属性名相同时需就近原则,先在实例里面查找,没找到再到原型...

    戏说JS中的原型-Prototype

    javascript没有继承这个还是比较蛋疼的地方,你说要是有一个类有几个相同的属性,但是我们又不能够去继承他,这个太痛苦了?如果出现这个问题了我们能够怎么办啊,想想还是比较蛋疼的。。。。啊啊啊啊 啊,不能这么...

    JavaScript 继承使用分析

    深入学习javascript继承之前,先了解下面的几个概念: 父类:被继承的类 子类:由继承得来的类 超类:也就是父类 抽象类:一般不用来实例化的类,它的用途是用来给其他类继承. 基类:提供给其他类可以继承的类 派生类:由基类...

    前端Javascript相关面试基础问答整理md

    9. 原型和原型链 10. prototype与__proto__的关系与区别 11. 继承的实现方式及比较 12. 深拷贝与浅拷贝 13. 防抖和节流 14. 作用域和作用域链、执行期上下文 15. DOM常见的操作方式 16. Array.sort()方法与实现机制 ...

    javascript闭包详解中文word版

    Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包 对于那些使用传统静态语言C/C 的程序员来说是一个新的语言特性。本文将以例子入手来介绍Javascript闭包的语言特性,并结合...

    理解JavaScript的prototype属性

    其实,关于prototype只要几句话就可以总结: 任何原型都是对象,只有对象有原型 只有Function有prototype属性,它是这个Function作为构造器时生成对象所继承的原型。Function的原型和它的prototype属性无关 对象的...

Global site tag (gtag.js) - Google Analytics