原生的原型链

function fn(){},fn 为 Function的一个实例,原型链为 null -> Object -> Function -> fn:

fn.__proto__ === Function.prototype

Function.prototype.__proto === Object.prototype

Object.prototype.__proto__ === null

原型链通过原型(prototype)链接,prototype 就是一个 只有(构造)函数才有的特殊的实例,包含了constructor指针(和__proto__,所有实例都有

之后new出来的普通实例(非prototype)都包含这个prototype(引用名为__proto__):console.log(sonA)   //  {/* 其他属性 */ __proto__: Son.prototype}

举例来说,对于函数实例,所有函数实例.__proto__ === Function.prototype (通过这个能拿到Function上的通用属性,如bind函数)

甚至Function.__proto__ === Function.prototype, Object.__proto__ === Function.prototype 

Function instanceof Object // true  Function.__proto__.__proto__ === Object.prototype (优先是更具体的函数,然后才作为更抽象的对象,对象永远在原型链较上层)

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

原型链继承:

未继承时

console.log(Son.prototype) // {  constructor: Son, __proto__: Object.prototype }

原型链继承了Father时,

console.log(Son.prototype)  // { __proto__: Father.prototype }父类的一个实例, 通过new Father 或者 Object.create(Father.prototype)生成

需要手动赋予constructor:

Object.defineProperty(Son.prototype, "constructor", {

  value: Son,

  writable: false

});

console.log(Object.prototype)

__proto__: null }

原型链继承,本质就是修改函数的prototype,使其从指向Function变为指向父类;父类的对象刚好符合这个特性

巩固一下上面的知识点,请判断以下比较是否为真:

Object.prototype.__proto__ === null

Object.__proto__ === Function.prototype

Function.__proto__ === Function.prototype

fn.__proto___ === Function.prototype

Object.prototype === Function.prototype.__proto__

Object.prototype === fn.prototype.__proto__

Object.prototype.isPrototypeOf(fn)

Object.prototype.isPrototypeOf(fn.prototype)

Function.prototype === fn.__proto__;

Function.prototype.isPrototypeOf(fn)

Function.prototype.isPrototypeOf(fn.prototype) // false

答案:以上判断若未特殊说明,结果都为真

谈一下new

var foo = new Foo();
实际是这样调用的
 
    var this = new Object(); //Note: this no longer point to global variable if called with new
    this.__proto__ = Foo.prototype;
    Foo.call(this);
    return this;
  或者
 var this = Object.create(Foo.prototype);
   Foo.call(this);
 return this;
 
其中object.create(p)的polyfill如下:
     function f(){}
     f.prototype = p;
     return new f();

自定义原型链:基于原型链的继承

Father() {} -> Son() {]

继承的本质是,如何使Son的实例能访问到Father定义的属性

通过原型链,我们将Son的原型指向Father

Son原型链现在是指向的Function,Son.__proto__ === Function.prototype

我们希望Son.__proto__ === Father.prototype

按es5之前的规范,我们不能直接访问__proto__,那么只能修改prototype (ES5中用Object.getPrototypeOf函数获得一个对象的[[prototype]]。ES6中,使用Object.setPrototypeOf可以直接修改一个对象的[[prototype]])

我们知道 Father的实例的__proto__指向Father.prototype,那么Son.prototype等于Father的实例就可以

Son.prototype = new Father()  或者

Son.prototype = Object.create(Father.prototype)

这里有一个问题,prototype的constructor属性应该指向构造函数,而这种写法的constructor通过原型链会找到Father,所以需要定义一下constructor

Object.defineProperty(Son.prototype, "constructor", {

  value: Son,

  writable: false

});

顺便了解一下原型链查找顺序

优先查找对象的,对象上没有则通过__proto__找prototype,还没找到,就找prototype.__proto__, 也就是父类的prototype

比如

对象objA查找hasOwnProperty 

objA -> Son.prototype -> Object.prototype -> Object.prototype.hasOwnProperty

函数funcA查找bind

funcA -> Function.prototype -> Function.prototype.bind

PS:对于 const fn = () => {} 这样的箭头函数,不属于原型链的范畴 可以参考 http://www.cnblogs.com/mengff/p/9656486.html

