JavaScript 语言精粹 笔记-第三章:对象

173 阅读5分钟

对象字面量

  • 一个对象字面量就是由一对花括号以及括号中的零或多个 “名/值” 对组成的整体。其中,逗号用于分割多个 “名/值” 对。

    var a = {
       "first-name": "Bar",
       first_name: 'Foo'
    }
    

    在上述代码块中,等号右边的就是对象字面量。

  • JavaScript 对属性名没有任何要求,属性名不需要遵守标识符的规范。比如,虽然下述代码的属性名出现了保留字和空字符串这些看似不合理的名字,但代码是可以正常运行的。然而,在开发中,还是尽量按照标识符的规范去写。

    var b = {
      var: 1,
      let: 2,
      if: 3,
      switch: 4,
      break: 5,
      '': 6
    } 
    
    • 如果属性名不合法,则必须使用引号括住属性名,如"first-name"的引号是必需的。而对于合法的属性名,引号是可选的,如first_name

      注意:在JavaScript 中,标识符中包含连接符(-)是不合法的,但允许包含下划线(_)。另外,虽然书中提到“在对象字面量中,如果属性名是一个合法的 JavaScript 标识符且不是保留字,则并不强制要求用引号括住属性名。”,但实际上,保留字也是可以不用引号括住属性名的,如上述代码所示。

    • 属性的值可以是另一个对象字面量,也就是说,对象是可嵌套的,比如:

      var aa = {
        bb: {
          cc: 1
        }
      }
      

检索

  • 检索,可以简单理解为获取。

  • 在 JavaScript 中,有两种检索属性值的方式,一种是点(.)表示法,另一种是使用 [] 括住带引号的属性名。其语法如下:

    • 对象.属性名
    • 对象["属性名"]

    对于合法的属性名,两种方式都可以;对于非法的属性名,必须通过 []。

  • 如果尝试检索对象中一个不存在的属性的值,将返回 undefined

  • 可以使用 || 运算符填充默认值,防止返回 undefined

  • 尝试检索 undefined 的属性的值将会导致 TypeError 异常。

更新

  • 通过赋值语句,可以更新一个对象中某个属性的值,也可以为该对象新增一个属性。比如
    • 更新:a["first-name"] = Cat
    • 新增:a.second_name = Dog

引用

  • 在 JavaScript 中,对象通过引用来传递。它们永远不会被复制:
    var x = a;
    x.first_name = 'HHH'
    var y = a.first_name; 
    // 因为 x 和 y 是指向同一个对象的引用,所以 y 也为 'HHH'
    
    var d = {}, e = {}, f = {}; // d、e 和 f 都引用了一个不同的空对象。
    d = e = f = {}; // d、e 和 f 都引用同一个空对象
    

原型

  • 每个对象都会连接到一个原型对象,并且可以从中继承属性。在通过对象字面量创建一个新对象时,该对象会连接到Object.prototype,它是 JavaScript 中的标配对象。如果不想让对象连接到Object.prototype,也可以选择另一个对象作为它的原型。

  • 原型连接,就是将一个对象连接到另一个原型对象上,连接的桥梁就是 prototype 属性。通过原型连接,形成一条查找属性的规则:如果要获取对象的某个属性值,但该对象无此属性,那么 JavaScript 会试着从原型对象中获取属性值。如果也没有,那么会再从它的原型中寻找,依此类推,直到该过程最后到达终点 Object.prototype。如果终点也不存在,那么结果就是 undefined 值。这个过程称为委托

  • 原型关系是一种动态的关系。如果我们添加一个新的属性到原型中,该属性会立即对所有基于该原型创建的对象可见。

反射

  • typeof 操作符可确定属性的类型,它会返回属性类型的字符串形式,比如:
    typeof 1   // 'number'
    typeof 'str'  // 'string'
    
  • 通过对象.hasOwnProperty('属性名')可判断属性是否是对象独有的而不是原型上的,如果是独有的则返回true

枚举

  • 通过 for in 可枚举一个对象中所有的属性名,包括不需要使用的函数和原型中的属性。如果想过滤掉它们,可通过 hasOwnProperty 方法选择非原型中的属性,以及使用 typeof 来排除函数。
    • 属性出现的顺序是不确定的,如果要确保属性以特定的顺序出现,最好的方法就是用 for 代替 for in,并创建一个包含按顺序排列的属性名的数组:
      var i;
      var p = ['a', 'b', 'c'];
      for (i = 0; i < p.length; i += 1) {
          ...
      }
      

删除

  • delete 运算符可以用来删除对象的属性。如果对象包含该属性,那么该属性就会被移除,其语法如下:

    delete 对象.属性名delete对象["属性名"]

  • 删除对象的属性可能会让来自原型链中的属性透现出来。

减少全局变量污染

  • 随意定义全局变量可能会导致出现同名变量,从而造成全局变量污染的问题。为减少污染,可以只创建一个唯一的全局变量:

    var MYAPP = {};

    该变量就变成了你的容器,可以随意在容器中添加资源:

    MYAPP.a = {
        b: 1,
        c: 2
    }
    MYAPP.b = {
        ...
    }
    

    现在只需要把全局性的资源都纳入到这个名称空间下,程序与其它程序、组件或类库之间发生冲突的可能性就会显著降低,程序的易读性也会更强。