对象

195 阅读4分钟

类型

javascript中一共有六种主要类型:number,string,boolean,null,undefined,object。但注意,简单基本类型本身并不是对象,null有时会被当成一种对象类型,但这其实是语言的一个bug,它本质上是基本类型。

内置对象

javascript中还有些内置对象:String,Number,Boolean,Object,Function,Array,Date,RegExp,Error。它们实际上是一些内置函数,可以被当作构造函数来使用,从而构造一个对应子类型的新对象。

内容

对象的内容是由一些存储在特定命名位置的值组成的,称之为属性,但它们实际上并不是被直接存储在对象容器内部的,存储在对象容器内部的是这些属性的名称,它们指向这些值真正的存储位置

        var myObject = {
            a: 2
        }
        myObject.a; // 2
        myObject[a]; // 2

.a的语法称之为属性访问,[a]的语法称之为键访问,两种语法的主要区别在于,. 操作符要求属性名满足标识符的命名规范,[...]的语法则不用

在对象中,属性名永远是字符串

属性和方法

函数永远不会属于一个对象,函数和对象的关系最多只能说是间接关系,即使是属性访问返回的函数(方法)也和其他函数没有任何区别(除了可能发生的隐式绑定this),举例!

        function foo(){
            console.log("foo");
        }
        var someFoo=foo;
        var myObject={
            someFoo:foo
        }
        foo; // function foo(){...}
        someFoo; // function foo(){...}
        myObject.someFoo; // function foo(){...}

someFoo和myObject.someFoo只是对于同一个函数的不同引用,并不能说明这个函数属于某个对象,即使是在对象内部声明一个函数表达式,这个函数也不会属于这个对象,它们只是对同一个函数对象的多个引用

        var myObject={
            foo:function(){
                console.log("foo");
            }
        }
        var someFoo=myObject.foo;
        someFoo; // function foo(){...}
        myObject.foo; // function foo(){...}

数组

数组也支持[]访问形式,数组期望的是数值下标,也就是索引,数组也是对象,虽然每个下标都是整数,但仍然可以给数组添加属性,所以完全可以把数组当成普通的键值对对象来使用,但这不是个好主意

注意:如果给数组添加属性但属性名看起来像一个数字,那么它会变成数值下标,举例!

        var myArray = ["foo", "42", "bar"];
        myArray["3"] = "baz";
        console.log(myArray.length); // 4
        console.log(myArray[3]); // baz

复制对象

浅拷贝:只复制引用,没有复制真正的值。两个都同时指向了一个空间,如果改变其中一个,另一个也会发生变化。(有点类似于新增了一个快捷方式,指向的地址是同一个)

浅拷贝可用Object.assign()方法实现

深拷贝:内存中开辟了一块内存地址用于存放复制的对象,两个指向不同的空间,如果改变其中一个,另一个也不会受影响

深拷贝可用递归实现

属性描述符

举例!

        var myObject = {
            a: 2
        }
        Object.getOwnPropertyDescriptor(myObject,"a");
              //configurable: true
              //enumerable: true
              //value: 2
              //writable: true

创建普通属性时属性描述符会使用默认值,也可以用Object.defineProperty来新增或修改属性并对特性进行配置,举例!

        var myObject = {}
        Object.defineProperty(myObject, "a", {
            value: 2,
            writable: true,
            configurable: true,
            enumerable: true
        })
        myObject.a // 2

下面介绍一下几个属性描述符

  1. writable:决定是否可以修改值
  2. configurable:决定属性是否可以配置,注意!把它修改成false是单向操作,不可撤销!连“删除”属性都会被禁止
  3. enumerable:决定属性是否会出现在对象的属性枚举中,比如for...in循环

不变性

有时候会希望属性或者对象是不可改变的,可以用这些方法实现

1.对象常量

结合writable: falseconfigurable: false,就可以创建一个常量属性(不可修改,重定义或者删除)

2.禁止扩展

如果想禁止一个对象添加新属性并且保留已有属性,可以使用Object.preventExtensions()方法

        var myObject = {
            a: 2
        }
        Object.preventExtensions(myObject)
        myObject.b = 3;
        console.log(myObject.b); // undefined

3.密封

Object.seal()会创建一个“密封”的对象,这个方法实质上是在现有对象上调用Object.preventExtensions()方法并把现有属性标记为configurable: false,这样不仅不能添加新属性,也不能配置或者删除任何现有属性(虽然可以修改属性的值)

4.冻结

Object.freeze()会创建一个冻结对象,这个方法实质上是在现有对象上调用Object.seal(),并把所有数据访问属性标记为writable: false,这样就无法修改它们的值

[[GET]]和[[PUT]]

访问属性时,引擎会调用内部的默认[[GET]]操作(在设置属性值时是[[PUT]]),[[GET]]操作会检查对象本身是否包含这个属性,没找到会查找[[prototype]]原型链