JavaScript 对象&设计模式

js 对象&设计模式

对象

  1. 概念

无序属性的集合,其属性可以包含基本值、对象或者函数。”严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射 到一个值。正因为这样,我们可以把对象想象成散列表: 无非就是一组名值对,其中值可以是数据或函数。

  1. 对象的属性

数据属性:

  • [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。默认值为 true。

  • [[Enumerable]]:表示能否通过 for-in 循环返回属性。默认值为 true。

  • [[Writable]]:表示能否修改属性的值。默认值为 true

  • [[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读; 写入属性值的时候,把新值保存在这个位置。这个特性的默认值为 undefined。

修改属性默认的特性: Object.defineProperty()方法

这个方法 接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属 性必须是:configurable、enumerable、writable 和 value。设置其中的一或多个值,可以修改 对应的特性值。

    var person = {};
    Object.defineProperty(person, "name", {
        writable: false,
        value: "Nicholas"
    });
    alert(person.name); //"Nicholas" 
    person.name = "Greg"; 
    alert(person.name); //"Nicholas"

访问器属性:

在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下 4 个特性

  • [[Configurable]]

  • [[Enumerable]]

  • [[Get]]:在读取属性时调用的函数。默认值为 undefined。

  • [[Set]]:在写入属性时调用的函数。默认值为 undefined。

访问器属性不能直接定义,必须通过 Object.defineProperty() 方法来定义

    var book = {
        _year: 2004,
        edition: 1 
        };
    Object.defineProperty(book, "year", {
        get: function(){
            return this._year;
        },
        set: function(newValue){
            if (newValue > 2004) {
                this._year = newValue;
                this.edition += newValue - 2004;
    } }
    });
    book.year = 2005; alert(book.edition); //2

不一定非要同时指定 getter 和 setter。只指定 getter 意味着属性是不能写,尝试写入属性会被忽略。 在严格模式下,尝试写入只指定了 getter 函数的属性会抛出错误。类似地,只指定 setter 函数的属性也 不能读,否则在非严格模式下会返回 undefined,而在严格模式下会抛出错误。

Object.defineProperties()方法:

利用这个方法可以通过描述符一次定义多个属性。这个方法接收两个对象参数:第一 个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应。例如:

    var book = {};
        Object.defineProperties(book, {
            _year: {
                value: 2004
            },
            edition: {
                value: 1
            },
            year: {
                get: function(){
                        return this._year;
                    },
                set: function(newValue){
                    if (newValue > 2004) {
                        this._year = newValue;
                        this.edition += newValue - 2004;
                    }
            } }
        });

Object.getOwnPropertyDescriptor()方法:

可以取得给定属性的描述 符。这个方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。返回值是一个对象,如果 是访问器属性,这个对象的属性有 configurable、enumerable、get 和 set;如果是数据属性,这 个对象的属性有 configurable、enumerable、writable 和 value。

设计模式


1. Object 构造函数/对象字面量,缺点:使用同一个接口创建多个对象,会产生大量重复的代码。

2. 工厂模式

    function createPerson(name, age, job){
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function(){
            alert(this.name);
        };
        return o; 
    }

    这种模式抽象了创建具体对象的过程,用函数来封装以特定接口来创建对象的细节。解决了创建多个相似对象的问题,却没有解决对象的识别问题,即怎样知道一个对象的类型。

2. 构造函数模式

    function Person(name, age, job){
            this.name = name;
            this.age = age;
            this.job = job;
            this.sayName = function(){
                alert(this.name);
            }; 
    }

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

    要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4 个步骤:
    (1) 创建一个新对象;
    (2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
    (3) 执行构造函数中的代码(为这个新对象添加属性);
    (4) 返回新对象。

    可以将构造函数的名称当作一种特定的类型,这是比工厂模式好的地方。

    缺点:每个方法都要在每个实例上重新创建一遍
    改进:

    function Person(name, age, job){
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = sayName;
    }
    function sayName(){
        alert(this.name);
    }

3. 原型模式

    function Person(){}
    Person.prototype.name = "Nicholas";
    Person.prototype.age = 29;
    Person.prototype.job = "Software Engineer";
    Person.prototype.sayName = function(){
        alert(this.name);
    };

    好处:可以让所有对象实例共享它所包含的属性和方法,不必在构造函数中定义对象实例的信息。

    缺点:

    1) 所有实例在默认情况下都会取得相同的默认值。

    2) 如果原型中包含引用型数据,当实例修改时,所有实例都会发生变化。

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

    function Person(name, age, job){
        this.name = name; 
        this.age = age;
        this.job = job;
        this.friends = ["Shelby", "Court"];
    }
    Person.prototype = {
        constructor : Person,
        sayName : function(){
            alert(this.name);
        }
    }

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

5. 动态原型模式

    function Person(name, age, job){
        //属性
        this.name = name; 
        this.age = age; 
        this.job = job;
        //方法
        if (typeof this.sayName != "function"){
            Person.prototype.sayName = function(){
                alert(this.name);
            }; 
        }
    }







猜你喜欢

转载自blog.csdn.net/weixin_42186513/article/details/83213643