携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
对象是我们平时最常用到的数据格式,没有对象的可以使用构造形式自己new一个,或者使用声明形式创建。JavaScript有string, number, boolean, null, undefined, Symbol 6种基本类型,外加Object类型。
null有时候会被当作是对象类型,但实际上它并不是对象,虽然执行typeof null会返回object。
原理上是这么解释的: 不同对象在底层都表示为二进制,如果二进制前3位都为0的话会判断为object类型,null的二进制表示全为0,所以进行typeof操作会返回object。
JavaScript中有一些特殊的内置对象:String, Number, Boolean, Object, Function, Array, Date, RegExp, Error。实际上它们只是一些内置函数,可以当作构造函数来创建对应的类型的对象。
属性和 '方法'
对象有具体的属性和方法,对于获取属性的值我们有两种方法:
- 使用
.操作符,我们称为属性访问 - 使用
[]操作符,我们称为键访问
虽然都可以访问对象的属性,但是[]更强大一些,不同于.操作只能传递满足标识符命名规范的属性名,[]可以访问任意UFT-8/Unicode字符串属性名,并且最重要的是我们可以在[]里面使用变量访问, ES6中添加了可计算属性名。
如果访问的对象属性是个函数,我们经常会把它叫做方法。但是这样逻辑上有些不严谨,在别的语言中,属于对象的函数一般称为方法,但是从技术角度来说,函数永远不会属于一个对象,我们随时可以在外部单独调用对象的函数,或许我们可以理解为对象的函数属性只是一个指向内存中函数位置的指针,我们可以在任何地方调用它,它不是函数独有的。或许有人会说函数并不是在定义的时候成为方法的,而是在被调用的位置不同成为方法。但是这样还是有些不妥。
属性描述符
当我们对象为对象添加新的属性后,可以使用Object.getOwnPropertyDescriptor()对属性的配置进行查看,你会发现每个属性都有value(值)、writable(可写)、enumerable(可枚举)、configurable(可配置)四种属性描述符,也称为数据描述符。
如果我们新增属性时也可以使用Object.definProperty()对数据属性描述符进行配置。
var obj = {}
Object.definProperty(obj, 'a', {
value: 1,
writable: false,
enumerable: true,
configurable: true
}
如上述代码中配置的字面意思你就可以知道为属性所设置的规则。需要注意的是:
- 当
writable: false时,非严格模式下对属性进行修改会失败,严格模式下会报错 - 当
configurable: false时,对属性进行 修改、覆盖、删除 原属性都会失败,把configurable设置为false是单向操作,无法撤销。 enumerable可以控制属性是否可以被枚举,比如说是否可以被for...in循环遍历
属性不可变性
当我们想要保持对象的属性或者对象是不可变的时候,我们可以采取以下方法:
- 设置
writable: false和configurable: false(不可修改,不可重定义,不可删除) - 禁止对象添加新的属性并且保留已有属性:
Object.preventExtensions() - 密封:
Object.seal()会在一个现有对象上调用Object.preventExtensions()并且将现有属性标记为:configurable: false。当我们密封后,不能添加新属性,不能重新配置或者删除现有属性(可以修改属性值) - 冻结:
Object.freeze()会将对象冻结,这个方法会在对象上调用Object.seal()并且将现有属性标记为:writable: false
属性: [[Get]]
当我们对属性进行访问时,比如说myObject.a。我们可能以为就是在myObject对象中查找名字为a的属性。
在语言规范中,我们实际上是实现了 [[Get]]操作(有点像函数调用[[Get]]())。对象默认的内置[[Get]]操作首先在对象中查找是否有名称相同的属性,如果没有会遍历可能存在的[[Prototype]]链,如果找到对应属性就会返回属性值,否则返回undefined