内容有点儿多,将分为两篇内容与你们分享。有的地方确实难以理解,能够多动手实现一下,看看效果。javascript
一直据说有这么一句话,在JavaScript中,一切皆为对象。 java
经本人慎重研究以后发现,此言的确不虚。(这不废话么,虚不虚的还用你说。)函数
今天斗胆跟你们一块儿讨论一下JavaScript
重的Object
。了解Object
背后的 -- 生活
性能
阅读间隙,还得多注意休息哟~this
开始第一个小问题,看一下如何建立一个对象。建立对象有四(shi)种方式。如下几种方式均可建立一个对象,只不过建立以后的表现稍有不一样。具体表现为原型和this
的指向问题。有兴趣的读者可点击查看相关文章。在这里咱们就不详细介绍了。(偷个懒)prototype
注意点:对象
四种方式建立对象,除了原型和this
指针表现不一样,构造函数指向也有不一样。(此时说明的是不手动指定构造函数的状况下)ip
function Object() {}
Object.create
建立的对象,构造函数为入参origin
的构造函数class
方式建立,会将自己也做为构造函数。const obj = {} // 构造函数为 [Function: Object]
function Obj() {} const obj = new Obj() // 构造函数为 [Function: origin]
const origin = {a: 1, b: 2} const target = Object.create(origin) // 构造函数为 origin 的构造函数
class Origin {} const target = new Origin() // 构造函数 [Function: Origin]
注:
官方版
通俗版
key
属性,使用 .
运算符 或 中括号const obj = { a: 1, b: 2, c: 3, d: function () {} } obj.a === obj['a']// 1 obj.b === obj['b'] // 2 obj.c === obj['c'] // 3 obj.d === obj['d'] // function (){}
kay
值,只能使用中括号方式const obj = { a1: 1, a2: 2, a3: 3, a4: function (){} } for(let i = 1;i < 5;i ++) { obj['a' + i] } // 1,2,3,function (){}
注意:
若是对象中不含有某个key
,获取到的为 undefined
例如:
const obj = {} obj.c() // TypeError: obj.c is not a function
因为obj
中不含有c
这个方法,因此获取到的是undefined
。此值不是函数,执行报错
可修改成如下写法
const obj = {} typeof obj.c === 'function' && obj.c()
这里有的读者可能会说这样也能够 obj.c && obj.c()
。这种写法在下面这种状况下依然会报错
const obj = { c: 1 } obj.c()
因此,仍是要清楚的判断咱们要获取的key
是一个函数,才能执行。
在此段内容开始以前,先说一个小问题,如何判断对象中是否含有某个key
值?
2.1
中的属性获取undefined
便可。undefined
,则会出现判断失误的状况const obj = { c: undefined } console.log(obj.c === 'undefined') // 判断为true,可是obj中确实含有c这个key
in
key
// 包含某个key function A () { this.b = 1 } const a = new A() console.log('b' in a) // true
key
// 不包含某个key function A () { } const a = new A() console.log('b' in a) // false
key
,值为 undefined
的状况// 不包含某个key function A () { this.b = undefined } const a = new A() console.log('b' in a) // true
key
存在于原型链上function A () { } Object.prototype.b = 1 const a = new A() console.log('b' in a) // true
注意点:
缺点:in
方法没法判断当前key
是存在于对象自己仍是在原型链上。此状况,咱们须要用到下面这种方法。
hasOwnProperty
查询属性是否存在于自身function A () {} Object.prototype.b = 1 const a = new A() console.log(a.hasOwnProperty('b')) // false
function A () { this.b = 1 } const a = new A() console.log(a.hasOwnProperty('b')) // true
undefined
function A () { this.b = undefined } const a = new A() console.log(a.hasOwnProperty('b')) // true
总结:
undefined
的状况in
方法不能判断属性是在对象自己仍是在原型链上hasOwnProperty
能够判断属性是否存在于自身,同时也可判断属性值为undefined
的状况删除对象的属性能够使用delete
方法,只不过此方法的性能并不算太优越
const obj = { b: 1, c: 2 } delete obj.b console.log(obj) // {c: 2}
休息会儿,这篇文章可长哈,按部就班的来。
JavaScript
中将属性分为两种:数据属性和访问器属性。
数据属性包括:Configurable
、Enumerable
、Writable
、Value
四个属性描述符
访问器属性包括:Configurable
、Enumerable
、Set
、Get
四个属性描述符
经过对比咱们能够发现,属性描述有六类:
Configurable、Enumerable、Writeable、Value、Set、Get
注意:
修改描述符,只能够经过Object.defineProperty(obj, key, config)修改一个
|| Object.defineProperties(obj,config)修改多个
方法来修改。
例如:
const obj = { a: 1, b: 2, c: 3 } // 修改一个 Object.defineProperty(obj, 'a', { enumerable: true, writable: true, configurable: true }) // 修改多个 Object.defineProperties(person, { a: { enumerable: true, writable: true, configurable: true }, b: { enumerable: true, writable: true, configurable: true } }
Configurable
:是否可经过delete
删除属性、是否可从新定义属性、是否可修改描述符、是否可进行属性互换。
true
上述操做均可进行const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'a', { configurable: true }) delete obj.a Object.defineProperty(obj, 'a', { value: 11 }) Object.defineProperty(obj, 'a', { enumerable: true }) Object.defineProperty(obj, 'a', { set() {} })
false
严格模式下报错,普通模式下过滤操做const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'a', { configurable: false }) delete obj.a Object.defineProperty(obj, 'a', { value: 11 }) Object.defineProperty(obj, 'a', { enumerable: true }) Object.defineProperty(obj, 'a', { set() {} })
Enumerable
:是否可枚举
const obj = { a: 1, b: 2, c: 3 } // 为 true 的状况,可遍历 Object.defineProperty(obj, 'a', { enumerable: true }) for(let item in obj) { console.log(item) // a, b, c 可遍历到 a } // 为false的状况,不可遍历 Object.defineProperty(obj, 'a', { enumerable: false }) for(let item in obj) { console.log(item) // b, c 遍历不到 a }
Writable
:是否可修改属性的值,加上它,将变为数据属性
const obj = { a: 1, b: 2, c: 3 } // 为 true 可修改属性值 Object.defineProperty(obj, 'a', { writable: true }) obj.a = 2 console.log(obj.a) // 2 // 为false 不可修改属性值 严格模式下会报错 Object.defineProperty(obj, 'a', { writable: false }) obj.a = 2 console.log(obj.a) // 1
Value
:属性的数据值,加上它,将变为数据属性
const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'a', { value: 11 }) console.log(obj.a) // 11
Set
:写入属性时调用,加上它,将变为访问器属性
const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'a', { set() { console.log('a的值改变了') } }) obj.a = 2 // a的值改变了
Get
:读取属性时调用,加上它,将变为访问器属性
const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'a', { get() { console.log('获取a的值') } }) obj.a // 获取a的值
数据属性 --> 访问器属性
将 Writable、Value
中的任意一个替换为 Set、Get
中的任意一个。
访问器属性 --> 数据属性
将 Set、Get
中的任意一个替换为 Writable、Value
中的任意一个。
示例可接着往下看
想要查看某个属性的描述,能够使用Object.getOwnPropertyDescriptor(obj, key)
来查看
const obj = { a: 1 } console.log(Object.getOwnPropertyDescriptor(obj, 'a')) // { value: 1, writable: true, enumerable: true, configurable: true } Object.defineProperty(obj, 'a', { get() { console.log('获取a的值') } }) console.log(Object.getOwnPropertyDescriptor(obj, 'a')) /* { get: [Function: get], set: undefined, enumerable: true, configurable: true } */
此例咱们能够验证 属性互换
的正确性,当咱们将get
设置为 a
的描述符时,a
会变为访问器属性
接下文:Object 重识(二)