彻底搞懂js原型与原型链的更多相关文章

  1. 帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

    作为一名前端工程师,必须搞懂JS中的prototype.__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞 ...

  2. 彻底搞懂 JS 中 this 机制

    彻底搞懂 JS 中 this 机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.com/jasonGeng88/blog 目录 this 是什么 this 的四种绑定规 ...

  3. 让你彻底搞懂JS中复杂运算符==

    让你彻底搞懂JS中复杂运算符== 大家知道,==是JavaScript中比较复杂的一个运算符.它的运算规则奇怪,容易让人犯错,从而成为JavaScript中“最糟糕的特性”之一. 在仔细阅读了ECMA ...

  4. 一文搞懂 js 中的各种 for 循环的不同之处

    一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...

  5. 一文读懂JS中的原型和原型链(图解)

    讲原型的时候,我们应该先要记住以下几个要点,这几个要点是理解原型的关键: 1.所有的引用类型(数组.函数.对象)可以自由扩展属性(除null以外). 2.所有的引用类型都有一个’_ _ proto_ ...

  6. 彻底搞懂js __proto__ prototype constructor

    在开始之前,必须要知道的是:对象具有__proto__.constructor(函数也是对象固也具有以上)属性,而函数独有prototype 在博客园看到一张图分析到位很彻底,这里共享: 刚开始看这图 ...

  7. 一张图搞懂 Javascript 中的原型链、prototype、__proto__的关系 转载加自己的总结

    1. JavaScript内置对象 所谓的内置对象 指的是:JavaScript本身就自己有的对象 可以直接拿来就用.例如Array String 等等.JavaScript一共有12内置对象    ...

  8. Spirit带你彻底搞懂JS的6种继承方案

    JavaScript中实现继承的6种方案 01-原型链的继承方案 function Person(){ this.name="czx"; } function Student(){ ...

  9. 通过一张简单的图,让你彻底地搞懂JS的==运算

    大家知道,JavaScript中的==是一种比较复杂运算,它的运算规则很奇怪,很容易让人犯错,从而成为JavaScript中“最糟糕的特性”之一. 在仔细阅读ECMAScript规范的基础上,我画了一 ...

随机推荐

  1. tomcat部署项目

    提示:指定jdk版本  在bin路径下的setclasspath.bat文件添加 set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_201 set JRE_HO ...

  2. How to using Piwis Tester II code Porsche rear end electronics

    V18.100 Piwis Tester II Diagnostic Tool For Porsche With CF30 Laptop High Quality Top 7 Reasons to G ...

  3. zigbee组网函数的一些用法

    1.NLME_PermitJoiningRequest(0)  :(1)值0x00:表示禁止加入网络  (2)值0x01-0xFE:表示允许链接的秒数 (3) 值0xff:表示启用网络 同时此函数:是 ...

  4. 系统开机时提示BOOTMGR is compressed

    问题描述: 开机时提示 BOOTMGR  is compressed Press Ctrl+Alt+Del to restart 操作方法: 1.插入带有U盘启动的U盘2.进入winpe系统后,打开“ ...

  5. 深入理解泛型之JAVA泛型的继承和实现、泛型擦除

    很多的基础类设计会采用泛型模式,有些应用在使用的时候处于隔离考虑,会进行继承,此时子类如何继承泛型类就很讲究了,有些情况下需要类型擦除,有些情况下不需要类型擦除,但是大多数情况下,我们需要的是保留父类 ...

  6. 【题解】Luogu P4436 [HNOI/AHOI2018]游戏

    原题传送门 \(n^2\)过百万在HNOI/AHOI2018中真的成功了qwqwq 先将没门分格的地方连起来,枚举每一个块,看向左向右最多能走多远,最坏复杂度\(O(n^2)\),但出题人竟然没卡(建 ...

  7. 数据服务器------sql

    服务器:能够在网站中提供各种(浏览网页,收发邮件视频,语言)等服务器的软件与硬件集合. 数据库服务器(软件):(特点:永久海量存储数据:高速的查询){所有其他软件没有的特点} 数据库服务器分类 网状数 ...

  8. L1范数与L2范数​

    L1范数与L2范数​ ​ L1范数与L2范数在机器学习中,是常用的两个正则项,都可以防止过拟合的现象.L1范数的正则项优化参数具有稀疏特性,可用于特征选择:L2范数正则项优化的参数较小,具有较好的抗干 ...

  9. Kinect外包-就找北京动点飞扬软件(长年承接微软Kinect体感项目外包,有大型Kinect案例)

    承接Kinect体感企业项目.游戏项目外包 有丰富案例提供演示,可公对公签正规合同,开发票. 我们是北京的公司.专业团队,成员为专业WPF产品公司一线开发人员,有大型产品开发经验: 提供优质的售后服务 ...

  10. Hadoop之搭建完全分布式运行模式

    一.过程分析 1.准备3台客户机(关闭防火墙.修改静态ip.主机名称) 2.安装JDK 3.配置环境变量 4.安装Hadoop 5.配置集群 6.单点启动 7.配置ssh免密登录 8.群起并测试集群 ...