语法
对象有两种定义形式:声明形式和构造形式
声明形式:
| |
构造形式:
| |
类型
在JavaScript中共有6种基本类型(现在是7种)
- string
- number
- boolean
- null
- undefined
- object
还有一种symbol类型
简单基本类型并不是对象,虽然typeof null === 'object',但是这个语言的一个bug
原理是这样的,不同的对象在底层都表示为二进制,在JavaScript中二进制前3位为0的话会被判定为
object类型,null的二 进制全是0,自然前三位也是0,所以执行typeof时会返回"object"
内置对象
JavaScript中还有一些对象子类型,通常被称为内置对象
- String
- Number
- Boolean
- Object
- Function
- Array
- Date
- RegExp
- Error
这些对象从表现形式来说很像其他语言中的类型或者类,但在JavaScript中,只是一些内置函数,这些内置函数 可以当做构造函数来使用。
装箱和拆箱操作
把字面量转换成对象的操作称作"装箱",把对象转换成字面量的操作称作"拆箱"
“装箱”
| |
“拆箱”
| |
“自动装箱”
| |
属性
对象内的属性不是真正存储在对象内部,而是像指针一样,指向这些值的真正的存储位置
属性描述符
从ES5开始,所有属性都具备了属性描述符,可以使用defineProperty来显式指定一些特性
writable
writable决定是否可以修改属性的值如果
writable设为false,修改属性的值在非严格模式下静默失败,严格模式下抛出TypeErrorconfigurable
configurable决定是否可以通过defineProperty来修改属性描述符如果
configurable设为false,不管是否是严格模式,再次使用defineProperty都会抛出TypeError, 因此把configurable设为false是单向操作,无法撤销。除了无法修改,
configurable设为false还会禁止删除这个属性。enumerable
enumerable决定属性是否会出现在对象的属性枚举中,比如for..in中如果设为
false,属性可以正常访问,但不会出现在枚举中。
可计算属性名
ES6中增加了可计算属性名,可以在文字形式中使用[]包裹一个表达式当做属性名
| |
关于数组
如果试图向数组添加一个属性,但是属性名"看起来"像一个数组,那它会变成数值下标,因此会修改数组的内容而不是添加一个属性
| |
不变性
所有方法创建的都是浅不变性,也就是说它们只会影响目标对象的直接属性,如果目标对象引用了其他对象,其它对象的内容不受影响。
实现不变性的几种方法
对象常量
结合
writable:false和configurable:false可以创建一个真正的常量属性禁止拓展
如果想禁止一个对象添加新属性并保留已有属性,可以使用
Object.preventExtensions(..)密封
Object.seal(...)会创建一个密封对象,这个方法实际上会调用Object.preventExtensions,并将现有 对象的属性标记为configurable: false冻结
Object.freeze(...)会创建一个冻结对象,这个方法实际上会调用Object.seal, 并将现有对象的属性标记为writable: false
[[GET]] 和 [[PUT]]
[[GET]]操作
对于属性的访问实际上是实现[[GET]]操作,默认的[[GET]]操作实际上是首先在当前对象中查找是否有名称相同的属性,如果找到就返回这个属性的值,否则
沿着原型链查找,如果还没有找到,返回undefined
[[PUT]]操作
给对象的属性赋值会触发[[PUT]]操作,如果对象已经存在这个属性,[[PUT]]算法大致会检查下面这些内容
- 属性是否是访问描述符,如果是并且存在
setter就调用setter - 属性描述符中
writable是否是false,如果是,在非严格模式下静默失败,在严格模式下抛出TypeError异常 - 如果都不是,将该值设为属性的值
如果对象中不存在这个属性,,,之后再叙述,待补充
Getter 和 Setter
当给一个对象的属性定义getter、setter或者两者都有时,这个属性会被定义为"访问描述符",对于访问描述符来说,
JavaScript会忽略它们的value和writable特性,取而代之的是关心set和get特性。
| |
注意,由于只定义了a的getter,所以对a进行赋值操作会被忽略。
属性的存在性
in
in操作符会检查属性是否在对象及其原型链中
hasOwnProperty
hasOwnProperty只会检查属性是否在本对象中
注意: hasOwnProperty是存在于Object.prototype中的方法,所以通过Object.create(null)创建的对象调用会失败。
遍历
ES6中的for..of可以用来直接遍历值, for..of首先会向被访问对象请求一个迭代器对象,然后通过调用迭代器对象的next()方法来遍历所有返回值。
数组有内置的@@iterator,因此for..of可以直接应用在数组上。
| |
因此我们我们可以自己定义迭代器,只要迭代器拥有next方法,并且返回值符合{value: ..., done: true/false}规范,就可以使用
for..of来迭代遍历。