Object的一些静态方法(2)

开场白

很抱歉,开始讲述知识点之前还是要让你看一段不那么重要的开场白。

今天去了自己最为向往的公司参加了第二轮面试,跟CEO聊天的感觉真的非常好,希望自己能进去吧。但是不管怎么说,日子总得要过吧。如果真的不幸没有办法进入该公司,或许我能做的也就是整理着装,重新踏上求职之旅吧。不过在这之前,还是要每天学点javascript吧?

今天主要讲述下面这两组方法

1. Object.keysObject.getOwnPropertyNames的异同。

2. Object.seal, Object.preventExtensions以及Object.freeze可以在不同程度增强对象的健壮性。

正文

1. Object.keysObject.getOwnPropertyNames的异同

两个方法都是可以用来获取指定对象的自有属性的。那么它们有什么不同呢?
之前已经稍微提及过Object.keys了,它是用来获取一个对象的自有属性。比如:

> var a = {x: 1, y: 2}
undefined
> a
{ x: 1, y: 2 }
> Object.keys(a)
[ 'x', 'y' ]

那它有什么局限呢?更确切地说它只能用来获取对象可枚举的自有属性,我们看看下面的例子。

> Object.getOwnPropertyDescriptor(a, 'x')
{ value: 1, writable: true, enumerable: true, configurable: true }

> Object.defineProperty(a, 'x', {enumerable: false}) // 设置x属性为不可枚举的
{ y: 2 }

> a
{ y: 2 }

> Object.keys(a)
[ 'y' ]

可见,现在我们只能获取到对象a的自有的并且是可枚举的属性。如何获得对象a的自有属性,并且不管它们是否是可枚举的呢?这个时候我们可以考虑用Object.getOwnPropertyNames

> Object.getOwnPropertyNames(a)
[ 'x', 'y' ]

这样就可以获取对象a的所有自有的属性,包括了不可枚举的属性。如果我们需要遍历对象a的所有自有属性,这个方法就能派上用场了。

2. Object.seal, Object.preventExtensions以及Object.freeze可以在不同程度增强对象的健壮性。

这里就有一个问题,什么是对象的可扩展性?我用比较直白的话说就是“是否能够为这个对象添加属性?”。我们可以用Object.isExtensible来判断对象是否是可以扩展的。

> Object.isExtensible(1)
false
> Object.isExtensible({})
true
> Object.isExtensible("lanzhiheng")
false

字符串不可以扩展?你在逗我吗?对的,我们这里用的是字符串的字面量,它是不可以扩展的。做个实验:

> var str = "lanzhiheng"
undefined
> str.age = 12
12
> str.age
undefined

我们试图给str添加一个属性,然而最后查找的时候并没有设置成功,原因是

当我们添加属性的时候,JS会临时创建一个字符串的对象,并且它包装了原来的字符串字面量,所以这里并不会报错。但是当我们执行完str.age = 12之后这个对象自动销毁了,所以这个属性添加是没有作用的。

好啦,回到正题,下面是ES5之后才有的静态方法。我们按顺序来说说。

1. Object.preventExtensions 让对象变成不可扩展的

来看例子:

> var b = {x: 1, y: 2}
undefined
> b.z = 13
13

> Object.preventExtensions(b) // 保护可扩展性
{ x: 1, y: 2, z: 13 }

> b.k = 100
100
> b
{ x: 1, y: 2, z: 13 }

可见,一开始给对象b添加属性是可以的,然而,我们调用了Object.preventExtensions之后这个设置就失败了,在严格模式下甚至还会报错

TypeError: Can't add property x, object is not extensible

2. Object.seal 让对象变成不可扩展的并且把已有的属性设置成不可配置的

这里我们简单把不可配置理解成不可删除,(当然绝不是那么简单而已)。我们来操作一下新对象c

> c = {x: 1, y: 2, z: 3}
{ x: 1, y: 2, z: 3 }

> c.kk = 12  // 添加属性
12

> c
{ x: 1, y: 2, z: 3, kk: 12 }

> delete c.kk // 删除属性
true

> c
{ x: 1, y: 2, z: 3 }

目前为止是很正常的,现在用Object.seal来处理一下好吧。

> Object.seal(c)
{ x: 1, y: 2, z: 3 }

> c.kk = 1000 // 添加属性
1000

> c  // 无效
{ x: 1, y: 2, z: 3 }
> delete c.x // 删除属性
false

> c // 无效
{ x: 1, y: 2, z: 3 }

发现处理之后对c对象进行扩展以及删除属性这些操作都不生效了(严格模式下还会报错),这就是Object.seal方法的作用。可以保护对象的属性以及对象本身, 我们可以方便地用Object.isSealed来判断对象是否具有这类属性。

> Object.isSealed(c)
true

同时,我们也可以用来判断对象是否具有不可扩展且属性不可配置这些特征,即便它没有经过Object.seal处理

> var a = {x: 1, y: 2}
undefined

// 设置对象为不可扩展的
> Object.preventExtensions(a)
{ x: 1, y: 2 }
> Object.isSealed(a)
false

// 设置对应的属性的特性为不可配置的
> Object.defineProperties(a, {x: {configurable: false}, y: {configurable: false}})
{ x: 1, y: 2 }

> Object.isSealed(a)
true

这个方法是不是还不错?另外, 虽然我们无法对对象的已有结构进行修改,但是我们却依然可以修改对象已有的属性的值

> c
{ x: 1, y: 2, z: 3 }
> c.x = 100
100
> c
{ x: 100, y: 2, z: 3 }

要怎样更进一步方便地提高健壮性,把所有属性都弄成不可写的,并且不可配置的呢?这个时候会用到下面要介绍的Object.freeze方法。

3. Object.freeze 让对象变成不可扩展的, 并且把已有的属性设置成不可配置并且不可写

这里不多说明,直接举例子

> var d = {x: 1, y: 2, c: 3}
undefined

> Object.freeze(d)
{ x: 1, y: 2, c: 3 }

> d.kk = 100 // 扩展对象d
100
> d
{ x: 1, y: 2, c: 3 }

> delete d.x // 删除对象d属性
false
> d
{ x: 1, y: 2, c: 3 }

> d.x = 100 // 修改对象d属性的值
100

> d
{ x: 1, y: 2, c: 3 }

可见对象d进行了上面操作依然没有任何改变。同样的, 我们也可以用Object.isFrozen来判断对象是否有对应的特性。

> Object.isFrozen(d)
true

这里就不用复杂的例子了,跟Object.isSealed是差不多的。

当然,如果要对这些进行过保护的特性进行非法操作,在严格模式下是会抛出异常的。

> var dStrict = {x: 1, y: 2}
undefined

> Object.freeze(dStrict)
{ x: 1, y: 2 }

> dStrict.x = 100
TypeError: Cannot assign to read only property 'x' of object '#'
 
 

以上这点写代码的时候需要注意一下。毕竟严格模式跟非严格模式有很多行为都是有所区别的。

最后

终于到了尾声了,今天介绍的方法稍微多了一些,不过都是相关联并且比较方便记忆的,希望读者阅读的时候不会太难受。

Happy Writing & Coding

你可能感兴趣的:(Object的一些静态方法(2))