什么是对象?如何声明?
对象的定义
- 对象就是一堆无序数据的集合
- 这些数据集合以键值对的形式一一对应
- 这些键值对的键,我们称作 属性名(key) ;值,我们称作 属性值(value)
- 在内存中,对象类型的数据被存储在Heap区中
对象的声明
// 1. 常用方式:简单声明,直接通过 {} 代码块进行声明一个变量
let obj = {'name' : 'frank' , 'age' : 18 }
// 2.正规方式,通过 new Object 构造函数进行声明
let obj = new Object({'name' : 'frank' , 'age' : 18 })
// 3.非主流写法
// 这里也声明了对象,但是并没有变量接收这个对象
console.log({'name' : 'frank' , 'age' : 18 })
对象声明的一些细节
- 对象中的键名几乎所有是 字符串 (Symbol也可以作属性名,非常少用)!!!但是可以不加引号,我们可以通过
Object.keys()来验证这个结论;

- 对象中的键名加引号是,其可以包含任意字符,可以是空字符串,只有空格的字符串,emoji表情,中文,总之任意字符都可以;
- 对象中的键名不加引号时,其必须按照标识符来进行书写,但是额外允许数字作第一个字符。
- !!! 在声明对象的时候,属性名建议一定要 加引号 。
属性名一些刁钻点
-
Object.keys(obj)可以获取obj对象的所有属性名。 -
所有属性名都会自动变成字符串,在不加引号的情况下,对于有些属性名,JS甚至会帮它计算后再变成字符串。

- 使用变量作为属性名
- 属性名加了 [] 会被当做变量先进行求值,如果变量的值不是 字符串 则会自动把值变成字符串
- 不加 [] 的属性名则会自动变成字符串
let p1 = 'name'
let obj = { p1 : 'JackM' } // 这种情况 'JackM' 的属性名为 "p1",即 { "p1" : "JackM" }
let obj = { [p1] : 'JackM'} // 这种情况 'JackM' 的属性名为 p1变量的值,即 { "name" : "JackM" }
对象的隐藏属性
let obj = {}
// obj是一个空对象,为什么下面这行代码不报错?因为obj原型中有 toString()
obj.toString()
- JS中每一个对象都有一个隐藏属性
- 这个隐藏属性储存这个对象的共有属性组成的对象的地址
- 这个共有属性组成的对象就叫做原型。
- 也就是说隐藏属性储存原型的地址。
- 因为原型其实是共有属性组成的对象,所以原型也是一个对象,所以原型也有它的原型。
Symbol作属性名

- Symbol作属性名几乎不用,一般在“迭代”的时候才会使用到
对象属性的增删查改
删除属性
语法
delete obj.xxx或delete obj['xxx']即可删除 obj对象 中的 xxx 属性'xxx' in obj可以查询obj中是否有一个叫 xxx 的属性,这个查询不仅会在自身对象中查找,还会沿着原型链查询。

