原型

前言

继承是面向对象编程中相当重要的一个概念,它对帮助代码复用起到了很大的作用。

正文

Brendan Eich在创建JavaScript时,没有选择当时最流行的类继承机制,而是借鉴Self,用到了基于原型(prototype)的继承机制,这导致了JavaScript在继承机制方面与Java、C++等基于类继承机制的语言有着显著的区别。

其具体在于—C++的多重继承、Java的继承和接口实现中都包含""的概念,它们倾向于在创建对象之前[1]已经规定了对象需要继承的类和实现的接口,并且使用类与类之间的继承方式

而在JavaScript中没有""的概念,在对象之后所继承的对象也是可以发生动态变化的,并且使用的是对象与对象之间的继承方式

如果将JavaScript中由string,number,bigint,boolean,null,undefined,symbol组成的基础类型与其对应的值都按下不表,余下的引用类型与其对应的值将都存在着__proto__[2]属性,指向继承的原型对象[3]

与__proto__存在于每个对象中不同,prototype属性只存在于函数中,在默认的的情况下所有对象的__proto__属性的值与其构造函数下的prototype属性的值是一致的。

let obj = new Object();
obj.constructor === Object;//true
//obj的__proto__属性的值与obj的构造函数的prototype属性的值指向同一块堆内存
obj.__proto__ === obj.constructor.prototype;//true
obj.__proto__ === Object.prototype;//true

所有函数的构造函数都指向Function:

Object.constructor === Function;//true
//Object的__proto__属性的值与Object的构造函数的prototype属性的值指向同一块堆内存
Object.__proto__ === Object.constructor.prototype;//true
Object.__proto__ === Function.prototype;//true Function.constructor === Function;//true
//Function的__proto__属性的值与Function的构造函数的prototype属性的值指向同一块堆内存
Function.__proto__ === Function.constructor.prototype;//true
Function.__proto__ === Function.prototype;//true

Function的prototype属性的原型指向Object.prototype:

Object.prototype === Function.prototype.__proto__;//true

不单单是 Function 的prototype属性的原型指向 Object.prototype ,几乎所有的函数[4]的prototype属性的原型指向 Object.prototype ,从V8的测试代码中可见一斑:



最后,位于原型顶点的是Object.prototype.__proto__,它指向 null:

Object.prototype.__proto__ === null;//true
Object.prototype.constructor === Object;//true

根据以上逻辑画的原型指向图:



为了加深理解,我将再定义一个构造函数:

function Person(){

}
Person.constructor === Function;//true
Person.__proto__ === Person.constructor.prototype;//true
Person.__proto__ === Function.prototype;//true



通过新定义的构造函数创建对象:

let person = new Person();
person.constructor === Person;//true
person.__proto__ === person.constructor.prototype;//true
person.__proto__ === Person.prototype;//true



根据以上逻辑画的最终的原型指向图:

结尾

了解JavaScript中基于原型(prototype)的继承机制的重点在于捋清楚Object与Function的__proto__、constructor、prototype属性的指向关系,再进一步了解Object和Function各自对应的值以及通过Function对应的值创建出来的对象的__proto__、constructor、prototype属性的指向关系,就大功告成了。

听起来可能有一点点绕,最好是动手画一下图,以后忘记的时候看一下自己画的图就又想起来了。

最后,本人才疏学浅,如有错误之处,还望各位不理赐教。


  1. 这里的措辞最初为程序运行之前,后联想到hotswap,特意改为对象创建后。

  2. 虽然__proto__已经被不推荐使用,但是为了更直观,我在此文中获取对象原型的方法都将通过对象的__proto__属性,还望悉知。

  3. Object.prototype继承的原型指向null。

  4. bind、apply和call没有prototype属性。

