前言
回顾之前的七种数据类型:
- number string bool symbol
- null undefined
- object
五个falsy值
- null undefined
- 0 NaN
- ‘’(空字符串)
对象的概念
定义
①属性名:每个key都是对象的属性名(property)
②属性值:每个value都是对象的属性值
写法
let obj = { 'name': 'frank', 'age': 18 }
let obj = new Object({'name': 'frank'})
console.log({ 'name': 'frank, 'age': 18 })
细节
- 键名是字符串,不是标识符,可以包含任意字符
- 引号可省略,省略之后就只能写标识符
- 就算引号省略了,键名也还是字符串(重要)
奇怪的属性名
所有属性名会自动变成字符串
let obj = {
1: 'a',
3.2: 'b',
1e2: true,
1e-2: true,
.234: true,
0xFF: true
};
Object.keys(obj)//可以得到所有的键名(key)
=> ["1", "100", "255", "3.2", "0.01", "0.234"]
原因:如果不加引号js会自动计算键名(key)的值,所以建议不要不写引号。
Tips:Object.keys(obj) 可以得到 obj 的所有 key
变量做属性名(key)
如何用变量做属性名
之前都是用常量做属性名
let p1 = 'name'
let obj = { p1 : 'frank'} 这样写,属性名为 'p1'
let obj = { [p1] : 'frank' } 这样写,属性名为 'name'
对比
不加 [ ] 的属性名会自动变成字符串
加了 [ ] 则会当做变量求值
值如果不是字符串,则会自动变成字符串
对象的隐藏属性
隐藏属性
JS 中每一个对象都有一个隐藏属性
这个隐藏属性储存着其共有属性组成的对象的地址
这个共有属性组成的对象叫做原型
也就是说,隐藏属性储存着原型的地址
代码示例
var obj = {}
obj.toString() // 居然不报错
因为 obj 的隐藏属性对应的对象上有 toString()
超纲知识
除了字符串,symbol 也能做属性名
let a = Symbol()
let obj = { [a]: 'Hello' }
增删改查
1、删
①删除某个属性的写法
delete obj.xxx 或delete obj['xxx']
②判断一个属性是否删除,下面是不含属性名
'xxx' in obj===false
③含有属性名,但是值为 undefined
'xxx' in obj && obj.xxx === undefined
Tips:obj.xxx===undefined
,不能断定’xxx’是否为 obj 的属性,这只可判定属性值不可判定属性名是否有
let obj={}//obj.x===undefined
let obj2={x:undefined}//obj2.x===undefined
undefined只删除值
delete都删了
‘name’ in obj查看是否已经删了,返回false表示已经删了
2、查(读)
①查看对象所有自有属性名
Object.keys(obj)
②查看对象所有自有属性值
Object.values(obj)
③查看对象所有自有属性名和属性值
Object.entries(obj)
④查看对象所有属性名(自有和共有)
console.dir(obj)
或者自己依次用 Object.keys 打印出 obj.__proto__,但不推荐
⑤判断一个属性是自身的还是共有的
obj.hasOwnProperty('属性名')
Tips:‘属性名’ in obj可以查看 obj 里是否有这个属性,不管是自身的还是共有的
查看属性
两种方法查看属性
- 中括号语法:obj[‘key’]
- 点语法:obj.key
!!!坑新人语法:obj[key] // 变量 key 值一般不为’key’
var obj={name:'frank',age:18}
obj['name']//是"frank"
obj.name //是"frank"
obj[name]//是 undefined,name 默认是空字符串,默认每一个 window 的 name 都是空字符串,当然你也可以给 name 赋值
window.name='age'
//这个时候 obj[name]是 18。因为 name 是个变量,所以你可以给它赋值。
//如果中括号里面是变量,你必须先求变量的值
obj['na'+'me']//值是"frank"
3、修改或增加属性(写属性)
①直接赋值
let obj={name:'frank'} // name是字符串
obj.name='frank' // name是字符串
obj['name']='frank'
obj[name]='frank' // 错,因为name值不确定
obj['na'+'me']='frank'
let key='name';obj[key]='frank'
let key='name';obj.key='frank' // 错,因为obj.key等价于obj['key']
②批量赋值(是ES6新出的API)
Object.assign(obj,{age:18,gender:'man'})
③修改或增加共有属性
无法通过自身修改或增加共有属性
let obj={},obj2={} // 共有 toString
obj.toString='xxx'//只会在改 obj 自身属性
obj2.toString //还是在原型上
偏要修改或增加原型上的属性
obj.__proto__.toString='xxx' // 不推荐用__proto__
Object.prototype.toString='xxx'
//一般来说,永远不应该修改原型,会引起很多问题,比如代码崩溃,代码异常
④修改隐藏属性
不推荐使用proto
let obj={name:'frank'}
let obj2={name:'jack'}
let common={kind:'human'}
obj.__proto__=common
obj2.__proto__=common
推荐使用 Object.create
let obj=Object.create(common)
obj.name='frank'
let obj=Object.create(common)
obj2.name='jack'
Tips:规范的大概意思是,要改就一开始就改,别后来再改,后来改会非常影响性能
⑤'name' in obj
和obj.hasOwnProperty('name')
的区别
• 'name' in obj
是判断属性是否在obj对象里
• obj.hasOwnProperty('name')
是判断属性name是否为自身属性还是共有属性,为true就是自身属性