首先,此文是对于javascript原型链的一些私人见解,若能博君会心一笑,在下荣幸之至!

  为了阐述我的理解,首先提前声明一些前置知识,欢迎指正:

栈内存和堆内存:

  栈内存每个地址分配的地址长度较窄,且长度固定,用于检索和快速遍历,一般存着值类型数据,如string,number,booleen,null。

  堆内存的每个地址分配的地址长度是弹性变化的,用于存储具有一定结构的数据,如函数对象function,实例对象object等,为了提高检索效率,所有堆内存里对象的存储地址都记录在栈内存内,这样通过栈内存遍历就可以快速定位堆内存内的目标。

  在原型链里,常有这种情况:多个栈内存地址__proto__指向另一个栈内存地址prototype,而prototype指向堆内存内某一对象地址。

重点1 -> prototype和__proto__(隐式属性):

  对象分为函数对象和实例对象,函数对象又分为构造函数对象和普通函数对象。

  首先所有对象都具有__proto__属性,而特别地,函数对象内一定有prototype属性,打印任何对象时浏览器内默认不显示隐式属性,

  所有函数都有prototype这一属性对象(原型),且存在constructor属性存储自身堆内存所在地址,即存在隐式属性prototype:{constructor:f}。

重点2 -> 自有属性和继承属性(显式属性和隐式属性):

  var a = {}

  console.log( a.b )  // undefined

  a.__proto__ = { b:'b' }

  console.log( a.b )  // b

  函数对象一般有两个隐式属性,prototype指向自己的原型对象,__proto__一般会指向另一个函数对象的原型对象。

  从第三行代码看出对象的隐式属性是可以随意修改的,这也是javascript的一大特点,第四行代码实际上查找的是a.__proto__.b,浏览器隐藏了这一过程。

    访问函数的属性时,存在一个两遍查找的过程,第一遍查找自有属性,如果自有属性没有去继承属性__proto__里查找,__proto__会指向另一个函数对象的原型,在此原型里找同名属性,那如果没有找到怎么办呢?

  我们上文说过,函数对象有两个隐式属性,既然自己的prototype指向的这个原型对象里没有它需要找的同名属性,就会通过自己的另一个隐式属性__proto__再指向其构造函数的prototype,再到prototype指向的原型对象里去查找,由此形成原型链,事实上,原型链在进入到最后一环之前一直是以这样一种简单的规则勾连的。

重点3 -> 继承本质:

  var a = function () {} // #不一定要是构造函数

  var b = new a();

  console.log( b.__proto__ === a.prototype ) // true #类型和存储的地址都相同

  所有被函数构造出来的实例对象,其隐式属性__proto__指向其构造函数的隐式属性prototype。

  如果一个构造函数构造了许多实例对象,它们所有的__proto__相当于前文提到的栈内存入口,指向同一个构造函数的prototye,而构造函数的prototype是第一个指向其原型对象的栈内存入口,一般也可以将prototype说成原型对象,当然本质是其指向堆内存里的对象地址。

  堆内存里的原型对象所具有的属性和方法,javascript通过一些底层方法使得实例对象省略.__proto__的形式直接访问,且__proto__一旦找到对应的属性或方法就返回结果,不再往上寻找更高一级的原型对象,这就是继承的本质。

顶级构造函数Object 和 Function:

  Function.prototype.hasOwnProperty = function () { return 'Function prototype' } // #Object的原型里有内嵌hasOwnProperty方法

  function f () { this.x = 1 }

  f.x = 1

  var obj = new f()

  console.log( f.hasOwnProperty( 'x' ))  // Function prototype

  console.log(obj.hasOwnProperty( 'x' )) // true

  console.log( Object.hasOwnProperty( 'x' )) // Function prototype

  console.log( Object.__proto__ === Object.prototype ) // false

  console.log( Object.__proto__ === Function.prototype ) //  # Object将会继承Function的原型!

  console.log( Function.prototype === Function.__proto__ ) // true  #这意味着Function会自己继承自己的原型!

  console.log( Function.hasOwnProperty( 'x' )) // Function prototype

  上文说到如果自己的原型对象里没有要查找的同名属性,则通过另一个隐式属性__proto__再指向另一个函数的prototype,如此循环往复,最后都会到达两个顶级的构造函数,此时顶级函数Object的隐式属性__proto__将会找到Function的原型对象,令人惊讶的是Function的__proto__指向自身的prototye,这就意味着Function会继承自己的原型对象!

  对于所有实例对象和衍生函数而言,Object和Function是原型链的终点,它们两之间的继承关系显得特别混乱,如果按原型链的规则来制定最后一级的继承关系,势必引起所有函数和对象逻辑上的混乱。

  事实上,为了让函数具备对象的特性,在逻辑上是不可能有一套通用的规则的。

  我们假设javascript这种语言不再赋予函数对象的特性,那么原型链不仅会变得特别好理解,而且层次分明。

  Object和Function两个构造函数可以各司其职,各不相关,一个负责构造对象,一个负责构造函数,多么美妙而有序。所有对象的顶级原型都是Object.prototype,所有函数的顶级原型都是Function.prototype,然而javascript作为一门混沌而具有无穷潜力的语言,善于搜刮各种其他语言的优势填补自身的短板,而其他热门语言所具有的一大杀器便是继承的特性,对象和继承使javascript衍生出另一项绝活------构造函数。

  构造函数使得构造对象不再是Object函数的专利,但这也引申出另一个问题,那就是原型链的顶级原型和下一级原型之间需要谨慎应对(毕竟使用隐式属性模仿继承总有漏洞,需要一些手段来矫正规则),于是函数和实例对象的原型链在进入到最后一级的原型后,javascript在底层对它们添加了‘新的继承规则’。

  这些添加的规则使得所有实例对象和函数的继承特性在最后一级也表现得富有逻辑,比如一个实例对象,它既然不是函数,就不应该继承任何Function的原型属性和方法,因而Function的原型不会对任何实例对象造成干扰。

  一个函数,它若即是函数又是对象,在面向对象编程思想盛行的时代,就有继承Object所有方法和属性的权利,于是在函数的顶级原型Function.prototype上又加了一层Object.protype这一原型。

  Javascript通过隐式属性和在最后一级‘新的继承规则’成功复制了继承这一经典模式,除此之外,为了填补自身短板,适应各类编程思想,Javascript还发展出许多新的特性。

  比如摆脱弥补饱受诟病的弱类型特点,Javascript发展出strict模式下的编程,增加了许多报警机制,甚至衍生出一门新的语言Typescript。为了向Java等强类型语言致敬,发展出访问器属性,这一机制也是前端框架的核心原理之一.。

  最后,希望你我都能在Javascript语言中找到编程的乐趣,以上拙见,转载请注明出处。。

  

  

