3-安全/扩展内置对象 原型链(属性搜索原则) 继承实现的6种方法 Object.create() call/apply/ bind

扩展内置对象

  • 内置对象: Object | Array | Date | Function | String ...
  • 扩展: 给内置的对象添加属性和方法
  • 注意: 此方法可以达到扩展内置对象的效果.
    • 不建议使用: 在实际开发中, 可能多人合作开发. 若多人以此方法扩展对象, 代码难以维护, 可能代码被覆盖导致安全性差

安全的扩展内置对象

  • 核心操作
    • 自定义一个构造函数
    • 设置这个构造函数的原型对象是内置构造函数的一个实例


      内置扩展对象

      代码实现结构图

原型链

  • 原型链的顶端: Object.prototype
    • 原型链最顶端的原型: Object.prototype.__proto__ = null;
  • 原型链结构
    1. 每个对象都是由构造函数创建出来的
    2. 每一个构造函数都有对应的原型对象
    3. 构造函数的原型对象也是一个对象
    4. 因此, 构造函数的原型对象也有构造函数
    5. 构造函数的原型对象的构造函数也有原型对象, 这个原型对象也是一个对象
      原型链定义

原型链中属性的搜索原则

  • 就近原则
    • 访问对象属性时, 先查找自身是否有该属性, 有直接使用
    • 若没有, 就访问这个对象的原型对象是否有, 有就直接使用
    • 若没有, 会访问这个对象原型对象的原型对象上是否有, 如果有就直接使用
    • 直到Object的原型对象, 若没有, 则返回undefined(属性)或报错(方法)


      原型链属性的访问原则

继承的实现

  1. 属性拷贝(混入式继承)
    • 方法: 如果属性的值是引用类型的数据, 子对象和父对象共享同一份数据, 修改其中一个会影响另一个

        var obj = {name : 'zs',age : 20,friends:['小明','小红']};
        var  obj1 = {};
        // 需求:obj1获取obj的属性
      
        for(var key in obj){
            obj1[key] = obj[key];
        }
        // 修改了obj1的friends对obj的friends会有影响,因为他们存储的是同一个数组的地址
        obj1.friends.push('老王');
        console.log(obj1);
        console.log(obj);
      
    • 函数: Object.assign(子对象, 父对象1, 父对象2,...);

  2. 原型式继承
    • 方法: 父构造函数的原型对象赋值给子构造函数的原型对象(替换原型Son.prototype = Father.prototype)
    • 问题
      • 创建出来的对象, 构造器属性, 默认指向父构造函数
        • 无法通过构造器属性进行修改
      • 不能获取实例属性/方法, 只能获取父构造函数原型对象的属性和方法
  3. 原型链继承
    • 方法

      • 提供一个父构造函数
      • 提供一个子构造函数
      • 设置子构造函数的原型对象是父构造函数的实例
    • 注意点

      • 修正构造器属性: 要在设置原型链继承之后
      • 设置原型对象的属性: 要在设置原型链继承之後
      • 设置了原型链继承之後, 只能利用对象的动态特性设置原型对象, 不能使用字面量的方式


        原型链的注意点
    • 问题

      • 无法传递参数给父构造函数-13
      • 继承过来的实例属性会成为原型属性, 对创建出来的对象存在数据共享的问题
  4. 复杂的原型链实例
    • 注意点: 同原型链继承一样
  5. 借用构造函数继承
    • 方法: 只能获取实例属性和方法, 不能获取原型属性和方法
  6. 组合继承
    • 方法
      • 借用构造函数继承获取实例属性和方法
      • 使用原型链继承获取原型属性和方法


        组合继承的基本写法

Object.create()

  • 定义: 创建一个新的对象, 并且设置这个对象的原型对象是传入的参数
  • 兼容: ES5支持

call() | apply() |bind

  • 在ES3, 给Function的原型对象添加2个方法
    • Function.prototype.call | Function.prototype.apply
  • 作用: 借用其他对象的方法
  • 参数
    • 第一个参数: 调用方法的对象(函数内部this的绑定对象)
    • 后面的参数:
      • call 参数列表 参数1, 参数2...

      • apply 参数列表[参数1, 参数2]

        //打印1: 期望传递一个参数(参数列表可不传)
        console.log(Function.prototype.call.length);  
        //打印2: 期望传递两个参数(调用对象的数组, [])
        console.log(Function.prototype.apply.length);  
        
bind.png

深拷贝/浅拷贝

  • 浅拷贝: 引用类型数据只拷贝到地址
  • 深拷贝: 内容拷贝
    • 实现
      1. 提供一个函数, 函数有2个参数, 一个目标对象, 一个要拷贝属性的对象
      2. 判断: 第一个参数是否有值
      3. 遍历第二个参数, 判断属性值的类型
        • 如果是值类型的数据就直接赋值
        • 如果是引用类型的数据, 就再一次调用这个方法拷贝内部存储的数据

Array.isArray()

  • 定义: 判断一个对象是否是数组

  • ES5的方法, ES5之前不支持,故存在兼容性问题

      // 兼容写法
      if (!Array.isArray) {
        Array.isArray = function(arg) {
        return Object.prototype.toString.call(arg) === '[object Array]';
        };
      }
    
  • 其他方法:
    Object.prototype.toString.call()

      let a = [1,2,3]
      Object.prototype.toString.call(a) === '[object Array]';//true
      //检验是否是函数
      let a = function () {};
      Object.prototype.toString.call(a) === '[object Function]';//true
      //检验是否是数字
      let b = 1;
      Object.prototype.toString.call(a) === '[object Number]';//true
    
      //PS: 甚至对于多全局环境时, Object.prototype.toString().call()也能符合预期处理判断。
      //为body创建并添加一个iframe标签
      var iframe = document.createElement('iframe');
      document.body.appendChild(iframe);
      //取得iframe对象的构造数组方法
      xArray = window.frames[window.frames.length-1].Array;
      //通过构造函数获取一个实例
      var arr = new xArray(1,2,3); 
      console.log(Object.prototype.toString.call(arr) === '[object Array]');//true
      
      // 另外两种方法:存在多个全局环境的问题
      arr instanceof Array;//false  
      arr.constructor === Array;//false
    
    
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339