深入了解JavaScript中基于原型(prototype)的继承机制的更多相关文章

  1. JavaScript中的原型prototype和__proto__的区别及原型链概念

    问题 初学js的同学,总是搞不清楚js中的原型是什么东西,看着控制台打印出来的一串串__proto__,迷惑不已. 例如我定义一个Person,创建一个实例p,并打印实例. function Pers ...

  2. JavaScript中的原型链和继承

    理解原型链 在 JavaScript 的世界中,函数是一等公民. 上面这句话在很多地方都看到过.用我自己的话来理解就是:函数既当爹又当妈."当爹"是因为我们用函数去处理各种&quo ...

  3. JavaScript之基于原型链的继承

    本文介绍下js的OOP中的继承. 上图的要点为:Foo函数在创建时会自动生成内置属性prototype,而typeof Foo.prototype是object类型的. 上图的要点为:Foo.prot ...

  4. 【转】JavaScript中的原型和继承

    请在此暂时忘记之前学到的面向对象的一切知识.这里只需要考虑赛车的情况.是的,就是赛车. 最近我正在观看 24 Hours of Le Mans ,这是法国流行的一项赛事.最快的车被称为 Le Mans ...

  5. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

  6. javascript中的原型继承

    在Javascript面向对象编程中,原型继承不仅是一个重点也是一个不容易掌握的点.在本文中,我们将对Javascript中的原型继承进行一些探索. 基本形式 我们先来看下面一段代码: <cod ...

  7. 图解JavaScript中的原型链

    转自:http://www.jianshu.com/p/a81692ad5b5d typeof obj 和 obj instanceof Type 在JavaScript中,我们经常用typeof o ...

  8. 前端知识体系:JavaScript基础-原型和原型链-理解原型设计模式以及 JavaScript中的原型规则

    理解原型设计模式以及 JavaScript中的原型规则(原文地址) 1.原型对象:我们创建的每一个函数(JavaScript中函数也是一个对象)都有一个原型属性 prototype,原型属性实质上是一 ...

  9. JavaScript中的原型、原型链、原型模式

    今天,咱来聊聊JavaScript中的原型跟原型链 原型跟原型模式 这一块的知识,主要是设计模式方面的. 首先,我们知道JavaScript是面向对象的.既然是面向对象,那它自然也有相应的类跟对象等概 ...

随机推荐

  1. MAC与ARP缓存中毒介绍

    ARP 协议 用于地址解析,请求MAC地址. arp -a 或者 -n 查看ARP缓存表 ls(ARP) 查看scapy里的协议字段 ARP缓存中毒原理 ARP收到ARP请求报文,会将发送方的mac地 ...

  2. 风炫安全WEB安全学习第二十二节课 DOM型XSS讲解

    风炫安全WEB安全学习第二十二节课 DOM型XSS讲解 Dom型XSS演示 通过Javascript,可以重构整个HTML文档,你可以添加.移除.改变或重排页面上的项目 要改变页面的某个东西,Java ...

  3. 剑指offer 面试题10.2:青蛙变态跳台阶

    题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级--它也可以跳上n级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 编程思想 因为n级台阶,第一步有n种跳法:跳1级.跳2级.到跳n级跳1级,剩下 ...

  4. 基于 MapReduce 的单词计数(Word Count)的实现

    完整代码: // 导入必要的包 import java.io.IOException; import java.util.StringTokenizer; import org.apache.hado ...

  5. H5手机网页元素识别

  6. 有了链路日志增强,排查Bug小意思啦!

    在工作中,相信大家最怕的一件事就是听到有人在工作群艾特你:某某功能报错啦... 然后你就得屁颠屁颠的去服务器看日志,日志量少还好点,多的话找起来太麻烦了.不太容易直接定位到关键地方. 东找找西找找,好 ...

  7. 【Linux】 多个会话同时执行命令后history记录不全的解决方案

    基本认识 linux默认配置是当打开一个shell终端后,执行的所有命令均不会写入到~/.bash_history文件中,只有当前用户退出后才会写入,这期间发生的所有命令其它终端是感知不到的. 问题场 ...

  8. 【MYSQL】MySQL5.6.37二进制安装

    最近有个项目要用到mysql 于是在mysql的论坛中找到了一个5.6.37版本的 下面介绍怎么安装和使用mysql 下载地址: https://dev.mysql.com/downloads/mys ...

  9. ctfhub技能树—文件上传—双写后缀

    双写后缀绕过 用于只将文件后缀名,例如"php"字符串过滤的场合: 例如:上传时将Burpsuite截获的数据包中文件名[evil.php]改为[evil.pphphp],那么过滤 ...

  10. ctfshow—web—web5

    打开靶机,代码审计 附上代码 <?php error_reporting(0); ?> <html lang="zh-CN"> <head> & ...