8条规则图解JavaScript原型链继承原理

原形链是JS难点之一,而且很多书都喜欢用一大堆的文字解释给你听什么什么是原型链,就算有图配上讲解,有的图也是点到为止,很难让人不产生疑惑。

我们先来看一段程序,友情提示sublimeText看更爽:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>《JavaScript高级程序设计(第三版)》Page163页的源码</title>
<link href="" rel="stylesheet">
</head>
<body>
    <script type="text/javascript">
    function SuperType(){
        this.property = "我是父亲的属性";
    }
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    }
    function SubType(){
        this.subproperty = "我是孩子的属性";
    }
    SubType.prototype = new SuperType();
    SubType.prototype.getSubValue = function(){
        return this.subproperty;
    }
    var instance = new SubType();  
    alert(instance.getSuperValue());//我是父亲的属性
</script>
</body>
</html>

有的人可能会觉得很熟悉,这是《JavaScript高级程序设计(第三版)》Page163页的源码。ps:将原来的false,true改成中文字符串比较容易看懂

但是下面的图我看了就觉得很怪了,原来的原型不是换了吗?怎么还指向呢?然后自己画了一个图并且证明了一遍,才发现原来书里画的也是错的。



然后就引出了想要图解原型链的想法,我们来看下面,友情提示sublimeText看更爽:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>JS原形链图解</title>
</head>
<body>
    <script type="text/javascript">
    function SuperType(){
        this.property = "我是父亲的属性";
    }
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    }
    function SubType(){
        this.subproperty = "我是孩子的属性";
    }
    var SubPro = SubType.prototype;//因为下面要改变原型,先用一个引用存起来,不然等下找不到
    console.log("没改变原型之前是相等的:"+(SubType.prototype===SubPro))
    SubType.prototype = new SuperType(); //这里改变了SubType的原型使它指向一个SuperType实例
    console.log("给SubType构造函数换了原型之后是不等的:"+(SubType.prototype===SubPro));
    //这里可以看出原型已经改变了
    SubType.prototype.getSubValue = function(){
        return this.subproperty;
    }
    var instance = new SubType();
    //****************************
    //下面开始证明图
    //****************************
    console.log("window对象下面添加了一个函数SuperType:"+(window.hasOwnProperty(‘SuperType‘)));
    console.log("window对象下面添加了一个函数SubType:"+(window.hasOwnProperty(‘SubType‘)));
    //下面全部为true
    console.log("1:"+(SuperType.prototype===SuperType.prototype));
    console.log("2:"+(SuperType===SuperType.prototype.constructor));
    //不能直接找到new SuperType,我们用5来获取
    console.log("3:"+(SubType.prototype.__proto__===SuperType.prototype));
    console.log("4:"+(SubType.prototype.constructor===SuperType));
    console.log("5:上面3,4已经顺带一起证明了,而且直接看代码就可以看出来了");
    //我们用SubPro暂存了原来的原型
    console.log("6:"+(SubPro.constructor===SubType));
    //还是因为取不到new SuperType,我们用SubType.prototype来获取
    console.log("7:"+(instance.__proto__===SubType.prototype));
    console.log("8:"+(instance.constructor===SuperType));
    //****************************
    //下面开始证明各自的属性位置
    //****************************
    console.log("instance有私有的subproperty属性:"+(instance.hasOwnProperty(‘subproperty‘)));
    console.log("new SuperType有私有的property属性:"+(SubType.prototype.hasOwnProperty(‘property‘)));
    console.log("SuperType.prototype拥有私有的getSuperValue属性:"+(SuperType.prototype.hasOwnProperty(‘getSuperValue‘)));
    console.log("SubType.prototype(换过的原型)拥有私有的getSubValue属性:"+(SubType.prototype.hasOwnProperty(‘getSubValue‘)));
    console.log("SubPro(原来的原型)拥有私有的getSubValue属性:"+(SubPro.hasOwnProperty(‘getSubValue‘)));//false原来的原型没有getSubValue函数,因为是换了原型再添加的函数,所以函数存在实例里面
    </script>
</body>
</html>



下面梳理一下原型链继承:(点击看大图)

这里通过一个SuperType实例替换SubType的原来的原型,这里的SuperType实例本身就拥有SuperType构造函数以及SuperType.prototype自带的一些属性,那么当取代SubType.prototype(原来的)之后,自然而然的instance实例的属性找不到的要到SubType的原型里面去找,而原来的原型已经被替换了,那么新原型里面有的属性就成了instance可以找到的属性了。ps:这里文字真心不好表达,反正就是往构造函数和构造函数原型找的意思。

