对象的特性
对象一共有三个对象特性,他们分别是:
- 对象的原型: 每个对象(除了null)都与另一个对象相关联,并且继承另一个对象的属性或方法。
- 对象的类: 是一个标识对象类型的字符串
- 对象的扩展标记: 指明了是否可以向该对象添加新的属性
(1)对象的原型
在上面我已经花一定的篇幅去介绍了对象的原型了,这里就不再做过多的介绍了。这里再介绍两种判断原型的方法,第一个是 Object.getPrototypeOf()
,第二个是 ifPrototypeOf()
- Object.getPrototypeOf( )
这个方法是ES5新增的方法,它需要传入对象作为参数,然后就会返回这个对象的原型,来看一下例子
let obj = Object.create({x:1}) //新建一个对象obj继承于 {x:1} Object.getPrototypeOf(obj) //返回 {x:1}
- isPrototypeOf( )
该方法可以判断一个对象是否是另一个对象的原型,或者说在另一个对象的原型链上。来看一下例子
let obj1 = {x:1}let obj2 = Object.create(obj1) obj1.isPrototypeOf(obj2) //返回true,因为obj2就是继承于obj1 Object.prototype.isPrototypeOf(obj2) //返回true,因为Object.prototype在obj2的原型链上
(2)对象的类
对象也是有类型的,这个我在本文的开头也就列举了,对象一共有这三大类,分别是内置对象 、宿主对象 、自定义对象。
我们如何来区分对象的具体类型呢?其实在 Object.prototype
中定义了一个方法属性,叫做 toString,调用该方法,并传入一个对象,就会返回一个字符串,字符串里的信息就用以表示对象的类型。
我们直接通过 Object.prototype.toString.call(obj)
来判断对象的类型,这里用到的 call
的作用就是将 toString 方法内部的 this 指向我们要判断的对象,如果有不懂的小伙伴可以去查看一下我的另一篇介绍call的文章
//先将 Object.prototype.toString.call() 封装成一个函数,方便后面的代码简化function classof(obj) { return Object.prototype.toString.call(obj)} classof(null) //[object Null]classof(undefined) //[object Undefined]classof(1) //[object Number]classof("") //[object String]classof(true) //[object Boolean]classof({}) //[object Object]classof([]) //[object Array]classof(/\d+/) //[object RegExp]classof(new Date()) //[object Date]classof(window) //[object window]classof(document) //[object HTMLDocument]function a() {}classof(new a()) //[object Object]let b = {}classof(b) //[object Object]let c = Object.create(b)classof(c) //[object Object]
简单总结一下
- 继承于内置对象的对象,会返回一个字符串,字符串里包含了该内置对象的构造函数名
- 判断宿主对象的类型时,例如判断window对象的类型,需要在浏览器环境下才能判断。
- 通过对象直接量 、调用构造函数(new fn())以及Object.create() 这三种方式创建的自定义对象,他们的对象类型都为
[object Object]
(3)对象的扩展
对象是具有扩展性的,其表示能否给对象添加新的属性。一般情况下,对象都是可扩展的,除非我们将他转换成了不可扩展的。接下来我们来看几个将对象转换成不可扩展的方法。
- Object.preventExtensions( )
我们要想将一个可扩展的对象转换成不可扩展的,我们需要调用
Object.preventExtensions()
,将需要转换的对象作为参数传入即可。
注意:
- 对象一旦转换成不可扩展,就无法再转成可扩展的了
- 对象转换成不可扩展,只会影响该对象本身,但不会影响原型。即无法给该对象添加新的属性,但是我们可以给该对象的原型添加新的属性,该对象可以继承原型中的新属性。
好了废话不多说,接下来看一个例子
let obj1 = {x:1}let obj2 = Object.create(obj1) //obj2继承于Obj1obj2.z = 4 //给obj2添加一个属性z,值为4console.log(obj2) //打印 {z:4}Object.preventExtensions(obj2) //将obj2转换成不可扩展的obj2.y = 2 //尝试向obj2中添加新属性yconsole.log(obj2.y) // 打印 undefined ,说明obj2是不可扩展的 obj1.y = 2console.log(obj2.y) // 打印 2 ,说明obj2虽然被转换成不可扩展的了,但是还是能从原型继承属性的 delete obj2.z //打印 {},说明使用Object.preventExtensions()将对象转换成不可扩展后,虽然无法添加属性,但是可以删除属性
我们可以将对象传入 Object.isExtensible()
来判断对象是否为可扩展的。
- Object.seal( )
该方法是ES5中提供的,不仅具有能将对象转换成不可扩展的作用(无法添加新属性),而且还能使对象中的自有属性都设置为不可配置的,即无法删除自有属性了。我们可以成为将对象封闭。
let obj1 = {x:1}let obj2 = Object.create(obj1) //obj2继承于Obj1obj2.z = 4 //给obj2添加一个属性z,值为4console.log(obj2) //打印 {z:4}Object.seal(obj2) //将obj2封闭 delete obj2.z //打印 {z:4},说明使用Object.seal()将对象封闭后,既无法添加属性,也无法删除属性 obj2.z = 100 //修改obj2中的属性z为100console.log(obj2) //打印 {z:100} ,说明已封闭的对象,还是可以对其属性进行修改的
我们可以将对象传入 Object.seal()
中,判断对象是否已封闭
- Object.freeze( )
该方法也是ES5中提供的,它在 Object.seal()
的基础之上,增加了一个限制,即将对象的自有的所有数据属性设置为只读。我们把这种限制叫做冻结
let obj1 = {x:1}let obj2 = Object.create(obj1) //obj2继承于Obj1obj2.z = 4 //给obj2添加一个属性z,值为4console.log(obj2) //打印 {z:4}Object.freeze(obj2) //将obj2冻结 obj2.z = 100 //修改obj2中的属性z为100console.log(obj2) //打印 {z:4} ,说明已冻结的对象,无法修改对象中的属性值
我们可以将对象传入 Object.isFrozen()
中,判断对象是否已冻结
结束语
好了,洋洋洒洒这一系列文章也写完了,写加上思考理解大概耗时有十几个小时吧,说真的,刚开始写这篇文章的时候,自己对于 “对象” 这个概念也不是说很透彻很透彻,但是我为了让大家能明白,自己也花了很多的心思去研究,去理解。到现在完结,我对 “对象” 的概念也是有了更深的理解了。
真的是原创不易啊,大家觉得写的不错的点个关注,点个赞,感谢啦~