从原型链探究Javascript这么火的原因的更多相关文章

  1. JavaScript学习总结(四)——this、原型链、javascript面向对象

    一.this 在JavaScript中this表示:谁调用当前函数this就指向谁,不知道调用者时this指向window. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是 ...

  2. js原型与原型链探究

    原型有一个非常重要的属性叫 prototype 一.先写一个简单的例子,看看 A的原型和A的实例 分别是什么 function A() {} var a = new A() console.log(a ...

  3. 前端知识体系:JavaScript基础-原型和原型链-理解JavaScript的执行上下文栈,可以应用堆栈信息快速定位问题

    理解JavaScript的执行上下文栈,可以应用堆栈信息快速定位问题(原文文档) 1.什么是执行上下文: 简而言之,执行上下文就是当前JavaScript代码被解析和执行时所在环境的抽象概念,Java ...

  4. 玩转JavaScript OOP[3]——彻底理解继承和原型链

    概述 上一篇我们介绍了通过构造函数和原型可以实现JavaScript中的“类”,由于构造函数和函数的原型都是对象,所以JavaScript的“类”本质上也是对象.这一篇我们将介绍JavaScript中 ...

  5. javascript继承--原型链的 继承

    作者的话:原型链是JavaScript中相当重要的一个知识点,这里我使用了函数结构图,来帮助我更好的理解 /* 原型链继承方式: 通过改变一个对象的原型对象的指向来继承另一个对象 原理: 我们知道,一 ...

  6. 《前端之路》之 JavaScript原型及原型链详解

    05:JS 原型链 在 JavaScript 的世界中,万物皆对象! 但是这各种各样的对象其实具体来划分的话就 2 种. 一种是 函数对象,剩下的就是 普通对象.其中 Function 和 Objec ...

  7. JavaScript中的原型链和继承

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

  8. Javascript之继承(原型链方式)

    1.原型链 原型链是JavaScript中继承的主要方法. 每个构造函数都拥有一个原型对象,原型对象都包含一个指向构造函数的指针(constructor),实例都包含一个指向原型对象的内部指针(__p ...

  9. 明白JavaScript原型链和JavaScrip继承

    原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: <script type="text/javascript"&g ...

随机推荐

  1. history program(language)

    1950与1960年代 有三个现代编程语言于1950年代被设计出来,这三者所衍生的语言直到今日仍旧广泛地被采用: Fortran (1955),名称取自"FORmula TRANslator ...

  2. maven安装与基本配置

    maven安装与基本配置 依赖:java环境,JDK安装 一. maven安装 (一)下载maven (二)安装与环境变量设置 (三)maven setting.xml配置 二. 创建maven项目 ...

  3. vBox Arch UEFI LVM安装

    Table of Contents 介绍 配置 基础 VirtualBox配置 安装准备 基础 分区 格式化 挂载 安装 选择镜像 安装基本系统 配置 fstab chroot 一些配置 lvm2 网 ...

  4. 2017年4月13日用VS写C程序遇到的一些问题

    在网上找到一篇展示计算机浮点数格式的文章,且有C代码如下: #include <stdio.h> #include <stdlib.h> #include <string ...

  5. Hello vue.js的随笔记录

    数据双向绑定的script在组件定义位置后面才顶用. 使用它的话,引用js就好,比较简单. 声明一个vm对象,new Vue({}).这个构造里传一个对象,包含el:界面元素,data:数据,meth ...

  6. xml的作用

    XML应用面主要分为两种类型,文档型和数据型.下面介绍一下几种常见的XML应用: 1.自定义XML+XSLT=>HTML,最常见的文档型应用之一.XML存放整个文档的XML数据,然后XSLT将X ...

  7. centos7 下 安装部署nginx

    centos7 下 安装部署nginx 1.nginx安装依赖于三个包,注意安装顺序 a.SSL功能需要openssl库,直接通过yum安装: #yum install openssl b.gzip模 ...

  8. java 秒时间格式化

    public static String durationFormat(Integer totalSeconds) { if (totalSeconds == null || totalSeconds ...

  9. MIME 参考手册

    本文摘自http://www.w3school.com.cn/media/media_mimeref.asp MIME (Multipurpose Internet Mail Extensions) ...

  10. 如何将Excel转换成Markdown表格[转]

    在这篇文章中,我将告诉你如何快速的将Excel转换为markdown表格,以及如何将Google Docs,Numbers,网页中的表格或其他类似Excel的程序数据转换为Markdown表格 你可能 ...