这里当然也发生了略微有点奇怪的两点:

  1. __proto__属性指向新原型(本来是指向旧的SubType.prototype也就是SubPro的),这里勉强可以理解,换了原型嘛!
  2. constructor指向了SuperType构造函数(没有改变原型的话是指向SubType构造函数的),无法理解,代码是var instance = new SubType();怎么顺便把constructor属性也换了?

但是问题存在我们依旧可以很好理解JS的原型链继承:通过新的实例继承父构造函数与其原型的属性,然后通过替换子构造函数原型达到继承的目的。



非常建议看过《JavaScript高级程序设计(第三版)》的童鞋看完上面之后回去把书里面原型链这一节看一下,对比一下。如果有问题请留言。万分感谢!如果觉得我写的有用的话请点个赞,这是对我最大的鼓励!么么哒^_^

原文地址:请点击这里

时间: 2024-08-05 12:00:45

8条规则图解JavaScript原型链继承原理的相关文章

JavaScript学习总结(十七)——Javascript原型链的原理

一.JavaScript原型链 ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法.其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.在JavaScript中,用 __proto__ 属性来表示一个对象的原型链.当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止! 比如现在有如下的代码: 扩展Object类,添加Clone和Extend方法 1 /*扩展Object类,添加Clone,JS实现克隆的方法*/ 2 Ob

javascript原型链继承

一.关于javascript原型的基本概念: prototype属性:每个函数都一个prototype属性,这个属性指向函数的原型对象.原型对象主要用于共享实例中所包含的的属性和方法. constructor属性:每个原型对象都有一个constructor属性,这个constructor属性包含一个指向prototype属性所在函数的指针. 例如 Foo.prototype.constructor指向Foo函数.这个属性是只读的. __proto__属性(ES6通过对__proto__属性进行标

老生常谈之JavaScript原型链继承

介绍 本文总结了ES3,ES5,ES7和NS(NonStandard)四种原型链继承的实现方法. 前言 ECMAScript 6 class将给开发者带来JavaScript OOP的规范实现,但这种方式的直接应用和普及至少得等到IE11被淘汰掉,而到那时,说不定我们已转向边沿领域了. 随着Web的快速发展,新的方法可能会随时取代旧的方法,而我们在lifetime中用过的方法,代表着一代人的记忆,又怎能忘怀? 分享 另附上BDD测试 这其中: 较新的JavaScript运行环境能兼容旧的继承方法

图解Javascript原型链

本文尝试阐述Js中原型(prototype).原型链(prototype chain)等概念及其作用机制.上一篇文章(图解Javascript上下文与作用域)介绍了Js中变量作用域的相关概念,实际上关注的一个核心问题是:“在执行当前这行代码时Js解释器可以获取哪些变量”,而原型与原型链实际上还是关于这一问题. 我们知道,在Js中一切皆为对象(Object),但是Js中并没有类(class):Js是基于原型(prototype-based)来实现的面向对象(OOP)的编程范式的,但并不是所有的对象

【笔记】javascript原型链继承实例

function Shape(){ this.name = 'shape'; this.toString = function(){ return this.name; } } function TwoDShape(){ this.name = '2D shape'; } function Triangle(side,height){ this.name = 'Triangle'; this.side = side; this.height = height; this.getArea = fu

Javascript的原型、原型链、原型链继承

原型 在javascript中,原型分有两种:显示原型(prototype)和隐式原型(__proto__). __proto__(隐式原型) JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过__proto__来访问.ES5中有了对于这个内置属性标准的Get方法Object.getPrototypeOf(). prototype(显式原型) 这是函数对象特有的属性.这个属性是一个指针,指向一个对象,这

Javascript 组合继承 原型链继承 寄生继承

Javascript继承通常有三种方式. 第一种:组合式继承: function SuperType(name) { this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function() { console.log(this.name); }; function SubType(name, age) { //通过ca

一步步学习javascript基础篇(5):面向对象设计之对象继承(原型链继承)

上一篇介绍了对象创建的几种基本方式,今天我们看分析下对象的继承. 一.原型链继承 1.通过设置prototype指向“父类”的实例来实现继承. function Obj1() { this.name1 = "张三"; } function Obj2() { } Obj2.prototype = new Obj1(); var t2 = new Obj2(); alert(t2.name1); 这里有个明显的缺点就是:(如果父类的属性是引用类型,那么我们在对象实例修改属性的时候会把原型中

明白JavaScript原型链和JavaScrip继承

原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: 1 <script type="text/javascript"> 2 function parent(){ 3 this.name="cehis"; 4 } 5 6 function son(){ 7 this.age=11; 8 } 9 10 function sub(){ 11 this.sex="nan"; 12 }