JS高级 03

作者: _MARPTS | 来源:发表于2018-05-25 11:29 被阅读0次

    JS实现继承的方式

    • 1.属性拷贝
    • 2.原型式继承
    • 3.原型链继承
    • 4.借用构造函数继承|伪对象继承|经典点继承
    • 5.组合继承
    • 6.Object.create()
    • 7.完全拷贝

    属性继承

    • 混入式继承/ 属性拷贝(两种方式)
    • 特点: 属性是引用类型,数据会共享
      • for --- in 循环
    var obj = {
        name :'zs'
        ,age:20,
        friends:['小明','小红']
    }
    
    var obj1 = {};
    
    for(var key in obj){
        obj1[key] = obj[key]
    }
    
    obj1.friends.push('老王')
    
    console.log(obj1);
    console.log(obj);
    
    // 如果属性是引用类型的数据,子对象和父对象会共享同一份数据,修改其中一个,会影响另外一个
    
    
    • 函数拷贝属性/ 相当于函数封装了for..in
    • ES6 后才开始支持
    • 语法Object.assign(o,obj,obj1)
      • 第一个参数传目标对象
      • 后面参数是要拷贝属性的对象
    var obj = {name:'zs'};
    var obj1 = {age:20};
    
    var o = {};
    
    // 第一个参数:目标对象
    //后面参数:要拷贝属性的对象
    Object.assign(o,obj,obj1);
    
    console.log(o);
    

    原型式继承

    特点:

    • 1.不能获取实例属性和实例方法,只能获取父构造函数原型对象的属性和方法
    • 2.无法修正构造器属性,默认指向父构造函数

    设置子构造函数的原型对象是父构造函数的原型对象---->原型式继承

    • 1.构造函数创建对象访问原型属性
    function Person() {
        
    }
    // 利用构造函数创建出来的对象可以使用原型对象的属性和方法
    Person.prototype.des = 'des';
    var p1 = new Person();
    console.log(p1.des);
    
    • 2.替换原型
    • 3.原型对象替换原型
    //1.提供一个父构造函数
    function Person() {
        this.name = '默认';
    }
    Person.prototype.des = 'aaa';
    //2.提供一个子构造函数
    function stu() {
        
    }
    // 设置子构造函数的原型对象是父构造函数的原型对象---->原型式继承
    stu.prototype = Person.prototype;
    
    var s1 = new Stu();
    console.log(s1.des);
    
    扩展内置对象
    • 给所有内置的对象添加属性或方法
    • Object Array Date Function String..
        // 需求 arr1有一个des属性和logDes方法
        var  arr1 = [1,2,3,4];
        arr1.des = 'des';
        arr1.logDes = function () {
            console.log(this.des);
        }
        
        console.loe(arr1.des);
        
        var arr2 = [5,6,7];
        arr2.des = 'des';
        arr2.logDes = function () {
            console.log(this.des);
        }
        
        // 需求  所有数组都添加一个des属性和logDes方法
        Array.prototype.des = 'des';
        Array.prototype.logDes = function() {
            console.log(this.des);
        }
        var arr3 = [3,4,5];
        var arr4 = [6,7,8];
        console.log(arr3.des);
        console.log(arr4.des);
    
        //通过这种方式确实可以扩展内置对象,但是不建议这样做
        // 因为在公司开发中,很可能是多人一起开发,而且项目的代码量可能非常多
        //如果人人都通过这种方式扩展内置对象,不方便项目日后的维护,很容易出现方法被覆盖的问题
    
    安全的扩展内置对象
    • 1.提供一个构造函数
    • 2..设置这个构造函数的原型对象是内置构造函数的一个实例
    function MyArray() {
        
    }
    MyArray.prototype = []//new Array();
    MyArray.prototype.des = 'des';
    MyArray.prototype.logDes = function (){
    console.log(this.des);
    }
    
    var myarr1 = new MyArray();
    myarr1.push('小明');
    console.log(myarr1);
    console.log(myarr1.des);
    
    ;
    

    原型链(画图理解)

    • 1.每一个对象都是由构造函数创建的
    • 2.每一个构造函数都有对应的原型对象
    • 3.原型对象也是一个对象,也是由构造函数创建出来的
    • 4.这个构造函数也有自己的原型对象,这个原型对象也是有个对象,也是由构造函数创建出来的
    • 以上就形成一个链式的结构,称为原型链
    • 原型链的顶端是Object的原型对象
    • (Object的原型对象也是由构造函数创建出来的,它的原型对象指向null)
    原型链中属性的访问原则(就近原则)
    • 通过对象.属性访问属性的时候,首先会查找自身,如果有就直接使用
    • 如果没有,会查找原型对象,如果有就直接使用
    • 如果原型对象也没有,会查找原型对象的原型对象,如果有就直接使用
    • 如果还没有会继续向上查找,知道原型链的顶端(Object.prototype)
    • 如果还没有,返回undefined(属性)或者报错(调用方法)

    原型链继承

    特点

    • 1.对比原型式继承,他还可以继承父构造函数的实例属性,方法和原型对象
    • 2.对比原型式继承,他可以修正构造器属性constructor
    • 1.提供一个父构造函数和子构造函数
    • 2.设置子构造函数的原型的对象好似父构造函数的一个实例 --->原型链继承
    //1.提供一个父构造函数和子构造函数
    function Person() {
        this.name = '默认';
    }
    Person.prototype.des = 'des';
    
    function Stu() {
        
    }
    // 2.原型链继承
    Stu.prototype = new Person();
    
    var s1 = new Stu();
    console.log(s1.des);//des
    console.log(s1.name);//默认
    
    
    原型链注意点
    • 1.注意修正构造器要在原型链继承之后(涉及到替换对象的地址变更)
    • 2.同理,要给当前对象的原型对象设置属性或方法,要在设置原型链继承之后
    • 3.在原型链继承后,只能在原型链的基础上动态添加和修改属性和方法,如果用替换对象会破坏原型链继承
    原型链继承的问题
    • 1.无法传递参数给父构造函数
    • 2.继承过来的实例属性会变为原型属性,就有数据共享的问题

    Object.create()方法

    • 创建一个新的对象,并设置这个对象的原型对象
    • ES5 支持
        var obj = {name:'zs',age:20};
        
        //创建一个新的对象,并设置这个对象的原型对象
        var o = Object.create(obj);
        console.log(o.name);
    
    • 兼容性处理
      var obj = {name:'zs',age:20};
      // 兼容性处理
      if(Object.create){
          var o = Object.create(obj);
      }else{
          // 非标准方法
          //var o = new Object();
          //o._protp_ = obj;
          
          // 标准方法  可封装
          function F() {
              
          }
          F.prototype = obj;
          var o = new F();
      }
      
    • 兼容性函数封装
      function createObj(obj){
          if(Object.create){
              return Object.create(obj);
          }else{
              function F(){
              }
              F.prototype=obj;
              return new F()
          }
      }
      
    • 方法二:处理兼容性 给Object添加方法(要放在使用方法前面)
      if(!Object.create){
          Object.create = function (obj){
              function F(){
              }
              F.prototype=obj;
              return new F() 
          }
      }
      
    call和apply函数
    • 1.在ES3的时候,系统给Function的原型队形添加了call和apply函数

    • 2.作用:借用其他对象的方法

    • call(调用对象,参数1,参数2(参数类表)

      • 语法: 借用对象.借用方法.call(调用对象,参数1,参数2(参数类表)
    • apply(调用对象,参数数组)

      • 语法: 借用对象.借用方法.apply(调用对象,参数数组)
    var zs = {
        name:'zs',
        showName : function (p1,p2){
            console.log(this.name,p1,p2)
        }
    }
    
    var ls = {
        name: 'ls'
    }
    
    zs.showNam('憨厚','耿直');
    // 无法直接访问
    //ls.showNam('智商高','情商低') // 报错
    
    zs.showName.call(ls,'智商高','情商低')
    zs.showName.apply(ls,['智商高','情商低'])
    
    借用构造函数继承 | 经典继承 | 伪对象继承
    • 只能获取实例属性和实例方法,不能获取原型属性和属性方法
    • 本质是借用执行父构造函数的函数把this传入
        function Person(name,age){
            this.name = name;
            this.age = age;
        }
         Person.prototype.des= 'des';
        
        function stu(num,name,age){
            this.num = num;
            // 借用构造函数继承
            Person.call(this,name,age)
        }
    
        var s1 = new stu(10086,'zs',20);
        var s2 = new stu(1002,'ls',22);
        
        console.log(s1);
        console.log(s2);
        
        console.log(s1.des);
        console.log(s2.des);
    
    组成继承

    特点(利用借用构造函数继承)

    • 1.解决了原型链参数传递给父构造函数的问题
    • 2.解决了原型链继承所得的原型对象的数据共享问题
    • 1.利用借用构造函数继承获取实例属性和方法
    • 2.再获取原型属性和方法
        function Person(name){
            this.name = name;
        }
        Person.prototype.des= 'des';
        
        function stu(num,name){
            this.num = num;
            // 借用构造函数继承
            Person.call(this,name)
        }
        
        // 原型式继承
        Stu.prototype = Person.prototype
        
        // 原型链继承
        Stu.prototype = new Person()
        Stu.prototype.constructor = stu;
        
        var s1 = new stu(10086,'zs');
        
        console.log(s1.name);
        console.log(s1.des);
    
    深拷贝和浅拷贝
    • 浅拷贝(地址拷贝)(指针拷贝)
      • 引用类型的属性,把地址拷贝
    • 深拷贝(内容拷贝, 完全拷贝)
      • 引用类型的属性,拷贝内容,过程要实现
      • 1.提供一个函数,有2个参数(目标对象,要拷贝属性的对象)
      • 2.判断第一个参数是否有值,如果没值,就初始化一个空点的对象
      • 3.遍历第二参数,判断属性值的类型
        • 1.值类型的,直接赋值
        • 2.引用类型的,再一次调用这个方法去拷贝存储的内容
      function deepCopy(obj,copyObj){
          obj = obj || {};
          
          for(var key in copyObj){
              if(typeof copyObj[key] == 'object'){
                  obj[key] = {};
                  //引用类型的数据
                  deepCopy(obj[key],copyObj[key])
              }else{
                  // 值类型
                  obj[key]=copyObj[key]
              }
          }
      }
      
    Array.isArray()
    • 判断一个对象是否是数组

    • ES5支持

    • 在ES5之前是怎么判断一个对象是数组?
      Object.prototype.toString.call(判断对象)// [object,Array]

    • 兼容性的处理

      if(!Array.isArray){
          Array.isArray = function (obj){
              return Object.prototype.toString.call(obj);
          }
      }
      

    相关文章

      网友评论

        本文标题:JS高级 03

        本文链接:https://www.haomeiwen.com/subject/atmyjftx.html