创建对象的几种方法的优劣对比

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

看到标题,你可能会不屑地想,创建对象谁不会啊,不就直接等于号加花括号嘛。是的,只是我们开发中最常用的开发方法,看当你看完这篇文章,你肯定会得到一些不一样的收获。

对象的含义

在JS中,Object是一种无序名值对的集合,属性值可以为基本数据类型、对象或者函数。所以函数就是一组键值对的集合。

创建对象的几种方法

在开发中,我们常用的创建对象基本有两种方式。

1、使用New操作符和Object构造函数

   let person = new Object();
   person.name = 'zhangsan';
   person.age = 18;
   person.getName = function(){
       return this.name;
   }
复制代码

2、使用对象字面量的方法。

   let person = {
       name:'zhangsan',
       age:18,
       getName:function(){
           return this.name;
       }
   }
复制代码

以上是我们常用的两种创建对象的方法,能够满足我们多数的开发过程的需求。优点是简单、易于理解。但是对象的属性值是直接设置自身的,当我们需要创建多个属性相同,属性值不同的对象时候,按照上面的方法,只能通过复制代码的方法实现,造成冗余的代码,所以才有了今天我们的这篇文章。

3、基于工厂方法的模式

工厂方法是一种设计模式。这种模式的核心是封装生产“产品”的方法。然后用户只需知道“工厂名称”和传入所需的“原料“就可以得到对应的”产品”,而不用关心“工厂“内部生产“产品“的过程。下面是代码实现。

    //创建Person的工厂函数,需要传入name和age两个参数
    function createPerson(name,age){
        return {
              name,
              age,
              getName:function(){
                  return this.name;
              }
        }
    }
    
    let zhangSan = createPerson('zhangSan',18);
    let liSi = createPerson('liSi',18);
复制代码

使用工厂模式可以减少很多冗余的代码,但是因为我们不知道工厂函数内部的实现,在调用工厂函数的时候,我们不知道工厂生产出来的产品是什么类型的。

4、基于构造函数模式

构造函数是通过this为对象添加属性的,然后通过new操作符来创建对象的实例。下面我们看代码实现。

    function Person(name,age){
        this.name = name;
        this.age = age;
        this.getName = function(){
            return this.name;
        }
    }
    
    let zhangSan = new Person('zhangSan',18);
    let liSi = new Person('liSi',18);
        
    console.log(zhangSan.getName === liSi.getName) //false
复制代码

使用构造函数,可以很好的解决工厂模式的问题。但是因为每次都是每次都是创建新的实例,所以它们的方法其实是不一样的。工厂模式其实也存在这个方法,因为getName函数实现的功能一样,因此我们期待它是共用的,而不是每次都创建新的,占用内存,另外函数也没必要在代码执行前就绑定到对象上。

5、基于原型对象的模式

    function Person(name,age){
        Person.prototype.name = name;
        Person.prototype.age = age;
        Person.prototype.getName = function(){
            return this.name;
        }
    }
    let zhangSan = new Person('zhangSan',18);
    let liSi = new Person('liSi',20);
        
    console.log(zhangSan.getName === liSi.getName) //true
    console.log(zhangSan.age) // 此时会打印出来20,与我们预期的18不符合
    console.log(liSi.age) // 20
复制代码

使用基于原型对象的模式创建对象的实例,实例的属性和方法都是相等共用的,解决了基于构造函数模式的问题:函数会创建多个,造成内存浪费。但是也是因为属性和方法都是共用的,导致修改一个实例的一个属性值,会影响到别的实例相同的属性值。

6、构造函数和原形混合的模式(推荐)

那么为了解决构造函数模式和原形对象模式的缺点,就出现了构造函数和原形混合的模式。它结合了两者的优点又避免了缺点。即将我们需要私有不共享的属性使用构造函数的模式创建,而需要共享的函数方法使用原形模式创建,代码实现如下:

    //通过构造函数定义实例不共享的属性
    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    //通过原形链定义共用的方法
    Person.prototype.getName = function(){
        return this.name;
    }
    
    let zhangSan = new Person('zhangSan',18);
    let liSi = new Person('liSi',20);
        
    console.log(zhangSan.getName === liSi.getName) //true
    console.log(zhangSan.age) // 18
    console.log(liSi.age) // 20
复制代码

7、基于动态原型模式

上面的方法6其实已经很完美啦,但是还有上面方法的变种,参考一下:

//通过构造函数定义实例不共享的属性
    function Person(name,age){
        this.name = name;
        this.age = age;
        if(typeOf Person.prototype.init === 'undefined'){
            Person.prototype.getName = function(){
                return this.name;
            }
            Person.prototype.init = true;
        }
    }
    
    let zhangSan = new Person('zhangSan',18);
    let liSi = new Person('liSi',20);
        
    console.log(zhangSan.getName === liSi.getName) //true
    console.log(zhangSan.age) // 18
    console.log(liSi.age) // 20
复制代码

猜你喜欢

转载自juejin.im/post/7109068258610937886