• 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的对象

  • 相关阅读:
    【纯水题】POJ 1852 Ants
    【树形DP】BZOJ 1131 Sta
    【不知道怎么分类】HDU
    【树形DP】CF 1293E Xenon's Attack on the Gangs
    【贪心算法】CF Emergency Evacuation
    【思维】UVA 11300 Spreading the Wealth
    【树形DP】NOI2003 逃学的小孩
    【树形DP】BZOJ 3829 Farmcraft
    【树形DP】JSOI BZOJ4472 salesman
    【迷宫问题】CodeForces 1292A A NEKO's Maze Game
  • 原文地址:https://www.cnblogs.com/mackxu/p/2767181.html
Copyright © 2020-2023  润新知