Skip to content
目录

JS对象

  • 是一组属性的无序集合,内容是键值对

属性的类型

用内部特性来描述属性的特征

  • 数据属性(常规的属性),以下是内部特性
    • [[Configurable]]: 表示属性是否可以通过 delete 删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。默认情况下,所有直接定义在对象上的属性的这个特性都是 true
    • [[Enumerable]]: 表示属性是否可以通过 for-in 循环返回。默认情况下,所有直接定义在对象上的属性的这个特性都是 true
    • [[Writable]]: 表示属性的值是否可以被修改。默认情况下,所有直接定义在对象上的属性的这个特性都是 true
    • [[Value]]: 包含属性实际的值
    • 修改属性的数据特征用Object.defineProperty(object,property,描述符对象):描述符对象比如 {writable: false,value: "Nicholas"},注意:把configurable设置成false之后就不能再用defineProperty()方法处理同一个属性,而且调用defineProperty(),如果没声明的数据特征会自动为false
  • 访问器属性:是一种特别的属性,没有值,包含一个获取(getter)函数和一个设置(setter)函数,。在读取访问器属性时,会调用获取函数,这个函数的责任就是返回一个有效的值。在写入访问器属性时,会调用设置函数并传入新值,这个函数必须决定对数据做出什么修改
    • 访问器属性有四个特性
      • [[Configurable]]
      • [[Enumerable]]
      • [[Get]]
      • [[Set]]
js
// 定义一个对象,包含伪私有成员 year_和公共成员 edition
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 相当于这个属性的设置可以更新对象中别的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

对象操作

  • 删除对象属性 delete obj.pro
  • 定义多个属性Object.defineProperties(obj,{描述符对象})
    比如{pro1:{描述符对象},pro2:{描述符对象}}
  • Object.getOwnPropertyDescriptor(obj,proName): 读取对象属性的特性,返回一个对象
  • Object.getOwnPropertyDescriptors(obj): 返回该对象每个自有属性的特性的对象集合
  • 合并对象-> Object.assign(目标对象,一个或多个源对象),是一种浅复制:然后将每个源对象中可枚举(obj.propertyIsEnumerable()返回 true)和自有(obj.hasOwnProperty()返回 true)属性复制到目标对象
    • 以字符串和符号为键的属性会被复制。对每个符合条件的属性,这个方法会使用源对象上的[[Get]]取得属性的值,然后使用目标对象上的[[Set]]设置属性的值
  • 对象标识及相等判定:Object.is(a,b)

增强的对象语法

ECMAScript 6 为定义和操作对象新增了很多极其有用的语法糖特性,这些特性都没有改变现有引擎的行为,但极大地提升了处理对象的方便程度

  • 属性值简写:如果属性名和变量名一样,可简写
  • 可计算属性:[]中括号包围起来的js表达式做对象字面量的属性
    • ES5中只能添加属性
      js
      const nameKey = 'name';
      const ageKey = 'age'; 
      const jobKey = 'job';
      let person = {};
      person[nameKey] = 'Matt';
      person[ageKey] = 27;
      person[jobKey] = 'Software engineer';
      
      1
      2
      3
      4
      5
      6
      7
    • 可计算属性与属性值简写不兼容
  • 简写方法名
    • 新的简写方法的语法遵循同样的模式,但开发者要放弃给函数表达式命名
    • 简写方法名对获取函数和设置函数也是适用的(新的语法糖:get set可以在对象字面量中直接定义比如let ob={a:5,get name(){},set name(){}};中定义了name属性(访问器属性)的get和set函数)
    • 简写方法名与可计算属性键相互兼容

对象解构

就是使用与对象匹配的结构来实现对象属性赋值, 一种新的赋值方式

js
// 使用对象解构
let person = {
name: 'Matt',
age: 27
};
let { name: personName, age: personAge } = person;
console.log(personName); // Matt
console.log(personAge); // 27 

let person = {//变量名跟属性名一样可进一步简写
name: 'Matt',
age: 27
};
let { name, age } = person;
console.log(name); // Matt
console.log(age); // 27 

let { name, job='Software engineer' } = person;//可设置默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 解构并不要求变量必须在解构表达式中声明。不过,如果是给事先声明的变量赋值,则赋值表达式必须包含在一对括号中

    js
    let personName, personAge;
    let person = {
    name: 'Matt',
    age: 27
    };
    ({name: personName, age: personAge} = person);
    
    1
    2
    3
    4
    5
    6
  • 嵌套解构:原理很简单

  • 部分解构:发生错误不回滚

  • 参数上下文匹配:在函数参数列表中也可以进行解构赋值。对参数的解构赋值不会影响 arguments 对象,但可以在函数签名中声明在函数体内使用局部变量

    js
    let person = {
    name: 'Matt',
    age: 27
    };
    function printPerson(foo, {name, age}, bar) {
    console.log(arguments);
    console.log(name, age);
    }
    function printPerson2(foo, {name: personName, age: personAge}, bar) {
    console.log(arguments);
    console.log(personName, personAge);
    }
    printPerson('1st', person, '2nd');
    // ['1st', { name: 'Matt', age: 27 }, '2nd']
    // 'Matt', 27
    printPerson2('1st', person, '2nd');
    // ['1st', { name: 'Matt', age: 27 }, '2nd']
    // 'Matt', 27
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

创建对象

  • ECMAScript 6 开始正式支持类和继承。ES6 的类旨在完全涵盖之前规范设计的基于原型的继承模式。不过,无论从哪方面看,ES6 的类都仅仅是封装了 ES5构造函数加原型继承的语法糖而已
  • 工厂模式:简单粗暴用new Object()创建空对象并手动赋值
  • 构造函数(构造函数名最好大写),定义后用new关键字
    js
    function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
    console.log(this.name);
    };
    }
    let person1 = new Person("Nicholas", 29, "Software Engineer");
    let person2 = new Person("Greg", 27, "Doctor");
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    • 新创建的对象的constructor属性指向构造函数,而且也是构造函数的实例,instanceof返回true
    • 这个新对象内部的[[Prototype]]特性被赋值为构造函数的 prototype 属性
    • 构造函数不一定要写成函数声明的形式。赋值给变量的函数表达式也可以表示构造函数
    • 构造函数也是函数
    • 构造函数的问题构造函数虽然有用,但也不是没有问题。构造函数的主要问题在于,其定义的方法会在每个实例上都创建一遍: 要解决这个问题,可以把函数定义转移到构造函数外部
  • 原型模式
    • 每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法(实际上,这个对象就是通过调用构造函数创建的实例对象的原型。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型)
    • 代办(红宝书p224)

Released under the MIT License.