资讯专栏INFORMATION COLUMN

关于构造函数、原型、原型链、多种方式继承

zxhaaa / 1359人阅读

摘要:可以看出这个构造函数是由创建出来的,而我们看下的隐式原型,竟然是指向了的原型,也就是也是由创建出来的。例如,其他构造函数的原型将覆盖属性并提供自己的方法。将构造函数的执行对象赋给这个空对象并且执行。把对象的隐式原型指向构造函数的原型。

构造函数与实例对象

又是这个经典的问题,嗯,我先来写个构造函数,然后实例化一个对象看看。

function Person(name) {
  this.name = name
}
Person.prototype.eat = () => {console.log("eat")}
Person.prototype.play = () => {console.log("play")}
let Han = new Person("Han")

通过一系列打印发现了这样的关系:

原型链 -- 原型(prototype)和隐式原型(__proto__)

可以看出实例对象没有prototype(也就是原型),只有构造器才拥有原型。而所有的js对象都拥有__proto__(也就是隐式原型),这个隐式原型所指向的就是创造这个对象的构造器的原型。如实例Han的隐式原型指向了其构造函数(Person)的原型;Person的隐式原型指向了Function的原型;而原型自身也有隐式原型,指向了Object的原型。

有点绕口,其实就是通过隐式原型可以向上找到是谁构造了自己,并且如果自己没有相应的属性或者方法,可以沿着这条原型链向上找到最近的一个属性或方法来调用。如Han.eat(),实际上是调用了Han.__proto__.eat(),把构造器Person的原型的eat方法给拿来用了;再如Han.hasOwnProperty("name"),实际上是调用了Han.__proto__.__proto__.hasOwnProperty("name"),因为Han自己没hasOwnProperty这方法,就通过隐式原型向上找到了Person的原型,发现也没这方法,就只能再沿着Person的原型的隐式原型向上找到了Object的原型,嗯然后发现有这方法就拿来调用了。

构造器constructor

所有构造函数都有自己的原型(prototype),而原型一定有constructor这么个属性,指向构造函数本身。也就是告诉大家这个原型是属于本构造函数的。

Function & Object

可以看出Person这个构造函数是由Function创建出来的,而我们看下Function的隐式原型,竟然是指向了Function的原型,也就是Function也是由Function创建出来的。很绕是不是,我们先不管,继续溯源下去,再看下Function的原型的隐式原型,指向的是Object的原型,继续往上找Object的原型的隐式原型,嗯终于结束了找到的是null,也就是Object的原型是原型链上的最后一个元素了。

接下来看下Object,Object是由Function创建出来的,而Function的隐式原型的隐式原型是Object的原型也就是Function通过原型链可以向上找到Object的原型,两者看起来是你生我我生你的关系,这里也就引用比较好懂的文章来解释下: 从Object和Function说说JS的原型链

Object
JavaScript中的所有对象都来自Object;所有对象从Object.prototype继承方法和属性,尽管它们可能被覆盖。例如,其他构造函数的原型将覆盖constructor属性并提供自己的toString()方法。Object原型对象的更改将传播到所有对象,除非受到这些更改的属性和方法将沿原型链进一步覆盖。

Function
Function 构造函数 创建一个新的Function对象。 在 JavaScript 中, 每个函数实际上都是一个Function对象。

---- 来自mozilla

接下来说下构造函数实例化对象到底做了些啥,其实看也能看出来了。

let Jan = {}
Person.call(Jan, "Jan")
Jan.__proto__ = Person.prototype

1、创建一个空对象。
2、将构造函数的执行对象this赋给这个空对象并且执行。
3、把对象的隐式原型指向构造函数的原型。
4、返回这个对象

是的就是这样,next page!

继承 原型链继承
function Person(name) {
  this.name = name
  this.skills = ["eat", "sleep"]
}
Person.prototype.say = ()=> {console.log("hi")}

function Boss() {}
Boss.prototype = new Person()
let Han = new Boss()

原理就是这样

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102575.html

相关文章

  • Javascript 五十问——实现的继承多种方式

    摘要:组合继承实现了属性分离,方法共享下的完美继承方案继承我们的主角,,就是对组合继承的改进。这也是为什么在子类构造函数中一定要显示调用的原因。 谈到继承,或者更广义上的:一个对象可以使用另外一个对象的属性或方法。实现起来无外乎有两种方式:apply or call 改变this的作用域原型继承 改变__proto__指向,添加作用域链 而JavaScript所有的继承实现,都是围绕以上两点...

    BlackHole1 评论0 收藏0
  • Javascript面向对象从入门到重新入门--关于继承

    摘要:这个构造函数的不管从调用方式还是内部写法就都很有的感觉,但是从用途上来说,它其实更靠近的概念是中的工厂方法。到这里,所有关于继承的东西讲完了,接下来准备准备说说当中的封装 所谓的对象,就是抽象化的数据本身 一个面向对象转向面向原型的困惑 我发现Javascript这门语言每次翻开都会带给人新感受,尤其是看完其他语言的面向对象再来看它,但是如果你也是过来人就一定记得教科书里面冗长乏味的...

    3fuyu 评论0 收藏0
  • JavaScript深入之继承多种方式和优缺点

    摘要:深入系列第十五篇,讲解各种继承方式和优缺点。优点融合原型链继承和构造函数的优点,是中最常用的继承模式。寄生组合式继承为了方便大家阅读,在这里重复一下组合继承的代码组合继承最大的缺点是会调用两次父构造函数。 JavaScript深入系列第十五篇,讲解JavaScript各种继承方式和优缺点。 写在前面 本文讲解JavaScript各种继承方式和优缺点。 但是注意: 这篇文章更像是笔记,哎...

    JackJiang 评论0 收藏0
  • 读《javaScript高级程序设计-第6章》之继承

    摘要:此时的原型对象包括一个指向另一个原型的指针,相应的,另一个原型中的指向另一个构造函数。这种关系层层递进,就通过一个原型对象链接另一个构造函数的原型对象的方式实现了继承。 读这篇之前,最好是已读过我前面的关于对象的理解和封装类的笔记。第6章我一共写了3篇总结,下面是相关链接:读《javaScript高级程序设计-第6章》之理解对象读《javaScript高级程序设计-第6章》之封装类 一...

    villainhr 评论0 收藏0
  • javascript继承 --- 多种继承方式解析(ES5)

    摘要:继承前言作为一门轻量级的脚本语言在和的横空出世之后将其推向的新的高度虽然中出现的新的生成对象的类语法格式但依然为的语法糖而我们依然有必要从的原生实现入手来了解它的继承实现方式给出了更加简洁的固定的类声明方式有兴趣的可以查看阮一峰的入门下面给 javascript继承 前言 javascript作为一门轻量级的脚本语言在ES6和node.js的横空出世之后将其推向的新的高度,虽然 ES6...

    yankeys 评论0 收藏0

发表评论

0条评论

zxhaaa

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<