手撕js中的继承(一)

知识铺垫

构造函数

构造函数是用来批量创建对象的函数,本质上也是函数,区别于其他函数的方式就是调用的方式。
简单点说:如果没有使用new来调用的,就是普通函数。如果使用了new来调用的,就是构造函数。
话不多说直接上代码康康:

function Person(uname, age){
  this.uname = uname;
  this.age = age;
}
let IronMan = new Person('Tony stark', 30);
Person('Tony stark', 40);

console.log(IronMan);
console.log(uname);
console.log(age);

打印结果如下:

let IronMan = new Person('Tony stark', 30);中,通过new调用了函数Person,并且生成了IronMan,这里的Person就成了构造函数,IronMan就成了Person的一个实例。

原型对象

当我们每次创建一个函数的时候,函数对象都会有一个prototype属性,这个属性是一个指针,指向它的原型对象原型对象的本质也是一个对象。看代码:

function Person(uname, age){
  this.uname = uname;
  this.age = age;
}
console.log(Person.prototype);

打印如下:

我们可以看到Person.prototype指向一个对象,就是Person的原型对象,在这个原型对象中有一个constructor属性又指向了Person构造函数。

构造函数,原型对象和实例的关系

直接上图!

从上图可以看到:

  • 函数对象prototype指向原型对象,原型对象的constructor指向函数对象。
  • 实例对象的__proto__指向原型对象,__proto__的作用是允许实例通过该属性访问原型对象中的属性和方法
function Person(uname, age) {
  this.uname = uname;
  this.age = age;
}
Person.prototype.sex = 'man';
let IronMan = new Person('Tony stark', 28);
let BlackWidow = new Person('Natalia', 24);
BlackWidow.sex = 'woman'
console.log(IronMan.sex);
console.log(BlackWidow.sex);

打印结果如下:

可以看出,我们并没有给IronMan实例设置sex属性,但因为__proto__会访问原型对象中对应的属性,所以输出man;同时,我们给BlackWidow设置sex属性后输出的是woman,两者比较说明实例本身不存在对应的属性和方法时,才会去原型对象上查找对应的属性和方法
补充:在这里我们打印一下这句话:

console.log(IronMan.constructor);

打印结果:

通过实例的constructor可以访问构造函数,但是constructor本质上却是原型对象的属性而不是实例对象的,是实例对象通过__proto__找到原型对象prototype然后通过原型对象的constructor指回的构造函数。如果难以理解,我们不妨打印一下IronMan这个实例:
看,实例对象IronMan上并没有constructor属性,而是通过__proto__找到了原型对象,原型对象上拥有constructor属性并且指向了Person构造函数。

继承

原型链

在js中继承的主要思路就是利用了原型链。
原型链的原理是:让一个引用类型继承另一个引用类型的属性和方法。
既然我们知道了原型对象通过constructor指向构造函数,实例通过__proto__指向原型对象,那我们不妨想一想:如果让原型对象等于另一个构造函数的实例会怎么样?

function Father() {

}
Father.prototype.sayF = function () {
  console.log('from Father');
}

function Son() {

}
Son.prototype = new Father();
Son.prototype.sayS = function () {
  console.log('from Son');
}

let father = new Father();
let son = new Son();

son.sayS();
son.sayF();

结果:

上面过程发生了什么呢?我们再画一张图:
  • 首先我们创建了Father和Son两个函数对象,同时也就生成了他们的原型对象。
  • 接着我们给Father的原型对象添加了sayF()方法
  • Son.prototype = new Father(),这一步我们让函数对象Son的prototype指针指向了Father的实例,这也就是为什么Son原型对象里面不再有constructor属性,其实Son本来有一个真正的原型对象可以通过Son.prototype访问,结果我们手动修改了这个指针的指向,所以Son真正的原型对象现在没有办法被访问了,取而代之的是Father的一个实例,所以没有constructor这个属性。(把之前的例子带进来看,其实father这个实例通过__proto__可以访问到Father的原型对象,Father的原型对象上是有constructor这个属性的,所以我们通过打印Son.prototype.constructor,还是可以打印出结果,只不过这个结果却是Father这个构造函数,我们在写的时候通常还需要手动为Son.prototype添加constructor属性将它指回Son构造函数:Son.prototype.constructor = Son;)
  • 我们给Son.prototype指向的对象,增加一个sayS方法
  • 生成一个实例son,调用了son的sayS方法,可以执行:这是因为,son.__proto__可以访问到Son原型对象上的方法。
  • 调用了son的sayF方法,也可以执行:这是因为,son沿着__proto__属性,可以访问Son的原型对象,这时并没有sayF这个方法,Son的原型对象继续沿着__proto__属性访问Father的原型对象,最终在Father.prototype上找到了sayF方法。
    所以现在就相当于son继承了Father的属性和方法,这种由__proto__不断把实例和原型对象联系起来的结构其实就是原型链。这也是es6之前继承的主要方式。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 原型链的缺陷 1.引用类型的值在原型链传递中存在的问题js中有简单数据类型和引用数据类型(复杂数据类型),引用类型...
    火星的天秤座阅读 214评论 0 1
  • 大纲:原型链借用构造函数组合继承原型式继承寄生式继承寄生组合式继承 1、原型链: 什么是原型链? 原型链的基本思想...
    葵自渡_阅读 377评论 0 0
  • 继承6种套餐 参照红皮书,JS继承一共6种 1.原型链继承 核心思想:子类的原型指向父类的一个实例 Son.pro...
    灯不梨喵阅读 3,113评论 1 2
  •   有了实体,为了简化定义,自然就有了继承的概念,比如已经定义了一个“人”类,后面需要详细分出“男人”和“女人”,...
    E微客阅读 349评论 0 1
  • 回想起刚入门JS的时候,初次接触JS原型继承,令我头大,心想啊,为什么要把继承搞得这么复杂。随着时间推移,学习源码...
    forJavascript阅读 374评论 2 1