• JS创建对象学习笔记


    一、创建对象

    1.1 工厂模式

    工厂模式抽象了创建具体对象的过程,用函数来封装以特定接口创建对象的细节。代码如下:

    function createPerson(name, age, job) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function() {
            console.log(this.name);
        };
        return o;
    }
    
    var person1 = createPerson('sy', 25, 'Software Engineer')
    var person2 = createPerson('sansa', 25, 'Doctor')

    工厂模式的优点:解决创建多个相似对象的问题

    缺点:无法解决对象识别的问题,即怎样知道一个对象的类型

    1.2 构造函数模式

    构造函数可以创建特定类型的对象,如果是Object和Array这样的原生构造函数,在运行时会出现在执行环境中,此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。

    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = function() {
            console.log(this.name)
        }
    }
    
    var person1 = new Person('sy',  25, 'Software Engineer')
    var person2 = new Person('sansa', 25, 'Doctor')

    与构造函数不同之处:

    没有显式地创建对象;直接将属性和方法赋给了this对象;没有return语句。

    创建Person的新实例,必须使用new操作符。会经过以下步骤:

    (1)创建一个新对象;

    (2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);

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

    (4)返回新对象。

    person1和person2都有一个constructor(构造函数)属性,该属性指向Person。

    person1.constructor == Person; // true

    构造函数的优点:可以清楚的知道一个对象的类型

    缺点:构造函数中存在方法的话,每个Person实例都包含一个不同的Function实例。ECMAScript中的函数是对象,因此每定义一个函数,就是实例化了一个对象。如果将方法移到全局作用域的话,会导致这个函数只能被某个对象调用,这让全局作用域名不副实。而且如果对象需要定义很多方法,那就要定义很多全局函数,这样对自定义的引用类型没有了封装性。

    1.3 原型模式(*)

    使用原型对象的好处是:可以让所有对象实例共享它所包含的属性和方法。创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,prototype就是通过调用构造函数而创建的那个对象实例的原型对象。

    function Person() {
    }
    
    Person.prototype.name = 'sy';
    Person.prototype.age = 25;
    Person.prototype.job = 'Software Engineer';
    Person.prototype.sayName = function() {
        console.log(this.name)
    };
    
    var person1 = new Person()
    person1.sayName() // 'sy'
    
    var person2 = new Person()
    person2.sayName() // 'sy'
    
    person1.sayName === person2.sayName // true

    __proto__存在于实例与构造函数的原型对象之间。

    Person.prototype.isPrototypeOf(person1) // true

    Object.getPrototypeOf(person1) == Person.prototype // true

    注:使用for-in循环时,返回的是通过对象访问的、可枚举的属性,包括实例中的属性,也包括存在于原型中的属性。要取得对象上所有可枚举的实例属性,使用ES5的Object.keys()方法,这个方法接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。

    如果要得到所有实例属性,无论是否可枚举,可以使用Object.getOwnPropertyNames(Person.prototype); // ["constructor", "name"] 显示了不可枚举的constructor属性

    简单的原型语法:

    function Person(){
    }
    
    Person.prototype = {
        name: 'sy',
        age: '25',
        job: 'Software Engineer',
        sayName: function() {
            console.log(name)
        }
    }

    constructor属性不再指向Person了。每创建一个函数,就会同时创建它的prototype对象,这个对象也会自动获得constructor属性,而这个语法,本质上完全重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向Object构造函数),不再指向Person函数。通过constructor无法确定对象的类型了。可以强制将constructor: Person,但是会导致它的[[Enumerable]]特性设置为true。实例中的指针仅指向原型,而不指向构造函数

    原型模式的优点:可以共享属性和方法

    缺点:对于包含引用类型的属性,会导致所有的对象都发生变化

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

    构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。最大限度地节省了内存,而且这种模式支持向构造函数传递参数。

    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.friends = ['111', '222']
    }
    
    Person.prototype = {
        constructor: Person,
        sayName: function() {
            console.log(this.name)
        }
    }
    
    var person1 = new Person('sy', 25, 'Software Engineer')
    var person2 = new Person('sansa', 25, 'Doctor')
    
    person1.friends.push('333')
    console.log(person1.friends === person2.friends) // false

    1.5 动态原型模式

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

    function Person(name, age, job){
        // 属性
        this.name = name;
        this.age = age;
        this.job = job;
        // 方法
        if(typeof this.sayName != 'function'){
            Person.prototype.sayName = function() {
                console.log(this.name)
            }
        }
    }
    var friend = new Person('sy', 25, 'Software Engineer') friend.sayName(); // sy

    使用动态原型模式时,不能使用对象字面量重写原型。如果在已经创建了实例的情况下重写原型,那么就会切断现有实例与新原型之间的联系。

    1.6 寄生构造函数模式

    思想:创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象。

    function Person(name, age, job){
            var o = new Object();
            o.name = name;
            o.age = age;
            o.job = job;
            o.sayName = function(){
                console.log(this.name);
            };
            return o; 
    }
    var friend = new Person("Nicholas", 29, "Software Engineer");
    friend.sayName();  //"Nicholas"    

    1.7 稳妥构造函数模式

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

    function Person(name, age, job){
        // 创建要返回的对象
        var o = new Object();
    
        // 可以在这里定义私有变量和函数
    
        // 添加方法
        o.sayName = function() {
            console.log(name)
        }
        // 返回对象
        return o; 
    }
    var friend = new Person("Nicholas", 29, "Software Engineer");
    friend.sayName();  //"Nicholas"    
  • 相关阅读:
    给窗体加个圣诞帽——抛砖引玉
    《高手寂寞》随感
    离职日记-计划与变化
    什么样的生活
    这一年……
    写在2011第一天的工作前
    Visual C++ 学习笔记四 —— 模板
    bugfree安装与配置
    QTP环境变量的使用
    测试提问单[转]
  • 原文地址:https://www.cnblogs.com/songya/p/11488887.html
Copyright © 2020-2023  润新知