定义
JS 对象是无序的数据集合,也是键值对的集合。
- 对象可以包含自身以及其他数据类型
- 键值对是指对象中的一对对 key (键名)与 value (键值)。例如下列语法中 key 是
'name'和'age';value 是'frank'和18。其中'name': 'frank'就是一个键值对
声明对象的语法
let obj = new Object({'name': 'frank'})
let obj = { 'name': 'frank', 'age': 18 }
console.log({ 'name': 'frank, 'age': 18 })
有三种方式是可以声明对象,第一种是正规写法;第二种是简便写法;第三种是直接console.log()出一个匿名对象,这种对象是没有名字的。一般使用前两种。
注意:
- 键名是字符串,(只会是字符串👈👈👈)不是标识符,可以包含任意字符
- 键名是字符串,里面可以是中文,表情,空格、空字符串等
- 引号可省略,省略之后就只能写标识符和数字。就算引号省略了,键名也还是字符串(👈重要)
- 例如以下例子,key是写的是
1但是使用Object.keys()查看发现虽然没加引号,但是key任然是字符串 (Object.keys()可以查看键名 )
- 例如以下例子,key是写的是
对象的属性
一个对象也可以说是一系列属性的集合,一个属性包含一个名和一个值。在括号内,对象的属性以键值对的形式来定义。属性间由逗号分隔。
例如:let obj = { 'name': 'frank', 'age': 18 }中 obj 有两个属性,分别是 name 和 age
- 每个 key 都是对象的属性名(property)
- 每个 value 都是对象的属性值
奇怪的属性名
所有属性名会自动变成字符串,但是如果不加引号可能属性名会先被修改再变成字符串。
- 例如:
所以尽量规范写法,写上引号。
变量作属性名
属性名是字符串,是常量。想要变量做属性名,需要给属性名加 [] 。例如:
- 不加
[]的属性名会自动变成字符串,加了[]则会当做变量求值,值如果不是字符串,则会自动变成字符串。
对象的隐藏属性
JS 中每一个对象都有一个隐藏属性,这个隐藏属性储存着其共有属性组成的对象的地址,这个共有属性组成的对象叫做原型。也就是说,隐藏属性储存着原型的地址
- 原型不是那个地址,是地址里面共有属性组成的对象
在上述例子中,输入obj.toString()居然不报错,因为 obj 的隐藏属性对应的对象上有 toString()。如下所示
原型
JS 中每一个对象都有一个隐藏属性,这个隐藏属性储存着其共有属性组成的对象的地址,这个共有属性组成的对象叫做原型。
每个对象都有原型
- 原型里存着对象的共有属性
- 比如 obj 的原型就是一个对象
obj.__proto__存着这个对象的地址- 这个对象里有 toString / constructor / valueOf 等属性
对象的原型也是对象
- 对象的原型也有原型
obj = {}的原型即为所有对象的原型- 这个原型包含所有对象的共有属性,是对象的根
- 这个原型也有原型,是 null(这里的null并非是不存在,只是人为指定为null)
对象属性的增删改查
删除对象的属性
delete obj.xxx
delete obj['xxx']
-
delete用于删除对象属性,不能删除对象
-
注意:
上图中想使用obj.name = undefined 删除属性,但是实际只删除了属性值,属性名仍保留在。所以这不能有效删除属性。
- 判断是否存在属性名或者属性值:
- 输入
'xxx' in obj,如果输出 false ,则表示对象中没有 xxx 此属性名;输出 true ,表示有 xxx 此属性名。 'xxx' in obj无法判定属性是属于自身的还是原型上共有的。对此又提供了一个 APIobj.hasOwnProperty('key')可以判别,如果输出true ,则表示对象自身有这个属性- 如果想查看含有属性名,但是值为 undefined 的 xxx 可以输入
'xxx' in obj && obj.xxx === undefined -
obj.xxx === undefined不能断定 'xxx' 是否为 obj 的属性
- 输入
查看对象的属性
- 查看自身属性
Object.keys(obj) //看属性名
Object.values(obj) //看属性值
Object.entries(obj) //看属性名和属性值
- 查看自身+共有属性
console.dir(obj) //以目录的形式打印
- 判断一个属性是自身的还是共有的
obj.hasOwnProperty('toString')
(输入后如果输出false说明是共有的不是自身的)
- 查看单个属性
- 中括号语法:
obj['key'] - 点语法:
obj.key - 注意:优先使用中括号语法。点语法会误导你,让你以为 key 不是字符串
- 例如:
- 中括号语法:
在这里:obj.name 等价于 obj['name'];obj.name 不等价于 obj[name]。简单来说,obj.name这里的 name 是字符串,而不是变量。默认每一个window的name属性是空字符串,当给 window.name 赋值'age'后就可以得到18。当中括号里面是变量,必须先求变量的值。
如同下面这个例子,声明let name = 'frank',那么obj[name] 等价于obj['frank']
修改或增加对象的属性
- 直接赋值
添加对象: let obj = {name: 'frank'} // name 是字符串
修改:
法一: obj.name = 'fang' // name 是字符串
法二: obj['name'] = 'fang'
法三: obj['na'+'me'] = 'fang' //先计算'na'+'me',发现等于'name',再赋值
法四: let key = 'name'; obj[key] = 'fang'
(错误修改方法:)
1: obj[name] = 'fang' // 错,因此处 name 值不确定
2: let key = 'name'; obj.key = 'fang' // 错,因为 obj.key 等价于 obj['key']
- 批量赋值
Object.assign(obj, {属性名: 属性值, 属性名: 属性值 , ...})
- 修改或增加共有属性
- 无法通过自身修改或增加共有属性
obj1, obj2 共有 toString ,obj1.toString = 'xxx' 只会在改 obj1 自身属性,obj2没有被影响obj2.toString 还是在原型上。
但是可以通过以下两种方式修改或增加原型上的属性(例如修改原型上toString属性)
obj.__proto__.toString = 'xxx'
Object.prototype.toString = 'xxx'
一般来说,不要修改原型,会引起很多问题
- 改原型
方法一:使用obj.__proto__ = common,例如:
let obj = {name:'frank'}
let obj2 = {name: 'jack'}
let common = {kind: 'human'}
obj.__proto__ = common
obj2.__proto__ = common
方法二:使用let obj = Object.create(common),例如:
let obj = Object.create(common)
obj.name = 'frank'
let obj2 = Object.create(common)
obj2.name = 'jack'
(要改就一开始就改,别后来再改)
注意:所有 __ proto__ 代码都是强烈不推荐写的
资料来源:饥人谷-系统班课程(方应杭)