牛骨文教育服务平台(让学习变的简单)

面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript中并没有类的概念,所以它的对象也有有所不同。

ECMAScript对象是一个无序属性的集合,其属性可以包含基本值、对象或函数。

对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。

每个对象都是基于一个引用类型创建的。

1、对象

1.1 创建对象

(1)创建自定义对象的最简单方式就是创建一个Object的实例,然后给其添加属性和方法:

var person = new Object();
person.name = "tg";
person.age = 10;
person.say = function(){
   console.log(this.name);
}

上面的例子创建了一个名为person的对象,并为它添加了两个属性(name、age)和一个方法(say())。

(2)对象字面量

var person = {
  name: "tg",
  age: 10,
  say: function(){
   console.log(this.name);
  }
}

这个person对象和上面例子是等价的。

1.2 属性类型

ECMA-262第5版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征。ECMA-262定义这些特性是为了实现JavaScript引擎用的,因此在JavaScript中不能直接访问它们。该规范将它们放在了两对方括号中,表示特性是内部值,如[[Enumerable]]。

ECMAScript中有两种属性:数据属性和访问权属性

1.2.1 数据属性

数据属性包含一个数据值的位置,在这个位置可以读取和写入值。

数据属性有4个描述特性:

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。比如直接在对象上定义的属性,它们的这个特性默认值为true。
  • [[Enumerable]]:表示能否通过for-in循环返回属性。对于直接在对象上定义的值,默认为true。
  • [[Writable]]:表示能否修改属性的值。
  • [[Value]]: 包含这个属性的数据值。读取属性值时,从这个位置读;写入属性值时,把新值保存在这个位置。默认值为undefined。

要修改属性默认的特性,必须使用ECMAScript 5的Object.defineProperty()方法,这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符对象的属性必须是:configurable、enumerable、writable和value。

var person = {};
Object.defineProperty(person, "name", {
  writable: false,
  value: "tg"
});

console.log(person.name);  // "tg"
person.name = "tg2";
console.log(person.name);  //  "tg"

在上面的例子中,我们将person对象中的名为name的属性的writable设置为false,也就是不可修改,所以即使后面执行了person.name="tg2",最后person对象的name值依旧是原始值。

注意:在严格模式下,如果对一个不可修改的属性执行赋值操作,会抛出错误;非严格模式下则忽略赋值操作。

一旦将configurable特性设置为false后,就不能再把它变回可配置的了,如果再修改除writable之外的特性,都会导致错误。

1.2.2 访问器属性

访问器属性不包含数据值,它们包含一对getter和setter函数(非必需)。在读取访问器属性时,会调用getter函数,返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,它负责决定如何处理数据。

访问器属性:

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。比如直接在对象上定义的属性,它们的这个特性默认值为true。
  • [[Enumerable]]:表示能否通过for-in循环返回属性。对于直接在对象上定义的值,默认为true。
  • [[Get]]:在读取属性时调用的函数,默认为undefined
  • [[Set]]:在写入属性时调用的函数,默认为undefined

访问器属性不能直接定义,也是要使用Object.defineProperty()方法来定义。

var person = {
  _age: 20,
  intro: ""
};
Object.defineProperty(person, "age", {
  get: function() {
    return this._age;
  },
  set: function(newValue){
    if(newValue < 18) {
      this.intro = "装嫩";
      this._age = newValue;
    }
  }
});

console.log(person.age);  // 20
person.age = 17; 
console.log(person.intro);  // "装嫩"

在上面的例子中,访问器属性age有一个getter函数和一个setter函数。getter函数返回_age的值,setter函数通过判断age的设置值来改变其他属性值。

1.2.3 定义多个属性

ECMAScript 5提供的Object.defineProperties()方法可以通过描述符一次定义多个属性,这个方法接收两个对象参数,第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象要添加或修改的属性一一对应。

var person = {};
Object.defineProperties(person, {
  _age: {
    value: 20
  },
  intro: {
    value: ""
  },
  age: {
    get: function(){
      return this._age;
    },
    set: function(newValue){
      if(newValue < 18) {
        this.intro = "装嫩";
        this._age = newValue;
      }
    }
  }
});

1.2.4 读取属性的特性

ECMAScript 5提供的Object.getOwnPropertyDescriptor()方法可以取得给定属性的描述符,它接受两个参数:属性所在的对象和要读取其描述符的属性名称,返回来的是一个对象,如果是访问器属性,这个对象的属性有configurable、enumerable、get和set;如果是数据属性,这个对象的属性有configurable、enumerable、writable和value。

var person = {
  _age: 20,
  intro: ""
};
Object.defineProperty(person, "age", {
  get: function() {
    return this._age;
  },
  set: function(newValue){
    if(newValue < 18) {
      this.intro = "装嫩";
      this._age = newValue;
    }
  }
});
var descriptor = Object.getOwnPropertyDescriptor(person,"age");

console.log(descriptor.enumerable);  // false
console.log(typeof descriptor.get);  // "function"

在JavaScript中,可以针对任何对象--包括DOM和BOM对象,使用Object.getOwnPropertyDescriptor()方法。