zoukankan      html  css  js  c++  java
  • JS对象继承与原型链

    1.以复制方式实现的继承

    1.1浅拷贝

    基本类型的复制

     1 var parent = {
     2     lanage: "chinese"
     3 }
     4 
     5 var child = {
     6     name: "xxx",
     7     age: 12
     8 }
     9 
    10 function extend(parent, child) {
    11     var child = child || {};
    12     for (const propertype in parent) {
    13         child[propertype] = parent[propertype];
    14     }
    15 }
    16 
    17 extend(parent, child);
    18 
    19 console.log(child);//{ name: 'xxx', age: 12, lanage: 'chinese' }

    以上代码中,通过一个extend()函数,将父对象parent的属性遍历赋给子对象child,从而实现继承。

    但是这种字面量复制的方式存在巨大的缺陷,当父对象有引用类型的属性时,通过这么复制的方式,就像上一节中的var b = a一样,只会将a对象的引用赋给b对象,结果两者是指向同一个对象内存的,继承出来的子对象的属性是同一个,显然是不能满足需求的,(基本类型之间画等号是值的复制,引用类型之间画等号是引用的复制)所以就需要另谋出路。

    1.2.深拷贝

    利用递归加类型判断复制引用类型

     1 var parent = {
     2     lanage: "chinese",
     3     address: {
     4         home: "gansu",
     5         office: "xian"
     6     },
     7     schools: ["xiaoxue", "zhongxue", "daxue"]
     8 }
     9 
    10 var child = {
    11     name: "xxx",
    12     age: 12
    13 }
    14 
    15 function extendDeeply(parent, child) {
    16     var child = child || {};
    17     for (const propertype in parent) {
    18         //首先判断父对象的当前属性是不是引用类型
    19         if (typeof parent[propertype] === "object") {
    20             //再判断该引用类型是不是数组,是则给子对象初始化为空数组,否则初始化为空对象
    21             child[propertype] = Array.isArray(parent[propertype]) ? [] : {};
    22             //递归调用自己,将父对象的属性复制到子对象
    23             extendDeeply(parent[propertype], child[propertype]);
    24         } else {
    25             //基本类型直接复制
    26             child[propertype] = parent[propertype];
    27         }
    28     }
    29 }
    30 
    31 extendDeeply(parent, child);
    32 console.log(child);
    33 child.schools[0] = "qinghua"; //改变子对象的属性值
    34 child.address.home = "tianjin";
    35 
    36 console.log(child.schools[0]); //qinghua
    37 console.log(parent.schools[0]); //xiaoxue
    38 console.log(child.address.home); //tianjin
    39 console.log(parent.address.home); //gansu

    可见此时子对象的改变并不会影响到父对象,父子彻底决裂。这便是深拷贝实现的继承。

    注意:for in 是可以遍历数组的,结果为数组元素下标。

    2.以构造函数实现继承

     1 function Parent() {
     2     this.name = "name";
     3     this.age = 12;
     4 }
     5 
     6 function Child() {
     7     Parent.call(this);
     8     this.language = "chinese";
     9 }
    10 
    11 var child = new Child();
    12 console.log(child);//{ name: 'name', age: 12, language: 'chinese' }
    13 child.name = "swk";
    14 console.log(new Parent().name);//name

    如上所示,通过在子类构造函数中调用父类构造函数,将父类属性继承到子类对象上,new出来的每一个子类对象都是独立的实例,这种方式更符合面向对象的思想。

    3.以原型方式实现继承

     1 var person = {name: "pname"};
     2 
     3 function myCreate(person) {
     4     var ins;
     5     function F() { };
     6     F.prototype = person;
     7     ins = new F();
     8     return ins;
     9 }
    10 
    11 var c = new myCreate(person);
    12 console.log(c.name); //pname
    13 console.log(c); //{}

    如上所示,将一个构造函数的原型替换为父对象,然后返回该构造函数的实例,如此一来创建的子对象就是F的实例,并且其原型为父对象,所以c.name可以被查找到,但子对象c本身是没有属性的。这种直接重写prototype原型对象的弊端在于会断掉原本的原型链,即没有了继承自Object的方法,和给原型对象prototype上添加属性是不同的。

    4.JS原型链

    盗一波大神的经典图

    从该图可以看出两点

    4.1从原型prototype层面:

    • 不论是 new Foo()自定义构造函数,new Object()系统构造函数,还是对象字面量创建出来的对象,只要是对象,其原型最终都指向Object.prototype对象,自定义的多绕了一步,就像Java里说的,Object.prototype是一切JS对象的根对象。
    • 函数的原型都指向Function.prototype,而在JS中,函数也是对象的一种,所以符合第一条。

    4.2从构造器constructor层面

    • 首先对象的构造器肯定是指向他的构造函数,f1, f2指向Foo(), o1, o2指向Object()。
    • 而构造函数Foo()和Object()的constructor属性最终指向函数构造器Function()。
  • 相关阅读:
    前端神器avalonJS入门(一)
    emmet的使用
    VS2015中SharedProject与可移植类库(PCL)项目
    Map工具系列-08-map控件查看器
    Map工具系列-07-TFS变更集提取工具
    Map工具系列-06-销售营改增历史数据处理工具
    2018.04.02 matplotlib 图名,图例,轴标签,轴边界,轴刻度,轴刻度标签
    2018.03.30 abap屏幕标签保存之前执行过的状态
    2018.03.29 python-matplotlib 图表生成
    2018.03.29 python-pandas 数据读取
  • 原文地址:https://www.cnblogs.com/jixiaohua/p/10514239.html
Copyright © 2011-2022 走看看