区分删除属性和属性值为undefined
- 删除属性是把 属性名+属性值 整个键值对从对象中删除,而不仅仅只是把属性值改为undefined。这两种方法最大的区别就是:删除属性后对象不再有该属性,而属性值改为undefined后对象仍拥有该属性,只是该属性没有赋值。
let obj = {
'aaa': 'aaa',
'bbb': 'bbb'
}
delete obj.aaa
obj.bbb = undefined
console.log('aaa' in obj) // false
console.log('bbb' in obj) // true
- 所以判断一个属性是否在该对象中,不能使用
obj.xxx === undefined,要使用'xxx' in obj - JS关于删除属性一个小问题:JS中删除对象中一个原本就不存在的属性并不会报错。
查看对象属性
查看所有属性
- 查看所有属性的属性名(键)
Object.keys(obj)
- 查看所有属性的属性值(值)
Object.values(obj)
- 查看所有属性的属性名和属性值
Object.entries(obj)
- 查看自身属性+原型对象中的属性
console.dir(obj)控制塔打印obj的目录详细信息obj.\_\_proto\_\_查看obj的原型对象中的属性
- 判断一个属性是否是自身属性而不是原型中的属性
- 用:
obj.hasOwnProperty('xxx') - 不要使用
'xxx' in obj这个方法会沿着原型链查找属性
- 用:
查看属性
-
中括号语法
obj['xxx']注意:使用引号包裹属性名,直接使用属性名obj[xxx]使用变量,会先计算 xxx变量的值 再把这个值变成字符串 再查询属性
-
点语法
obj.xxx注意:这个 xxx 没有引号,但是一个字符串
-
一道代码题分清楚上面3种情况
let list = ['name', 'age', 'gender']
let person = {
name: 'frank', age: 18, gender: 'man'
}
for (let i = 0; i < list.length; i++) {
let name = list[i]
console.log(???) // 这里 ??? 替换成什么使person所有属性被打印出来
}
// 1.console.log(person.name) 2.console.log(person[name])
// 答案:console.log(person[name])
增加&修改对象属性
- 增加和修改对象属性方法一样。当对象已经存在某属性时,给该属性赋值则是修改属性;如果对象不存在某属性,给该属性赋值就是增加对象属性。
单个属性操作
let obj = { name: 'frank' }
obj.name = 'Jack'
obj['name'] = 'frank'
obj[name] = 'frank' // 错误,因为不知道name变量并没有声明赋值
obj['na' + 'me'] = 'frank' // 正确,先计算 两个字符串的拼接,再进行增改操作
let key = 'name';
obj[key] = 'frank' // 正确,相当于 obj['name'] = 'frank'
let key = 'name';
obj.key = 'frank' // 错误,但是可以在 obj 新增一个属性名为 key 的属性
批量赋值,ES6新特性
let obj = { 'name': 'Jack' }
Object.assign(obj, { 'age': 18, 'gender': 'male' }) // 增加 'age' 、 'gender' 属性
属性增改与原型的关系
- 一般,增加和修改属性只能作用于自身对象,无法影响到原型
let obj1 = {}
let obj2 = {}
obj1.toString = 'xxx' // 首先查询toString属性,发现obj1自身上没有这个属性,新增 toString 并赋值 'xxx',并没有影响原型
console.log(obj1.toString) // 'xxx'。先在自身上找toString,发现存在属性,直接引用该属性
console.log(obj2.toString) // toString函数。先在自身上找toString,找不到,沿着原型链向原型中找,找到并引用
- 增改原型上的属性(错误) 虽然原型上的属性可以增改,但是非常不建议这么做,会引起很多问题
这种修改原型的方式,是修改原型上的属性,原型会直接受到影响,导致其他对象如果要通过原型链调用里面的属性,会出现报错。
let obj1 = {}
let obj2 = {'name' : 'jack'}
// 1.通过 __proto__ 修改原型上的属性,不推荐使用 __proto__进行任何操作
obj1.__protot__.toString = 'xxx'
// 2.通过obj1的上一级对象的 prototype 属性进行修改原型上的属性
Object.prototype.toString = 'xxx'
obj2.toString() // 报错,因为原型上的属性已经被修改
- 增改原型上的属性(正确) 如果要修改原型那么就在一开始创建对象的时候就修改
这种增改的方式其实就是再插入多一个原型!而不是单一修改原型的某个属性值
// 1.通过 __proto__ 不推荐直接使用 __proto__
let obj = { name: 'frank' }
let common = { kind: 'human' }
obj.__proto__ = common // 此时:obj的__proto__指向的是 common ,而common的__proto__指向的是Object.prototype。
// obj不仅可以通过原型链调用 common 中的属性,还能调用 Object.prototype 中的属性,如toString。
// 2. 通过 Object.create
// Object.create()第二个参数 格式:{name:{value:'jack'}} 指的是创建对象的自身属性
// new Object 与 Object.create 是不一样的
let common = { kind: 'human' }
let obj = Object.create(common)
obj.name = 'frank'
let obj2 = Object.create(common, { 'name' : { value : 'jack' } } )