Object对象的相关方法

1.Object.getPrototypeOf()

Object.getPrototypeOf方法返回参数对象的类型。这是获取原型对象的标准方法

    var F = function () { }
    var f = new F()
    console.log(Object.getPrototypeOf(f) === F.prototype) // true

上面代码中,实例对象f的原型是F.prototype。

下面是几种特殊对象的原型。

    // 空对象的原型是Object.prototype
    console.log(Object.getPrototypeOf({}) === Object.prototype)

    // Object.prototype的原型是null
    console.log(Object.getPrototypeOf(Object.prototype)) // null

    // 函数的原型是Function.prototype
    function f(){}
    console.log(Object.getPrototypeOf(f) === Function.prototype) // true

2.Object.setPrototypeOf()

Object.setPrototypeOf方法为参数对象设置原型,返回该参数对象。它接受两个参数,第一个是现有对象,第二个是原型对象。

    var a = {}
    var b = { x: 1 }
    Object.setPrototypeOf(a, b)
    console.log(Object.getPrototypeOf(a) === b) // true
    console.log(a.x)

上面代码中,Object.setPrototypeOf方法将对象a的原型,设置为对象b,因此a可以共享b的属性。

new命令可以使用Object.setPrototypeOf方法模拟。

    var F = function () {
      this.foo = 'bar'
    }

    var f = new F()

    console.log(f.constructor === F)

    // 等同于
    var f1 = Object.setPrototypeOf({},F.prototype)
    console.log(f1.constructor === F) // true
    F.call(f1)

上面代码中,new命令新建实例对象,其实可以分成两步。第一步,将一个空对象的原型设为构造函数的prototype属性(上例为F.prototype);第二步,将构造函数内部的this绑定这个空对象,然后执行构造函数,使得定义在this上面的方法和属性(上例是this.foo),都转移到这个空对象上。

3.Object.create()

生成实例对象的常用方法是,使用new命令让构造函数返回一个实例。但是很多时候,只能拿到一个实例对象,它可能根本不是由构造函数生成的,那么能不能从一个实例对象,生成另一个实例对象呢?

    // 原型对象
    var A = {
      print: function () {
        console.log('hello')
      }
    }

    // 实例对象
    var B = Object.create(A)

    console.log(Object.getPrototypeOf(B) === A) // true
    console.log(B.print === A.print) // true
    B.print() // hello

上面代码中,Object.create方法以A对象为原型,生成了B对象。B继承了A的所有属性和方法。

实际上,Object.create方法可以用下面的代码代替。

    if (typeof Object.create !== 'function') {
      Object.create = function (obj) {
        function F() { }
        F.prototype = obj
        return new F()
      }
    }

上面代码表明,Object.create方法的实质是新建一个空的构造函数F,然后让F.prototype属性指向参数obj,最后返回一个F的实例,从而实现让该实例继承obj的属性

下面三种方式生成的新对象时等价的。

    var obj1 = Object.creat({})
    var obj2 = Object.create(Object.prototype)
    var obj3 = new Object()

如果想要生成一个不继承任何属性(比如没有toString和valueOf方法)的对象,可以将Object.create的参数设为null。

    var obj = Object.create(null)
    console.log(obj.toString) // undefined

上面代码中,对象obj的原型是null,它就不具备一些定义在Object.prototype对象上面的属性,比如toString方法。

使用Object.create方法的时候,必须提供对象原型,即参数不能为空,或者不是对象,否则会报错。

    Object.create() // TypeError: Object prototype may only be an Object or null
    Object.create('123') // TypeError: Object prototype may only be an Object or null

Object.create方法生成的新对象,动态继承了原型。在原型上添加或修改任何方法,会立刻反映在新对象上。

    var obj1 = { p: 1 }
    var obj2 = Object.create(obj1)
    obj1.p = 2
    console.log(obj2.p) // 2

上面代码中,修改对象原型obj1会影响到实例对象obj2。

除了对象的原型,Object.create方法还可以接受第二个参数。该参数是一个属性描述对象,它所描述的对象属性,会添加到实例对象,作为该对象自身的属性。

    var obj = Object.create({}, {
      p1: {
        value: 123,
        enumerable: true,
        configurable: true,
        writable: true
      },
      p2: {
        value: 'abc',
        enumerable: true,
        configurable: true,
        writable: true
      }
    })
 
    console.log(obj.p1) // 123

    // 等同于
    var obj1 = Object.create({})
    obj1.p1 = 123
    obj1.p2 = 'abc'
    console.log(obj1.p2) // abc

Object.create方法生成的对象,继承了它的原型对象的构造函数。

    function A() { }
    var a = new A()
    var b = Object.create(a)
    console.log(b.constructor === A) // true
    console.log(b instanceof A) // true

4.Object.prototype.isPrototypeOf()

