美文网首页
js中对象object的创建模式

js中对象object的创建模式

作者: jadefan | 来源:发表于2019-10-12 22:23 被阅读0次

    对象的创建除了通过字面量,常用模式还包括:

    • 工厂模式
    • 构造函数模式
    • 原型模式
    • 构造函数与原型组合模式
    • 动态原型模式
    • 寄生构造函数模式
    • 稳妥构造函数模式
      我们逐一来看下:

    工厂模式

        function createPerson(name, age, job) {
          var obj = new Object();
          obj.name = name;
          obj.age = age;
          obj.job = job;
          return obj;
        } 
        var p1 = createPerson('wang', 28, 'programmer');
        console.log(p1.name);  //wang
    

    优点:可以通过函数可以创建多个类似对象
    缺点:无法识别对象,什么意思呢?看一下代码:

        var str = new String();
        console.log(str instanceof Object);  //true
        console.log(str instanceof String);  //true
        console.log(p1 instanceof Object);   //true
        console.log(p1 instanceof createPerson);  //false
    

    通过new String()创建的str,不仅可以识别出是Object,还可以识别出是String
    而p1却不行

    构造函数模式

        function Person(name) {
          this.name = name;
          this.sayName = function () {
            console.log(this.name);
          }
        }
        var p2 = new Person('wang');
        console.log(p2.name);  //wang 
        console.log(p2 instanceof Object);   //true
        console.log(p2 instanceof Person);  //true
    

    优点:创建的对象可以很好的识别
    缺点:定义的方法在多次实例化时会重复创建,耗费资源
    验证一下:

        var p3 = new Person('wang');
        console.log(p2.name == p3.name);       //true
        console.log(p2.sayName == p3.sayName); //false
    

    创建同样属性的对象,尽管属性值相同,但方法并不相同
    我们知道函数名只是指向函数的指针,所以可以通过指针指向同一个函数

        function Person(name){
          this.name = name;
          this.sayName = sayName;
        }
        function sayName(){
          console.log(this.name);
        }
    
        var p2 = new Person('wang');
        var p3 = new Person('wang');
        console.log(p2.sayName == p3.sayName); //true
    

    这样将方法提到全局,构造函数内的方法名只赋值函数名指针即可
    但这样如果需要的方法较多,会造成全局函数滥用

    原型模式

    每个函数都有prototype(原型)属性,这个属性是一个指针,指向一个对象,叫原型对象
    原型对象包含着由特定类型的所有实例共享的属性和方法

    根据定义可以将共用的属性和方法放在原型对象中,实现共享

        function Person() { }
        Person.prototype.name = 'wang'
        Person.prototype.sayName = function () {
          console.log(this.name);
        }
    
        var p1 = new Person();
        p1.sayName();  //wang
        var p2 = new Person();
        p2.name = 'zhang';
        p2.sayName();  //zhang
        console.log(p1.sayName == p2.sayName); //true
    

    这样即可以灵活定义,方法又指向同一个函数
    优点:很好的解决了方法函数的共享问题
    缺点:对象的属性都指定了默认值(小问题),对于引用类型的属性共享后,在某个对象中修改会,会影响到其他对象的同名属性(大问题)
    验证一下:

        function Person() { }
        Person.prototype.name = 'wang'
        Person.prototype.friends = ['zhang', 'liu'];
    
        var p1 = new Person();
        console.log(p1.friends);  // ["zhang", "liu"]
        var p2 = new Person();
        p2.friends.push('li');
        console.log(p1.friends);  // ["zhang", "liu", "li"]
    

    p1.friends的两次输出不一致,受到p2修改属性的影响了

    构造函数与原型组合模式

        function Person(name,friends) {
          this.name = name;
          this.friends = friends;
         } 
        var p1 = new Person('wang', ['zhang', 'liu']);
        console.log(p1.friends);  //["zhang", "liu"]
        var p2 = new Person('wang', ['zhang', 'liu']);
        p2.friends.push('li');
        console.log(p1.friends);  //["zhang", "liu"]
    

    通过构造函数与原型的组合,就可以避免上面的问题
    这种组合模式,是目前使用最广泛、认同度最高的一种创建自定义类型的方法,也可以说是用来定义引用类型的一种默认模式。

    动态原型模式

    对于将构造函数与原型分开独立的写法,不够直观

        function Person(name, friends) {
          this.name = name;
          this.friends = friends; 
          if (typeof this.sayName != 'function') {
            Person.prototype.sayName = function () {
              console.log(this.name);
            }
          }
        }
    

    在每次调用执行构造函数时,会判断原型中sayName 是否存在,如果存在则证明函数的原型对象已经定义过,所以方法定义部分只会执行一次。

    寄生构造函数模式

        function Person(name) {
          var obj = new Object();
          obj.name = name;
          obj.sayName = function () {
            console.log(this.name);
          }
          return obj;
        }
        var p1 = new Person('wang');
        p1.sayName();  //wang
    

    寄生构造与普通工厂很类似,不同之处在于实例化对象时用到了new
    寄生构造与构造函数很类似,不同之处在于返回的对象并不是函数的this,而是与函数没有关系的另一个对象

    基本思想:创建一个函数,作用仅仅是封装创建对象的代码,然后返回新创建的对象
    用途:在特殊情况下用来为对象创建构造函数

    假设想创建一个具有额外方法的特殊数组,但不能直接修改Array构造函数

        function SpecialArray(){
          var values = new Array();
          values.push.apply(values,arguments);
          values.toPipedString=function(){
            return this.join('-');
          }
          return values;
        }
        var nums = new SpecialArray(1,2,3,4,5);
        console.log(nums.toPipedString());  //1-2-3-4-5
    

    这种模式下返回的对象与构造函数没有关系,也就不能用instanceof确定类型
    所以可用其他模式情况下,优先使用其他模式

    稳妥构造函数模式

    稳妥对象,指没有公共属性,而且其方法也不引用this的对象
    适用于某些安全环境(禁用this和new),或者防止数据被其他程序改动时使用

        function Person(name) {
          var _age;
          var obj = new Object();
          obj.age = function(age){
            _age = age
          };
          obj.sayAge = function () {
            console.log(_age);
          }
          obj.sayName = function () {
            console.log(name);
          }
          return obj;
        }
        var p1 = Person('wang');
        p1.sayName();  //wang
        p1.age(18);
        p1.sayAge();   //18
    

    也就是说该模式下不用this和new,所以内部属性都用私有变量,更新属性需通过访问方法来操作

    相关文章

      网友评论

          本文标题:js中对象object的创建模式

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