关于原型链,__proto__和prototype,继承

ES6关于构造函数和继承有了新的语法,但先分析之前的写法,有助于理解原理

1.原型链

javascript没有像Java、C#类的概念,要实现继承只能是通过“原型(prototype)”这条链子将要继承的对象链接起来

//对象
var o={}
o.__proto__===Object.prototype//true
//数组
var arr=[1,2]
arr.__proto__===Array.prototype //true
Array.prototype.__proto__===Object.prototype //true
Object.prototype.__proto__===null //true
//函数
function f(){}
f.__proto__===Function.prototype//true
Function.prototype.__proto__===Object.prototype//true

说实话一直困惑__proto__prototype这俩啥关系,通过上面的代码就再清晰不过了__proto__指向了所继承的父原型,prototype指向自己的原型,所以通过修改__proto__可以改变所继承的原型,但__proto__ 并不是语言本身的特性,这是各大厂商具体实现时添加的私有属性,虽然目前很多现代浏览器的 JS 引擎中都提供了这个私有属性,但依旧不建议在生产中使用该属性,避免对环境产生依赖。生产环境中,我们可以使用 Object.getPrototypeOf方法来获取实例对象的原型,然后再来为原型添加方法/属性。

2.构造函数

function Person(name,age){
  this.name=name
  this.age=age
  this.sayName=function(){
    alert(this.name)
  }
}
Person.prototype.constructor===Person//true

以上是个构造函数,我一直觉得就是个函数,但其实它返回的是个对象,用new关键字构造一个对象。并且在自己的prototype上将constructor属性指向了自己

var person1=new Person('张三',27)
var person2=new Person('李四',18)
person1.constructor===Person//true
person1.__proto__===Person.prototype//true
person2.__proto__===Person.prototype//true
person1.sayName===person2.sayName//false 这不是我们想要的

每个实例的属性需要不一样,因为每个人的名字不一样,但是sayName需要共用,可以把需要共用的属性或方法放在prototype上,

Person.prototype.sayName2=function(){
  alert(this.name)
}
person1.sayName2===person2.sayName2//true

现在Person上其实有2个属性,一个是默认生成的constructor,另一个是sayName2,所以又可以用以下的写法解释

Person.prototype={
  constructor:Person,
  sayName2:function(){
    alert(this.name)
  }
}

接下来对比以下ES6的新语法class

class Person{
  constructor(name,age){//放在构造器里面的是 不公用的
    this.name=name
    this.age=age
    this.sayName=function(){
      alert(this.name)
    }
  }
 //放在构造器外面的是公用的
  sayName2(){
    alert(this.name)
  }
}

咋样,就感觉是把之前的写法合并起来了

3.继承

//父构造函数
function SuperType(name){
  this.name=name
}
SuperType.prototype.sayName=function(){
  alert(this.name)
}
//子构造函数
function SubType(name,age){
  SuperType.call(this,name)
  this.age=age
}
var sub=new SubType('张三',12)
sub.name//"张三"
sub.sayName//undefined
sub.__proto__===SubType.prototype//true
SubType.prototype.__proto__===SuperType.prototype//false

先用call方法继承构造器里的属性,此时的关系为,sub——>SubType——>Object,要实现继承要把SubType.prototype.__proto__===SuperType.prototype 你可能想这么写 SubType.prototype = SuperType.prototype,但这样是不行的,他们俩公用一个原型的话,SubType就没有存在的意义了,我们可以用下面的代码

function F(){}//先创建了一个临时性的构造函数
F.prototype = SuperType.prototype;//将父原型作为临时构造函数的原型
var prototype=new F()//这边也可以直接用new SuperType(),但这样加上上面的call方法会导致2次调用SuperType
prototype.contructor=SubType
SubType.prototype=prototype//然后将临时构造函数的实例作为子构造函数的原型
SubType.prototype.__proto__===SuperType.prototype//true

下面来看看ES6继承的写法

class SuperType{
  constructor(name){
    this.name=name
  }
  sayName(){
    alert(this.name)
  }
}
class SubType extends SuperType{
  constructor(name,age){
    super(name)//必须调用下父类
    this.age=age
  }
  sayAge(){
    alert(this.age)
  }
}
var sub=new SubType('张三',12)
sub.__proto__===SubType.prototype//true
SubType.prototype.__proto__===SuperType.prototype//true

注意这边会多一个联系,这个是ES6特有的

SubType.__proto__===SuperType//true

这样的结果是因为,类的继承是按照下面的模式实现的。

class SuperType {
}
class SubType {
}
// B 的实例继承 A 的实例  B.prototype.__proto__=A.prototype
Object.setPrototypeOf(SubType.prototype, SuperType.prototype);
// B 继承 A 的静态属性  B.__proto__=A
Object.setPrototypeOf(SubType , SuperType );

这两条继承链,可以这样理解:作为一个对象,子类(SubType)的原型(__proto__属性)是父类(SuperType);作为一个构造函数,子类(SubType)的原型对象(prototype属性)是父类的原型对象(prototype属性)的实例。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354