Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Object

1. 静态方法

Object 是最基础的对象,其他所有对象都继承自它

可以直接通过 Object.方法名 调用,故为静态方法

属性相关

  • .keys()

    • 获取对象自身的属性键(不包括继承的),返回一个数组
      print(Object.keys(obj)); // ["key1", "key2"]
      
      • 只返回可枚举的属性,最常用,用来计算对象属性个数
  • .getOwnPropertyNames()

    • 获取对象自身的属性键(不包括继承的),返回一个数组
      print(Object.getOwnPropertyNames(obj)); // ["key1", "key2"]
      print(Object.getOwnPropertyNames(arr)); // ["0", "1", "length"]
      
      • 会同时返回不可枚举的,比如 length
  • .values()

    • es8 新增,可遍历对象的值
    • 作用于对象
      let obj = { x: "123", y: 1 };
      let values = Object.values(obj); // ['123', 1]
      
    • 作用于数字键对象,会按键的升序导出
      const obj = { 10: "xxx", 1: "yyy", 3: "zzz" };
      Object.values(obj); // ['yyy', 'zzz', 'xxx']
      
    • 作用于字符串
      let values = Object.values("es8"); // ['e', 's', '8']
      
  • .entries()

    • es8 新增,可遍历对象的键和值,二者拼成数组,再作为大数组的一个元素
    • 作用于对象
      const obj = { x: "123", y: 1 };
      Object.entries(obj); // [['x', '123'], ['y', 1]]
      

原型链相关

  • .create()

    • es6 新增,可使用现有对象 proto 来提供原型信息,从而创建一个新对象

      newObj = Object.create(proto, [propertiesObject]);
      
    • 参数

      • proto 必选
        • 表示新对象的原型对象,即该对象会被复制到新对象的原型上
        • 可填值
          • 另一个对象,或者函数的 prototype 属性
          • 创建空对象时可以传 null
      • propertiesObject 可选
        • 表示添加到新对象的可枚举属性(即其自身的属性,而不是原型链上的枚举属性)
        • 对应 Object.defineProperties()的第二个参数
    • 下面通过几个案例,说明这种创建方式,与原有的构造函数创建,有何不同

    • 案例 1

      • 在 es6 之前,如果通过构造函数创建,会直接添加到实例下面
        let a = { rep: "apple" };
        let b = new Object(a);
        console.log(b); // {rep: "apple"}
        console.log(b.__proto__); // {}
        console.log(b.rep); // {rep: "apple"}
        
        • 这里最终能输出,是因为自身实例就有
      • es6 出现后,通过.create()创建,可以添加到原型下面
        var a = { rep: "apple" };
        var b = Object.create(a);
        console.log(b); // {}
        console.log(b.__proto__); // {rep: "apple"}
        console.log(b.rep); // {rep: "apple"}
        
        • 这里最终能输出,是向上追溯原型链得到的
    • 案例 2

      • 在 es6 之前,如果通过构造函数创建,需要自己一个个地补充原型
        let People = function () {};
        People.prototype.y = 20;
        People.prototype.showNum = function () {};
        let p = new People();
        
        • 如果我们检查,会发现 p.__proto__的值就是People.prototype
      • es6 出现后,通过.create()创建,可以直接先写个对象,然后当成原型使用
        let proto = {
          y: 20,
          z: 40,
          showNum() {},
        };
        let o = Object.create(proto);
        
        • 这时候,p.__proto__的值就是 proto,方便多了
    • 案例 3

      • 创建一个 以空对象为原型,且拥有一个 p 实例属性(但此属性默认不可被循环枚举)的新对象
        o = Object.create({}, { p: { value: 42 } });
        o.p = 24;
        console.log(o.p); //输出42
        o.q = 12;
        for (var prop in o) {
          console.log(prop); //输出"q"
        }
        console.log(o.__proto__); //输出{}
        
        • 上面出现这些输出,是因为
          • 默认可枚举属性描述符全为 false,不可写,不可枚举,不可配置
          • 对象的原型属性,就是创建时给的{}
        • 如果通过字面量方法或者 new 创建
          • 则描述符全为 true
          • 对象的原型属性是有的,而且是 Object(或者是构造函数.prototype)
  • .setPrototypeOf()

    • es6 新增,可以给现有对象 obj,添加一个新的原型
      Object.setPrototypeOf(obj, proto);
      
      • 以前是通过给__proto__属性赋值实现的,但兼容性不好,只有浏览器要部署,其他环境不用部署
  • .getPrototypeOf()

    • es6 新增,可以读取现有对象 obj 的原型

      Object.getPrototypeOf(obj);
      
      • 以前是直接读取__proto__属性实现,但兼容性不好,只有浏览器要部署,其他环境不用部署
    • 案例 1

      • es6 之前,直接.assign()是拷贝不到原型上面的方法的

        let triangle = { x: 1 };
        function ColoredTriangle() {
          this.color = "red";
        }
        Object.assign(ColoredTriangle.prototype, triangle);
        let c = new ColoredTriangle();
        Object.defineProperty(c, "colorGet", {
          enumerable: true, // 设为可枚举,不然 Object.assign 方法会过滤该属性
          get() {
            return "Could it return " + this.color;
          },
        });
        
        let c2 = Object.assign({}, c);
        console.log(c2.x); //undefined
        
        • 这里拷贝的时候,把原型上面的属性和方法都弄丢了
      • es6 出现后,通过.getPrototypeOf()可以拿到原型,使得原型的拷贝成为可能

        let originProto = Object.getPrototypeOf(c);
        let objWithProto = Object.create(originProto);
        var c2 = Object.assign(objWithProto, c);
        console.log(c2.x); // 1
        
        • 这样就不会弄丢了
      • 其实上面的拷贝还有弊端,就是还是无法拷贝到可枚举属性中的 get 描述符,这就需要用到.getOwnPropertyDescriptors()

        let originProto = Object.getPrototypeOf(c);
        let c2 = Object.create(originProto, Object.getOwnPropertyDescriptors(c));
        

2. 原型方法

是通过Object.prototype.方法名挂载上去的,故为原型方法

需要用过对象实例.方法名来调用

  • .prototype.valueOf()

    • 返回当前对象对应的值
    • 一般用在自动类型转换中
  • .prototype.toString()

    • 返回当前对象对应的字符串形式
    • 一般用在自动类型转换中
    • 也常用来判断一个值的类型名
      Object.prototype.toString.call(值);
      
      • 会返回[object 类型名]
  • .prototype.toLocaleString()

    • 返回当前对象对应的本地字符串形式
  • .prototype.hasOwnProperty()

    • 判断某个属性是否为自身的属性(而不是继承的)
  • .prototype.isPrototypeOf()

    • 判断当前对象是否为另一个对象的原型
  • .prototype.propertyIsEnumerable()

    • 判断某个属性是否可枚举