JavaScript的对象是JS中唯一一种复杂类型,它可以存其他七种原始值(数字类型
Number
、字符串类型String
、布尔类型Boolean
、Undefined
类型、Null
类型、符号类型Symbol
、BigInt
类型)
重点内容提要
- 声明对象的两种语法
- 如何删除对象的属性
- 如何查看对象的属性
- 如何修改或增加对象的属性
'name' in obj
和obj.hasOwnProperty('name')
的区别
声明对象的两三种语法
- 对象字面量:
let obj = {'属性名':属性值,...}
,工作只用一般这个 - new构造函数:
let obj = new object{'属性名':属性值}
- ES5方法:
var obj = Object.create({...})
删除对象的属性
delete obj.xxx
delete obj['xxx']
obj.xxx = undefined
属性值改为了undefined
,而并非将该属性完全删除
当运行'xxx' in obj
值为 false
时,可确认已删除xxx
属性
查看对象的属性
- 查看自身独有属性:
Object.keys(obj)
- 查看自身独有加共有属性:
console.dir(obj)
- 两种方法单个属性属性:
obj['key'] 或 obj.key
,(注意key是字符串)
修改或增加对象的属性
- 声明时赋值:
let obj = {kkk: 'vvv'}
,kkk 是字符串 - 直接赋值(点运算符):
obj.kkk = 'vvv'
,kkk 是字符串 - 直接赋值(方括号运算符):
obj['kkk'] = 'vvv'
- 间接赋值(到变量):
let key = 'kkk'; obj[key] = 'vvv'
- 批量赋值:
Object.assign(obj, {age: 18, gender: 'man'})
'name' in obj
和obj.hasOwnProperty('name')
的区别
'name' in obj
:无法知道这个属性是对象自身的还是共有的,当自身没有但共有属性里面有这个属性时,也同样返回true。
obj.hasOwnProperty('name')
:可以很清楚的知道这个对象的某一个属性是自身的,不会去找共有属性里面
obj.hasOwnProperty('name')
:当自身没有,但共有属性里面有这个属性,返回false
,即使改变了原型,除非命名了一个和共有属性名字相同的属性。
正文开始
对象的定义
- 无序的数据集合
- 键值对的集合
对象的写法
|
|
细节
- key(键名)是字符串,不是标识符(不以数字开头的)
- 可以包含任意字符串,即使是空字符串、包含空格、中文、Emoji的字符串皆可,但没人这么用,此时引号不能省略
Chrome
的控制台返回值有欺骗性,用Object.keys(obj)
来查看正确的键名- 除了字符串,
symbol
也能做属性名,但不常用
|
|
- 引号可以省略,省略后只能写标识符(符合标识符规则的字符)
- 就算引号省略,键名也还是字符串
属性名
每个
key
(键)都是对象的属性名(property)
属性值
每个
value
都是对象的属性值
不规范的属性名
所有属性名会自动变成字符串
|
|
细节
- 加引号是最安全的键值写法,否则,键名就不一定符合预期
Object.keys(obj)
可以得到obj
的所有key
变量的值做属性名
如何用变量做属性名
- 之前都是用常量做属性名
- 想以变量的值作为属性名,以
[]
将变量括起来,这是ES6的新增语法
|
|
另一些例子
|
|
对比
- 不加
[]
的属性名会自动变成字符串 - 加了
[]
则会被当做变量并先求值,再作为字符串,成为属性名 - 值如果不是字符串,则会自动变成字符串
对象的隐藏属性
对象
obj
,点开控制台看到有个属性__proto__
,控制台骗你,__proto__
并非指向Object
- JS中每一个对象都有一个隐藏属性
- 这个隐藏属性存储着其共有属性组成的对象的地址
- 这个共有属性组成的对象叫做原型
- 也就是说,隐藏属性存储着原型的地址
- 共有属性省内存
代码示例
|
|
- 不报错是因为
obj
的隐藏属性对应的对象上有toString
- 原型即共有属性
- 内存举例:
#409
存着toString()
、valueOf()
、hasOwnProperty()
- 定义一个对象
obj2
,地址#901
,里面有__proto__
属性指向#409
- 这个对象就是原型,而
#409
是它的地址,#409
所代表的这块内存所表示的对象是原型 - 它是
obj
的原型,也是任何一个新对象的原型
one more thing…
- 除了字符串,
symbol
也能做属性名
|
|
目前(2020)不常用,在学「迭代」的时候会用到
增删改查
「增删改查」对象的属性
增加属性(写入属性)
直接赋值
|
|
错误,因为name 值不确定,不信,再看obj[name] = 'frank
|
|
let key = 'name';
错误,因为obj.key = 'frank'
obj.key
等价于obj['key']
增加属性(写入属性),即属性设置又称为属性赋值
增加属性和改变属性的方法一样,其中,点运算符和方括号运算符这两种方法,与属性查询相同
|
|
批量赋值
|
|
增加共有属性
无法通过自身,来增加共有属性
|
|
硬要增加原型链上的属性
|
|
删除属性
delete obj.xxx
或delete obj['xxx']
- 即可删除
obj
的xxx
属性 - 请区分「属性值为
undefined
」和「不含属性名」 delete obj['xxx']
注意[]
里的引号""
,要求是一个字符串的形式
不含属性名
|
|
含属性名,但值为undefined
|
|
注意obj.xxx === undefined
- 所以
obj.xxx === undefined
不能断定xxx
是否为obj
的属性
|
|
严谨:
没有
和有但undefined
是不一样的
|
|
- 就算你删掉属性后再同样地删一次,JS也不报错
- 所以要验证
'xxx' in obj
,注意属性名一定要加引号
|
|
- 只能用
'xxx' in obj
查看属性名是否还在对象中:true表示在,false表示不在 'xxx' in obj && obj.xxx === undefined
返回true
,表示属性xxx
还在obj
中,而且属性xxx
的值是undefined
obj.xxx === undefined
不能断定'xxx'
是否为obj
的属性。
|
|
小结
判断对象是否含有某个属性名
'xxx' in obj
判断对象的某个属性的属性值是否为空,预期值
true
'xxx' in obj && obj.xxx === undefined
delete
操作符用于删除对象的属性那怎么删掉对象
|
|
改变属性(值)
原来没有某个属性,就是增加;有某个属性,就是修改
修改属性的值,即赋值
增加或修改属性(写入属性)
直接赋值 增加或修改
原来有某个属性,就是修改,确切地分为覆盖掉原来所有的属性值即修改属性值,还是增加新属性,方法一样
|
|
错误,因为name 值不确定,不信看obj[name] = 'frank'
|
|
obj[]
里是通过运算后得到的属性
|
|
let key = 'name';
错误,因为obj.key = 'frank'
obj.key
等价于obj['key']
批量赋值,批量增加属性(ES6)
|
|
assign
就是赋值的意思
增加或修改共有属性
无法通过自身,来增加或修改共有属性
|
|
- JS设计成读的时候,回去看对象隐藏属性发准考的原型;写的时候,不会改掉原型,只能写到自身的属性上
- 修改单个不同对象的共有属性不会互相覆盖
硬要增加或修改原型链上的属性
|
|
谨慎修改原型,可能引起很多问题,这就是JS脆弱的地方,可以随时修改任意对象的原型属性,毁掉整个对象体系
|
|
修改隐藏属性
不推荐使用
__proto__
,性能低
|
|
在原型中加了一个节点,原型后面还有原型,即原型链
推荐使用Object.create(common)
,(ES6)新方法
|
|
|
|
一创建时,就告指定原型
规范:要改就一开始就该,别后来再改
查看属性
分查看所有属性,和查看单个属性
查看所有属性(读取属性)
仅查看自身独有属性
Object.keys(obj)
- 返回一个包含所有属性名字符串的数组
查看独有 + 共有 的所有属性
console.dir(obj)
- 一目录的形式打出来,但chrome控制台瞎返回了一个
Object
,点开可以看到自身 + 共有 的所有属性__proto__
- 或者自己依次用
Object.keys()
在控制台打印出obj.__proto__
,这种方法不推荐,不规范
判断一个属性是自身的独有的,还是共有的:obj.hasOwnProperty(‘propertyName’)
'toString' in obj //true
是不会区分属性是自身的,还是共有的'xxx' in obj && obj.xxx === undefined
返回true
,表示属性xxx
还在obj
中,而且属性xxx
的值是undefined
obj.xxx === undefined
不能断定'xxx'
是否为obj
的属性- 用
'xxx' in obj
只用来查看属性名是否还在对象中:true表示在,false表示不在 - 只能用
obj.hasOwnProperty('toString')
,返回false
说明不是共有属性
仅查看所有属性的值
Object.values(obj)
- 返回一个包含所有属性值字符串的数组
既要看名,又要看值
Object.entries(obj)
- 返回一个数组,这个数组包含两个数组
- 一个数组包含所有属性名字符串
- 另一个包含所有属性值字符串
补充插入
原型
每个对象都有原型
- 原型里存着对象的共有属性
- 比如
obj
的原型就是一个对象 obj.__proto__
存着这个对象的地址- 这个对象里有
toString/constructor/valueOf
等属性
对象的原型也是一个对象
- 所以对象的原型也有原型
obj = {}
的原型即为所有对象的原型- 这个原型包含所有对象的共有属性,是对象的根
- 这个原型也有原型,是
null
|
|
把根对象的原型人为地指定为空值
null
原型之属性继承
对象都和某一个对象相关联,这个对象即原型,每一个对象都从原型继承属性。
所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过
Object.prototype
获得对原型对象的引用
|
|
对象本身具有的属性叫自有属性(own property),从原型对象继承而来的属性叫继承属性
|
|
in
操作符可以判断属性在不在该对象上,但无法区别自有还是继承属性
|
|
通过
hasOwnProperty()
方法可以确定该属性是自有属性还是继承属性
|
|
补充插入完毕
查看单个属性
两种方法查看单个属性
属性查询一般有两种方法,包括点运算符和方括号运算符
|
|
- 中括号语法:
obj['key']
,最明确 - 点语法:
obj.key
,易被误导成key
不是字符串,其实是字符串 - 坑新人语法:
obj[key]
,其变量key
值一般不为字符串'key'
|
|
如果要在对象字面量内部对属性名使用表达式,则需要使用ES6的可计算属性名
|
|
优先使用中括号语法
- 点语法会误导,让人误以为
.key
不是字符串 - 等能够确定不会混淆两种语法,再改用点语法
- 比如用点语法时,就加注释
重要知识点
- 读对象的属性时, 如果使用 语法,那么 JS 会先求 中表达式的值
注意区分表达式是变量还是常量。
- 如果使用点语法,那么点后面一定是 string 常量。
易混淆的
obj.name
等价于obj['name']
(注意这里的[]
中是字符串'name'
)obj.name
不等价于obj[name]
(注意这里的[]
中是变量name
)
简单说来,
.name
是字符串'name'
,而不是变量再举一例
|
|
obj[name]
等价于obj['frankfang']
,而不等价于obj['name']
而不是
obj['name']
和obj.name
面试就看分清变量
name
和常量字符串'name'
记清
obj.name
、obj['name']
、obj[name]
三者的区别
- 必须搞清的面试题
|
|
填空(坑)
-
console.log(person.name)
-
console.log(person[name])
区分
.name
和'name'
为什么这么重要
- 学
vue
的时候就知道厉害了
总结
删
|
|
查
|
|
改
- 改自身
obj['name'] = 'jack'
- 批量改自身
Object.assign(obj,{age:18,...})
,先赋值空对象 - 改共有属性
obj.__proto__['toString'] = 'xxx'
,不推荐 - 改共有属性
Object.prototype['toString'] = 'xxx'
- 改原型
obj.__proto__ = common
,不推荐 - 改原型
let obj = Object.create(common)
- 所有
__proto__
的代码都是墙裂不推荐写的,不可用于业务代码中,仅供学习测试
增(改),属于写
基本同上:已有属性则改;没有属性则增
查属于读,查的时候会看原型链
增改时不会看原型链,增改都是自身
|
|
原型是个对象,共有属性是原型对象的所有属性;原型包含共有属性,共有属性依附于原型对象上
参考文章
相关文章
- 无
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名
- 河 掘 思 知 简