• JS 面向对象 ~ 创建对象的 9 种方式


    一、创建对象的几种方式

      1、通过字面量创建

    var obj = {};
    
    这种写法相当于:
    
    var obj = new Object();

      缺点:使用同一个接口创建很多单个对象,会产生大量重复代码

      2、通过 工厂模式 创建对象 

    function createPerson(name, job) { 
     var o = new Object() 
     o.name = name 
     o.job = job 
     o.sayName = function() { 
      console.log(this.name) 
     } 
     return o 
    } 
    var person1 = createPerson('gaosirs', 'teacher') 
    var person2 = createPerson('X', 'Doctor')

      缺点:工厂模式虽然解决了创建多个相似对象的问题,但没解决对象识别的问题(即怎样知道一个对象的类型)。

      

      3、通过 构造函数 创建对象

    function Person(name,age,job){
        this.name=name;
        this.age=age;
        this.job=job;
        this.sayName=function(){
            alert(this.name);
        };
    }
    
    var person1=new Person(...);
    var person2=new Person(...);

      缺点:使用构造函数,每个方法都要在每个实例上重新创建一遍。

      4、通过 原型模式 创建对象

    function Person() { 
    } 
    Person.prototype.name = 'Gaosirs'
    Person.prototype.job = 'teacher'
    Person.prototype.sayName = function() { 
     console.log(this.name) 
    } 
    var person1 = new Person();
    person1.sayName(); //Gaosirs

      更简单的写法:

    function Person() { 
    } 
    Person.prototype = { 
     name: 'Gaosirs', 
     job: 'teacher', 
     sayName: function() { 
      console.log(this.name) 
     } 
    } 
    var person1 = new Person()
    person1.sayName() // Gaosirs

      缺点: 

      使用原型,所有的属性都将被共享,这是个很大的优点,同样会带来一些缺点

      原型中所有属性实例是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性也勉强可以,毕竟实例属性可以屏蔽原型属性。但是引用类型值,就会出现问题了

    function Person() { 
    } 
    Person.prototype = { 
     name: 'jiang', 
     friends: ['Shelby', 'Court'] 
    } 
    var person1 = new Person() 
    var person2 = new Person() 
    person1.friends.push('Van') 
    console.log(person1.friends) //["Shelby", "Court", "Van"] 
    console.log(person2.friends) //["Shelby", "Court", "Van"] 
    console.log(person1.friends === person2.friends) // true

      

      5、组合使用构造函数模式和原型模式 创建对象

      这是使用最为广泛、认同度最高的一种创建自定义类型的方法。它可以解决上面那些模式的缺点

      使用此模式可以让每个实例都会有自己的一份实例属性副本,但同时又共享着对方法的引用

      这样的话,即使实例属性修改引用类型的值,也不会影响其他实例的属性值了

    function Person(name) { 
     this.name = name 
     this.friends = ['Shelby', 'Court'] 
    } 
    Person.prototype.sayName = function() { 
     console.log(this.name) 
    } 
    var person1 = new Person() 
    var person2 = new Person() 
    person1.friends.push('Van') 
    console.log(person1.friends) //["Shelby", "Court", "Van"] 
    console.log(person2.friends) // ["Shelby", "Court"] 
    console.log(person1.friends === person2.friends) //false

      6、使用 动态原型模式 创建对象

      动态原型模式将所有信息都封装在了构造函数中,初始化的时候,通过检测某个应该存在的方法时候有效,来决定是否需要初始化原型

    function Person(name, job) { 
      // 属性 
     this.name = name 
     this.job = job 
     // 方法 
     if(typeof this.sayName !== 'function') { 
      Person.prototype.sayName = function() { 
        console.log(this.name) 
      } 
     } 
    } 
    var person1 = new Person('Gaosirs', 'Teacher') 
    person1.sayName()

      

      只有在sayName方法不存在的时候,才会将它添加到原型中。这段代码只会初次调用构造函数的时候才会执行。

      此后原型已经完成初始化,不需要在做什么修改了

      这里对原型所做的修改,能够立即在所有实例中得到反映

      其次,if语句检查的可以是初始化之后应该存在的任何属性或方法,所以不必用一大堆的if语句检查每一个属性和方法,只要检查一个就行

      7、使用 寄生构造函数模式 创建对象

      这种模式的基本思想就是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新建的对象

    function Person(name, job) { 
      var o = new Object() 
     o.name = name 
     o.job = job 
     o.sayName = function() { 
      console.log(this.name) 
     } 
     return o 
    } 
    var person1 = new Person('Gaosirs', 'student') 
    person1.sayName()

      这个模式,除了使用new操作符并把使用的包装函数叫做构造函数之外,和工厂模式几乎一样

      构造函数如果不返回对象,默认也会返回一个新的对象,通过在构造函数的末尾添加一个return语句,可以重写调用构造函数时返回的值

      8、使用 稳妥构造函数模式 创建对象

      首先明白稳妥对象指的是没有公共属性,而且其方法也不引用this。

      稳妥对象最适合在一些安全环境中(这些环境会禁止使用this和new),或防止数据被其他应用程序改动时使用

      稳妥构造函数模式和寄生模式类似,有两点不同:一是创建对象的实例方法不引用this,而是不使用new操作符调用构造函数

    function Person(name, job) { 
     var o = new Object() 
     o.name = name 
     o.job = job 
     o.sayName = function() { 
      console.log(name) 
     } 
     return o 
    } 
    var person1 = Person('Gaosirs', 'student') 
    person1.sayName()

      变量 person1 中保存的是一个稳妥对象,而除了调用 sayName() 方法外,没有别的办法访问其数据成员。

      和寄生构造函数模式一样,这样创建出来的对象与构造函数之间没有什么关系,instanceof操作符对他们没有意义

      9、使用 Object.create() 方法创建对象

      Object.create() 方法使用现有的对象来提供新创建的对象的__proto__。

    const person = {
      isHuman: false,
      printIntroduction: function () {
        console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
      }
    };
    
    const me = Object.create(person);
    
    me.name = "Matthew"; // "name" is a property set on "me", but not on "person"
    me.isHuman = true; // inherited properties can be overwritten
    
    me.printIntroduction();
      详见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
    随笔整理自 
      https://www.jb51.net/article/117164.htm
     《JavaScript 高级程序设计 第三版 》138页 第六章 面向对象的程序设计
    感谢博主分享!
  • 相关阅读:
    ASP.NET之Cookie(坑爹的Response.Cookies.Remove)
    ASP.NET 4.0中使用FreeTextBox和FCKeditor遇到安全问题警告的解决办法
    ASP.NET用户控件操作ASPX页面(在ASPX页面捕捉用户控件的事件)
    ASP.NET页面传值之Server.Transfer
    印象中的东北特色
    Python第二周之函数及其作用域
    Python第二周之字符串,列表,元组,集合,字典
    Python第一周习题集(一)
    Python第二周习题集(一)(Craps游戏 质数 公约数 公倍数 回文质数 21根火柴游戏 验证码 后缀名 骰子随机和)
    Python第一周习题集(二)
  • 原文地址:https://www.cnblogs.com/gaosirs/p/10637183.html
Copyright © 2020-2023  润新知