面向对象编程 -- 理解对象1

// 创建自定义对象的通常方式是创建 Object 的一个新实例,然后再给它添加属性和方法。

let person = new Object();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer";
           
person.sayName = function() {
  console.log(this.name);
};

创建自定义对象 01.png

// 前面的例子如果使用对象字面量则可以这样写:

let person = {
  name: "Nicholas",
  age: 29,
  job: "Software Engineer",
  sayName() {
    console.log(this.name);
  }
};

创建自定义对象2 02.png

一、属性的类型

// ECMA-262 使用一些内部特性来描述属性的特征。

// 为了将某个特性标识为内部特性,规范会用两个中括号把特性的名称括起来,比如[[Enumerable]]。

// 属性分两种:数据属性和访问器属性。

1.数据属性

// 数据属性包含一个保存数据值的位置。

// 数据属性有4个特性描述他们的行为。

1.[[Configurable]]:表示属性是否可以通过 delete 删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。

2.[[Enumberable]]:表示属性是否可以通过 for-in 循环返回。

3.[[writable]]:表示属性的值是否可以被修改。

4.[[Value]]:包含属性实际的值。


let person = {};
Object.defineProperty(person, "name", {
  writable: false,
  value: "Nicholas"
});
console.log(person.name);  // "Nicholas"!
person.name = "Greg";
console.log(person.name);  // "Nicholas"

数据属性 03.png

// 类似的规则也适用于创建不可配置的属性。

let person = {};
Object.defineProperty(person, "name", {
  configurable: false,
  value: "Nicholas"
});
console.log(person.name);  // "Nicholas"
delete person.name;
console.log(person.name);  // "Nicholas"
// 一个属性被定义为不可配置之后,就不能再变回可配置的了。

let person = {};
Object.defineProperty(person, "name", {
  configurable: false,
  value: "Nicholas"
});

// Throws an error
Object.defineProperty(person, "name", {
  configurable: true,
  value: "Nicholas"
});

数据属性2 04.png

2.访问器属性

// 访问器属性不包含数据值。

// 访问器属性有4个特性描述他们的行为。

1.[[Configurable]]:表示属性是否可以通过 delete 删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。

2.[[Enumberable]]:表示属性是否可以通过 for-in 循环返回。

3.[[Get]]: 获取函数,在读取属性时调用。

4.[[Set]]: 设置函数,在写入属性时调用。


let book = {
  year_: 2017,
  edition: 1
};
  
Object.defineProperty(book, "year", {
  get() {
    return this.year_;
  },
  set(newValue) {
    if (newValue > 2017) {
      this.year_ = newValue;
      this.edition += newValue - 2017;
    }
  }
});
book.year = 2018;
console.log(book.edition);  // 2

定义多个属性 05.png

二、定义多个属性

// 在一个对象上同时定义多个属性的可能性是非常大的。

let book = {};
Object.defineProperties(book, {
  	year_: {
  	  writable:true,
      value: 2017
	},
    edition: {
    	writable:true,
        value: 1
    },
    
    year: {
      get() {
        return this.year_;
      },
      set(newValue) {
        if (newValue > 2017) {
          this.year_ = newValue;
          this.edition += newValue - 2017;
        }
      }
    },
});

定义多个属性 06.png

三、读取属性的特性

// 使用 Object.getOwnPropertyDescriptor() 方法可以取得指定属性的属性描述符。

let book = {};
Object.defineProperties(book, {
  	year_: {
  	  writable:true,
      value: 2017
	},
    edition: {
    	writable:true,
        value: 1
    },
    
    year: {
      get() {
        return this.year_;
      },
      set(newValue) {
        if (newValue > 2017) {
          this.year_ = newValue;
          this.edition += newValue - 2017;
        }
      }
    },
});

let descriptor = Object.getOwnPropertyDescriptor(book, "year_");
console.log(descriptor.value);		// 2017
console.log(descriptor.configurable);	// false
console.log(typeof descriptor.get);		// undefined
let descriptor2 = Object.getOwnPropertyDescriptor(book, "year");
console.log(descriptor2.value);		// undefined
console.log(descriptor2.configurable);	// false
console.log(typeof descriptor2.get);		// function

读取属性的特性 07.png

// ECMAScript 2017 新增了 Object.getOwnPropertyDescriptors()静态方法。

let book = {};
Object.defineProperties(book, {
  	year_: {
  	  writable:true,
      value: 2017
	},
    edition: {
    	writable:true,
        value: 1
    },
    
    year: {
      get() {
        return this.year_;
      },
      set(newValue) {
        if (newValue > 2017) {
          this.year_ = newValue;
          this.edition += newValue - 2017;
        }
      }
    },
});

console.log(Object.getOwnPropertyDescriptors(book));

读取属性的特性 08.png

博文查考

JavaScript 高级程序设计(第4版) --【美】马特.弗里斯比 著