基础
判断数据类型 typeof
判断对象类型 instanceof
用 in 操作符来检查属性是否存在 key(属性名) in Object
删除对象的属性 delete delete Object['属性名']
拷贝
浅拷贝
1 | // 这是浅拷贝,拷贝返回的对象与原对象使用同一引用类型值地址 |
深拷贝
1 | // 乞丐版深拷贝 JSON 方法 |
上下文对象创建和初始化
- 全局:
- 在全局代码执行前最先创建一个全局上下文对象(window)
- 收集一些全局变量/函数, 并初始化
- 将这些变量设置为上下文对象的属性
- 函数:
- 在调用函数时, 在执行函数体之前先创建一个函数上下文对象
- 收集一些局部变量,/函数 并初始化
- 将这些变量设置为上下文对象的属性
- 声明提升
- 变量提升: 在变量定义语句之前, 就可以访问到这个变量(undefined)
- 函数提升: 在函数定义语句之前, 就可以执行该函数
- 如果一个变量和函数同名,函数声明优先于变量声明
- 函数中形参的赋值在函数声明之前
练习:
1 | var foo = 1; |
1 | var a = 1; |
严格模式:
‘use strict’
为了规范 js 的语言类型,推出了严格模式,严格模式下未经声明的值不可使用。
描述对象属性的特性的属性
到目前为止,属性对我们来说是一个简单的“键-值”对。但对象属性实际上是更复杂可变的东西。
两种描述属性:数据属性和访问器属性
1. 数据属性
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有 4 个描述其行为的特性
[[Configurable]] :是否可配置标志,表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
有时它会预设在内置对象和属性中。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true
当它的值为false的时候,一个不可配置的属性不能被
defineProperty
删除或修改。[[Enumerable]] :表示能否通过 for-in 循环返回属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true 枚举/穷举/遍历
[[Writable]] :表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true
[[Value]] :包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为 undefined
像上面的两种方法那样直接在对象上定义属性和方法,它们的 [[Configurable]] 、 [[Enumerable]] 和 [[Writable]] 特性都被设置为 true ,而 [[Value]] 特性被设置为指定的值。可以通过 Object.defineProperty() 来定义
属性描述符可以在各个属性的级别上工作。还有一些限制访问整个对象的方法:
-
禁止向对象添加属性。
-
禁止添加/删除属性,为所有现有的属性设置
configurable: false
。 -
禁止添加/删除/更改属性,为所有现有属性设置
configurable: false, writable: false
。
还有对他们的测试:
-
如果添加属性被禁止,则返回
false
,否则返回true
。 -
如果禁止添加/删除属性,则返回
true
,并且所有现有属性都具有configurable: false
。 -
如果禁止添加/删除/更改属性,并且所有当前属性都是
configurable: false, writable: false
,则返回true
。
这些方法在实践中很少使用。
2. 访问器属性
访问器属性不包含数据值;它包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的)。在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。
- [[Get]] :在读取属性时调用的函数。默认值为 undefined
- [[Set]] :在写入属性时调用的函数。默认值为 undefined
在对象字面量中,它们用 get
和 set
表示:
1 | // 从外表看,访问器属性看起来像一个普通的属性。这是访问器属性的设计思想。我们不以函数的方式调用 user.fullName,我们通常读取它:getter 在幕后运行。 |
访问器属性的描述符
访问器属性的描述符与数据属性相比是不同的。
对于访问器属性,没有 value
和 writable
,但是有 get
和 set
函数。
所以访问器描述符有:
- get —— 一个没有参数的函数,在读取属性时工作,
- set —— 带有一个参数的函数,当属性被设置时调用,
- enumerable —— 与数据属性相同,
- configurable —— 与数据属性相同。
例如,要使用 defineProperty
创建 fullName
的访问器,我们可以使用 get
和 set
来传递描述符:
1 | let user = { |
受保护的属性通常以下划线 _ 作为前缀,这不是在语言层面强制实施的,但是有一个在程序员之间人尽皆知的惯例是不应该从外部访问这些属性和方法。
注意: 属性可以是“数据属性”或“访问器属性”,但不能同时属于两者。
1 | // 同时存在 get函数和 value,会报错 |
3. defineProperty
要修改属性默认的特性,必须使用 Object.defineProperty()
方法。
语法:
1 | Object.defineProperty(obj, propertyName, descriptor) |
例如:
1 | var person = {}; |
注意:
使属性不可配置是一条单行道。我们不能把它改回去,因为
defineProperty
不适用于不可配置的属性。设置不可用的属性时,只在使用严格模式时才会出现错误。在非严格模式下,写入只读属性等时不会发生错误。但操作仍然不会成功。非严格模式下违反标志的行为只是默默地被忽略。
双向绑定
1 | <input type="text" v-module="name"> |
4. defineProperties
Object.defineProperties() 方法用来一次定义多个属性,这个方法接受两个对象参数: 添加或修改其属性的对象,与第一个对象中要添加或修改的属性一一对应的对象
语法:
1 | Object.defineProperties(obj, { |
例如:
1 | Object.defineProperties(user, { |
5. getOwnPropertyNames
Object.getOwnPropertyNames(obj) 可以得到 obj 所有的属性,无论它是否可枚举。
1 | var obj = { |
6. Object.keys
获取对象所有可枚举的属性
1 | var obj = { |
作业:
给任意 input 元素添加 v-module 属性,在 data 中添加相应属性,并实现双向数据绑定,生成的属性不可枚举。
1 | <!-- name改为"李白",data中添加name属性,值为"李白" --> |
题外
1 | var name = 'tt' |
函数的作用域在定义的时候就已经确定了
1 | function af() { |