实例对象的isPrototypeOf方法,用来判断该对象是否为参数对象的原型。

    var o1 = {}
    var o2 = Object.create(o1)
    var o3 = Object.create(o2)
    console.log(o2.isPrototypeOf(o3)) // true
    console.log(o1.isPrototypeOf(o3)) // true

上面代码中,o1和o2都是o3的原型。这表明只要实例对象处在参数对象的原型链上,isPrototypeOf方法都返回true。

    console.log(Object.prototype.isPrototypeOf({})) // true
    console.log(Object.prototype.isPrototypeOf([])) // true
    console.log(Object.prototype.isPrototypeOf(/xyz/)) // true
    console.log(Object.prototype.isPrototypeOf(Object.create(null))) // false

上面代码中,由于Object.prototype处于原型链的最顶端,所以对各种实例都返回true,只有直接继承自null的对象除外。

5.Objcet.getOwnPropertyNames()

Object.getOwnPropertyNames方法返回一个数组,成员是参数对象本身的所有属性的键名,不包含继承的属性键名。

    console.log(Object.getOwnPropertyNames(Date)) 
    // ["length", "name", "prototype", "now", "parse", "UTC"]

上面代码中,Object.getOwnpropertyNames方法返回Date所有自身的属性名。

对象本身的属性值周,有的是可以遍历的(enumerable),有的是不可以遍历的。Object.getOwnPropertyNames方法返回所有键名,不管是否可以遍历。只获取那些可以遍历的属性,使用Object.keys方法

    console.log(Object.keys(Date)) // []

上面代码表明,Date对象所有自身的属性,都是不可以遍历的。

6.Object.prototype.hasOwnProperty()

对象实例的hasOwnpropety方法返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上。

    console.log(Date.hasOwnProperty('length')) // true
    console.log(Date.hasOwnProperty('toString')) // false

上面代码表明,Date.length(构造函数Date可以接受多少个参数)是Date自身的属性,Date.toString是继承的属性。

另外,hasOwnProperty方法是Javascript之中唯一一个处理对象属性时,不会遍历原型链的方法。

7.in 运算符和 for ... in 循环

in运算符返回一个布尔值,表示一个对象是否具有某个属性。它不区分该属性是对象自身的属性,还是继承的属性。

    console.log('length' in Date) // true
    console.log('toString' in Date) // true

in 运算符常用于检查一个属性是否存在。

获得对象的所有可遍历属性(不管是自身的还是继承的),可以使用for...in循环

    var o1 = { p1: 123 }
    var o2 = Object.create(o1, {
      p2: { value: 'abc', enumerable: true }
    })
    for (p in o2) {
      console.log(p)
    }
    // p2
    // p1

上面代码中,对象o2的p2属性是自身的,p1属性时继承的。这两个属性都会被for...in循环遍历。

为了在for...in循环中获取对象自身的属性,可以采用hasOwnProperty方法判断一下。

    for (var name in object) {
      if(object.hasOwnProperty(name)){
        // loop code
      }
    }

获得对象的所有属性(不管是自身的还是继承的,也不管是否可枚举),可以使用下面的函数。

    function inheritedPropertyNames(obj) {
      var props = {}
      while (obj) {
        Object.getOwnPropertyNames(obj).forEach(function (p) {
          props[p] = true
        })
        obj = Object.getPrototypeOf(obj)
      }
      return Object.getOwnPropertyNames(props)
    }

上面代码依次获取obj对象的每一级原型对象“自身”的属性,从而获取obj对象的“所有”属性,不管是否可遍历。

下面是一个例子,列出Date对象的所有属性。

    console.log(inheritedPropertyNames(Date))
    // ["length", "name", "prototype", "now", "parse", "UTC", "arguments", "caller", "constructor", "apply", "bind", "call", "toString", "__defineGetter__", "__defineSetter__", "hasOwnProperty", "__lookupGetter__", "__lookupSetter__", "isPrototypeOf", "propertyIsEnumerable", "valueOf", "toLocaleString"]

8.对象的拷贝

如果要拷贝一个对象,需要做到下面两件事情。

  • 确保拷贝后的对象,与元对象具有同样的原型
  • 确保拷贝后的对象,与原对象具有同样的实例属性

下面就是根据上面两点,实现的对象拷贝函数。

    function copyObject(orig) {
      var copy = Object.create(Object.getPrototypeOf(orig))
      copyOwnPropertiesFrom(copy, orig)
      return copy
    }

    function copyOwnPropertiesFrom(target, source) {
      Object.getOwnPropertyNames(source).forEach(function (propKey) {
        var desc = Object.getOwnPropertyDescriptor(source, propKey)
        Object.defineProperty(target, propKey, desc)
      })
      return target
    }

另一种更简单的写法,是利用ES2017才引入标准的Object.getOwnPropertyDescriptsors方法。

    function copyObject(orig) {
      return Object.create(Object.getPrototypeOf(orig), Object.getOwnPropertyDescriptors(orig))
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值