zoukankan      html  css  js  c++  java
  • JS创建对象的7中方式

    1、  工厂模式

    2、  构造函数模式          [解决对象识别问题]

    3、  原型模式                   [解决方法和属性共享问题]

    4、  组合使用构造函数模式和原型模式

    5、  动态原型模式

    6、  寄生构造函数模式

    7、  稳妥构造函数模式

    • 最简单的方式:创建一个Object的实例,然后为它添加属性和方法。

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

    1 var person = new Object();
    2 person.name = 'mackxu';
    3 person.age = 23;
    4 person.job = 'Software Engineer';
    5 
    6 person.sayName = function() {
    7     debug(this.name);
    8 };
    • 工厂模式:这种模式抽象了创建具体对象的过程。

    具体做法:用函数封装以特定接口创建对象的细节

    缺点:对比上一个方法解决了创建多个相似对象的问题,但却没有解决对象识别的问题

     1     function createPerson(name, age, job) {
     2         var o = new Object();
     3         o.name = name;
     4         o.age = age;
     5         o.job = job;
     6         o.sayName = function() {
     7             debug(this.name);
     8         };
     9         return o;
    10     }
    • 构造函数模式:解决了对象识别问题

    使用new操作符调用构造函数经历4个步骤:

    1、 创建一个新对象

    2、 将构造函数的作用域赋给新对象(this指向这个新对象)

    3、 执行构造函数中的代码(为这个新对象添加属性)

    4、 返回新对象

    1     function Emp(name, age, job) {
    2        this.name = name;
    3        this.age = age;
    4        this.job = job;
    5        this.sayName = function() {
    6            debug(this.name);
    7        };
    9     }
    var p = new Emp();
    模拟过程如下:
    var p = {};
    Emp.apply(p);
    p.__proto__ = Emp.prototype;

    将构造函数当作函数

     1 var person = new Person('mackxu', 23, 'Software Engineer');
     2     person.sayName();
     3     debug(person.constructor == Person);
     4     debug(person instanceof Person);    
     5     //var person2 = Person('mack', 22, 'Doctor');
     6     //作为普通的函数
     7     Person('mack', 22, 'Doctor');
     8     sayName();        // == window.sagName();
     9     //在另外一个对象的作用域中调用
    10     var o = new Object();
    11     //this 指向o对象
    12     Person.call(o, 'zhangsan', 23, 'Nurse');
    13     o.sayName();    //zhangsan    
    14     debug(o instanceof Person);        //false

    问题:方法不能被实例共享

        解决方法有二:1、把方法定义到构造函数外面,但破坏了封装性

                    2、用原型模式共享方法

    • 原型模式(解决属性方法共享问题)

    每一个函数都有一个prototype属性,这个属性是一个对象,它的用途是保存可以由特定类型的所有实例共享的属性和方法。

     1 function Person() {
     2         //...
     3     }
     4     Person.prototype.name = 'mackxu';
     5     Person.prototype.age = 22;
     6     Person.prototype.job = 'Software Engineer';
     7     Person.prototype.sayName = function() {
     8         debug(this.name);
     9     };
    10 debug(person.sayName == person2.sayName)    //true

    理解原型:

     1 debug(Person.prototype.isPrototypeOf(person));    //true
     2 使用delete操作符删除实例的属性
     3 使用hasOwnProperty()方法可以检测一个属性在实例中,还是在于原型中。
     4 (准确的说:只能确定在实例中的属性,返回true)
     5     debug(person2.hasOwnProperty('name'));    //false
     6     debug('name' in person2);                //true
     7     //自定义函数判断属性在原型中定义
     8     function hasPrototypeProperty(object, name) {
     9         return !object.hasOwnProperty(name) && (name in object);
    10     }
    11     debug(hasPrototypeProperty(person2, 'name'));    //true
    12     //会屏蔽原型中与实例中相同的属性
    13     for (var property in person) {
    14         debug(property);
    15     }

    更简单的原型语法[字面量对象]

     1 function Person() {
     2         //...
     3     }
     4     Person.prototype = {
     5         constructor: Person,
     6         name : 'mackxu',
     7         age  : 22,
     8         job  : 'Software Engineer',
     9         sayName: function() {
    10             debug(this.name);    
    11         }
    12     };
    13     var person2 = new Person();
    14     debug(person2.name);
    15     debug(person2 instanceof Person);        //true
    16     debug(person2.constructor);            //Person{}
    17     debug(Person.prototype.constructor);    //Person{}    

    原型的动态性

    由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来

    ——即使是先创建了实例后修改原型也照样如此。

     1 function Person() {
     2         //.....
     3     }
     4     var person = new Person();
     5     Person.prototype.sayHi = function() {
     6          debug('Hi');
     7 };
     8  person.sayHi();        //Hi
     9 
    10     Person.prototype = {
    11         name: 'mackxu',
    12         sayHi: function() {
    13             debug('Hi');
    14         }
    15     };
    16     person.sayHi();        //error

    原理:

     

    原生对象的原型

    通过原生对象的原型,不仅可以取得所有默认方法的引用,而且可以定义新方法

        //为基本包装类型String添加自定义方法

    String.prototype.startWith = function(text) {
            return this.indexOf(text) == 0;
        };
        var msg = 'Hello World';
        debug(msg.startWith('Hello'));    //true

    原型对象的问题:

    1、 省略了为构造函数传递初始化参数的环节,

    2、 其共享本性导致的(对于引用类型属性)

    function Person() {
            //...
        }
        Person.prototype = {
            constructor: Person,
            students: ['aaa', 'bbb']
        };
        //students被实例所共享,违背了我们的初衷
        var person2 = new Person();
        debug(person2.students);
        var person3 = new Person();
        person2.students.push('ccc');     
        debug(person3.students);        //"aaa", "bbb", "ccc"

    3、 实例:属性是自己的,方法是被共享的

    • 组合使用构造函数模式和原型模式

    构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性

    结果,每个实例都有都会有自己的一份实例属性的副本,同时共享着对方的方法引用

     1     function Person(name, age, job) {
     2         this.name = name;
     3         this.age = age;
     4         this.job = job;
     5         this.friends = ['zhangsan', 'lisi'];
     6     }
     7     Person.prototype = {
     8         constructor: Person;
     9         sayName: function() {
    10             debug(this.name);
    11         };
    12     };
    13     var person2 = new Person('mackxu', 22, 'Software Engineer');
    14     var person3 = new Person('mackxu2', 23, 'Software Engineer');
    15     person2.sayName();        //mackxu
    16     person2.friends.push('wangwu');
    17     debug(person2.friends);        //['zhangsan', 'lisi', 'wangwu']
    18     debug(person3.friends);        //['zhangsan', 'lisi']
    • 动态原型模式

    把所有信息都封装在构造函数中,通过在构造函数中初始化原型,保持了同时使用构造函数和原型的有点。可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型

     1     function Person(name, age, job) {
     2         this.name = name;
     3         this.age = age;
     4         this.job = job;
     5         this.friends = ['zhangsan', 'lisi'];
     6         
     7         if (typeof this.sayName != 'function') {
     8             Person.prototype.sayName = function() {
     9                 debug(this.name);
    10             };
    11             Person.prototype.sayHi = function() {
    12                 debug("Hi");
    13             };
    14         }
    15     }
    16     var person2 = new Person('mackxu', 22, 'Software Engineer');
    17     person2.sayName();        //mackxu
    18     person2.sayHi();

        使用动态原型模式时,不能使用对象字面量重写原型。

    • 寄生构造函数模式

    构造函数在不返回值的情况下,默认会返回新对象实例。而通过在构造函数的末尾添加return,可以重写调用构造函数时返回的值。

    注意:返回的对象与构造函数或者与构造函数的原型属性之间没关系

     1     function Person(name, age, job) {
     2         var o = new Object();
     3         o.name = name;
     4         o.age = age;
     5         o.job = job;
     6         o.sayName = function() {
     7             debug(this.name);
     8         };
     9         return o;
    10     }
    11     
    12     var person2 = new Person('mackxu', 22, 'Software Engineer');
    13     person2.sayName();        //mackxu
    14     
    15     function SpecialArray() {
    16         //创建数组
    17         var values = new Array();
    18         //添加值
    19         values.push.apply(values, arguments);
    20         //添加方法
    21         values.toPipedString = function() {
    22             return this.join('|');
    23         };
    24         return values;
    25     }    
    26     //此处new的作用是什么??
    27     var colors = new SpecialArray('red', 'blue', 'green');
    28     debug(colors.toPipedString());
    • 稳妥构造函数模式

    禁止使用this和new,所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象

  • 相关阅读:
    离散数学知识点总结(8)-图论
    离散数学知识点总结(7)-格
    离散数学知识点总结(6)-计数技术
    离散数学知识点总结(5)函数
    离散数学知识点总结(4)-集合
    离散数学知识点总结(3)-二元关系
    离散数学知识点总结(2)-谓词逻辑
    离散数学知识点总结(1)-命题逻辑
    镜像仓库和Harbor
    视频管理上云平台EasyNVS 2.1版本分享RTSP流和RTMP流端口发生变化是什么原因?
  • 原文地址:https://www.cnblogs.com/mackxu/p/2767181.html
Copyright © 2011-2022 走看看