Javascript中理解并创建对象

理解对象

简单来说,对象是键值对的集合。
属性类型:数据属性,访问器属性。

  1. 数据属性:Configurable,Enumerable,Writable,Value
    configurable:是否能通过delete删除该属性,对象上定义的属性默认为true.
    enumerable:是否可通过for-in枚举,对象上定义的属性默认为true.
    writable:是否可修改,对象上定义的属性默认为true。
    value:这个属性的值,默认undefined。
    修改属性默认的特性:Object.defineProperty(对象,属性,描述符对象)

    Object.defineProperty(person, 'name', {
      writable: false,
      value: 'Li'
    })
    

    注意:将configurable配置为false之后,不能delete它,也不能修改 它,并且不能将它在改为true了。在调用object.defineProperty()方法,如果不指定configurable、writable、enumerable的值,默认为false。

  2. 访问器属性:getter,setter(非必须)
    configurable: 同数据属性。
    enumerable: 同数据属性。
    get:在读取访问器属性的时候会调用这个函数。
    set:在写入访问器属性的时候会调用这个函数。

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

    注:_year前面的下划线是一种常用的记号,表示只能通过对象方法访问的属性

    Object.defineProperties(book, 对应属性的描述符对象)
    Object.getOwnPropertyDescriptor(book, "_year"),该方法只能用于实例属性

创建对象

创建单个对象: 对象字面量/构造函数
创建多个对象

  1. 工厂模式

    function createPerson(name, age) {
      var o = new Object();
      o.name = name;
      o.age = age;
      o.sayName = function() {
        alert(this.name)
      }
      return o
    }
    var person1 = createPerson('Li', 23);
    var person2 = createPerson('Di', 13);
    

    优点:可以快速的创建多个相似的对象;
    缺点:无法知道一个对象的类型(对象识别)。

  2. 自定义构造函数

    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.sayName = function() {
        alert(this.name)
      }
    }
    var person1 = new Person('Li', 23);
    var person2 = new Person('Di', 13);
    

    new操作符
    a. 创建一个新对象;
    b. 设置原型链(将新对象的__proto__指向函数的prototype) ;
    c. 将构造函数的作用域赋给新对象(绑定this);
    d. 执行构造函数的代码(为新对象添加属性);
    e. 返回新对象。

    可以用instanceof检测person1和person2的类型
    person1 instanceof Person => true
    person1 instanceof Object => true

    优点:对象类型识别
    缺点:每个对象都有单独的sayName函数实例,这个不必要。

  3. 原型模式

    function Person() {
    }
    Person.prototype.name = 'Li';
    Person.prototype.age = 31;
    Person.prototype.sayName = function() {
      alert(this.name)
    }
    
    var person1 = new Person();
    var person2 = new Person();
    
    

    person1和person2共享所有的属性和方法。

    关于prototype和__proto
    Person.prototype.constructor 指向 Person
    person1.__proto__ 指向 Person.prototype
    Person.prototype.isPrototypeOf(person1) 指向 true
    Object.getPrototypeOf(person1) == Person.prototype
    Object.getPrototypeOf(person1).name 值为:"Li"

    读取对象的某个属性的时候,先在对象实例本身读取,如果没有找到,则去原型对象上去找,如果还没有找到,则沿着原型链继续往上找。
    可以通过person1.hasOwnProperty("age")来检测该属性是否是实例上的属性。
    操作符in: `alert("name" in person1) 不管是实例属性还是原型上的属性都返回true.
    in配合hasOwnProperty()可以检测属性是否是原型属性:

    function hasProtoProperty(object, name) {
      return !object.hasOwnProperty(name) && (name in object)
    }
    

    for-in:返回所有可枚举的属性(enumerable为true),包括实例上的以及原型对象上的。属性没有顺序。如果属性值为undefined或是null会抛出错误或不执行,所以建议先判断。

    Object.keys(person1)获取对象上所有可枚举的实例属性。返回数组。
    Object.getOwnPropertyNames(person1)获取对象上的所有实例属性,不论是否可以枚举。返回数组。

    调用构造函数会为实例添加一个指向最初原型(prototype)的指针(__proto__),如果在调用构造函数之后重新定义prototype,则会切断这个指针,即person.proto不再指向Person.prototype了。

    可以在原生对象(String/Number/Array/……)的原型上添加方法,但是不推荐。

    缺点:所有实例共享属性和方法,属性值不够灵活(当属性值为引用值的时候)

  4. 组合使用自定义构造函数和原型模式
    通过自定义构造函数定义实例属性,原型模式定义共享的属性和方法

    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    Person.prototype.sayName = function() {
      alert(this.name)
    }
    
    var person1 = new Person("Li", 12);
    var person2 = new Person("Di", 24);
    
  5. 动态原型模式

    function Person(name, age) {
     this.name = name;
     this.age = age;
     // 一下这段代码只在初次调用构造函数的时候执行
     if(typeof this.sayName != "function") {
       Person.prototype.sayName = function() {
         alert(this.name)
       }
     }
    }
    
    var person1 = new Person("Li", 12);
    var person2 = new Person("Di", 24);
    
  6. 寄生构造函数模式
    类似工厂模式,建议在特殊情况下使用。

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

  var person1 = new Person("Li", 12);
  var person2 = new Person("Di", 24);
  1. 稳妥构造函数模式
    稳妥对象:没有公共属性,方法也不引用this对象。在安全的环境中使用。

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

你可能感兴趣的:(Javascript中理解并创建对象)