• 读书笔记之创建对象


    最近在复习红宝书的对象一章,红宝书中一共提到了7种创建对象的方式(这里所说的对象更偏向于面向对象编程中的对象)。7种方式分别是:

    • 工厂模式
    • 构造函数模式
    • 原型模式
    • 构造函数和原型组合模式
    • 动态原型模式
    • 寄生构造模式
    • 稳妥构造模式

    首先解释几个概念:

    1. 对象 下面例子中所有的Person函数
    2. 实例/对象实例 通过new Person() or Person()返回的对象,如var person1 = new Person()中的person1
    3. 原型对象Person.prototype

    工厂模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Person() {
    var o = new Object();
    o.name = 'hanmeimei';
    o.say = function() {
    alert(this.name);
    }
    return o;
    }
     
    var person1 = Person();

    优点:完成了返回一个对象的要求。

    缺点:

    1. 无法通过constructor识别对象,以为都是来自Object,无法得知来自Person
    2. 每次通过Person创建对象的时候,所有的say方法都是一样的,但是却存储了多次,浪费资源。

    构造函数模式

    1
    2
    3
    4
    5
    6
    7
    8
    function Person() {
    this.name = 'hanmeimei';
    this.say = function() {
    alert(this.name)
    }
    }
     
    var person1 = new Person();

    优点:

    1. 通过constructor或者instanceof可以识别对象实例的类别
    2. 可以通过new 关键字来创建对象实例,更像OO语言中创建对象实例

    缺点:

    1. 多个实例的say方法都是实现一样的效果,但是却存储了很多次(两个对象实例的say方法是不同的,因为存放的地址不同)

    注意:

    1. 构造函数模式隐试的在最后返回return this 所以在缺少new的情况下,会将属性和方法添加给全局对象,浏览器端就会添加给window对象。
    2. 也可以根据return this 的特性调用call或者apply指定this。这一点在后面的继承有很大帮助。

    原型模式

    1
    2
    3
    4
    5
    6
    7
    8
    function Person() {}
    Person.prototype.name = 'hanmeimei';
    Person.prototype.say = function() {
    alert(this.name);
    }
    Person.prototype.friends = ['lilei'];
     
    var person1 = new Person();

    优点:

    1. say方法是共享的了,所有的实例的say方法都指向同一个。

    2. 可以动态的添加原型对象的方法和属性,并直接反映在对象实例上。

      1
      2
      3
      4
      5
      var person1 = new Person()
      Person.prototype.showFriends = function() {
      console.log(this.friends)
      }
      person1.showFriends() //['lilei']

    缺点:

    1. 出现引用的情况下会出现问题具体见下面代码:

      1
      2
      3
      4
      var person1 = new Person();
      var person2 = new Person();
      person1.friends.push('xiaoming');
      console.log(person2.friends) //['lilei', 'xiaoming']

      因为js对引用类型的赋值都是将地址存储在变量中,所以person1和person2的friends属性指向的是同一块存储区域。

    2. 第一次调用say方法或者name属性的时候会搜索两次,第一次是在实例上寻找say方法,没有找到就去原型对象(Person.prototype)上找say方法,找到后就会在实力上添加这些方法or属性。

    3. 所有的方法都是共享的,没有办法创建实例自己的属性和方法,也没有办法像构造函数那样传递参数。

    注意:

    1. 优点②中存在一个问题就是直接通过对象字面量给Person.prototype进行赋值的时候会导致constructor改变,所以需要手动设置,其次就是通过对象字面量给Person.prototype进行赋值,会无法作用在之前创建的对象实例上

      1
      2
      3
      4
      5
      6
      7
      8
      9
      var person1 = new Person()
      Person.prototype = {
      name: 'hanmeimei2',
      setName: function(name){
      this.name = name
      }
      }
       
      person1.setName() //Uncaught TypeError: person1.set is not a function(…)

      这是因为对象实例和对象原型直接是通过一个指针链接的,这个指针是一个内部属性[[Prototype]],可以通过__proto__访问。我们通过对象字面量修改了Person.prototype指向的地址,然而对象实例的__proto__,并没有跟着一起更新,所以这就导致,实例还访问着原来的Person.prototype,所以建议不要通过这种方式去改变Person.prototype属性

    构造函数和原型组合模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Person(name) {
    this.name = name
    this.friends = ['lilei']
    }
    Person.prototype.say = function() {
    console.log(this.name)
    }
     
    var person1 = new Person('hanmeimei')
    person1.say() //hanmeimei

    优点:

    1. 解决了原型模式对于引用对象的缺点
    2. 解决了原型模式没有办法传递参数的缺点
    3. 解决了构造函数模式不能共享方法的缺点

    缺点:

    1. 和原型模式中注意①一样

    动态原型模式

    1
    2
    3
    4
    5
    6
    7
    function Person(name) {
    this.name = name
    if(typeof this.say != 'function') {
    Person.prototype.say = function(
    alert(this.name)
    }
    }

    优点:

    1. 可以在初次调用构造函数的时候就完成原型对象的修改
    2. 修改能体现在所有的实例中

    缺点:红宝书都说这个方案完美了。。。。

    注意:

    1. 只用检查一个在执行后应该存在的方法或者属性就行了
    2. 不能用对象字面量修改原型对象

    寄生构造函数模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Person(name) {
    var o = new Object()
    o.name = name
    o.say = function() {
    alert(this.name)
    }
    return o
    }
     
    var peron1 = new Person('hanmeimei')

    优点:

    1. 和工厂模式基本一样,除了多了个new操作符

    缺点:

    1. 和工厂模式一样,不能区分实例的类别

    稳妥构造模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Person(name) {
    var o = new Object()
    o.say = function() {
    alert(name)
    }
    }
     
    var person1 = new Person('hanmeimei');
    person1.name // undefined
    person1.say() //hanmeimei

    优点:

    1. 安全,那么好像成为了私有变量,只能通过say方法去访问

    缺点:

    1. 不能区分实例的类别
  • 相关阅读:
    进程与线程
    java的引用
    基本类型变量、引用类型变量的在java中的存放位置
    Spring学习(三)
    Spring学习(一)
    Struts2学习(三)
    Vue,resource基本使用
    uni-app v-for数据的绑定唯一
    uni-app,v-for时 block 和 view 的使用
    Vue,生命周期函数演示(创建阶段的4个钩子函数,组件运行和销毁阶段的钩子函数)
  • 原文地址:https://www.cnblogs.com/libin-1/p/6060835.html
Copyright © 2020-2023  润新知