JavaScript 对象的基本用法

383 阅读6分钟

JS 中的数据类型共有七种:number、string、bool、symbol、undefined、null、object

其中,对象 object 是唯一的复杂类型,而其他六种类型都是简单类型。

对象的语法

对象是一组 “键值对”(key-value)的集合,是一种无序的复合数据集合。其写法如下:

let obj = {'name': 'jack', 'age': 18}    //简单写法
let obj = new Object({'name': 'jack'})   //规范写法
console.log({'name': 'jack', 'age': 18}) //匿名对象

属性名:每个 key(键)都是对象的属性名(property)

属性值:每个 value 都是对象的属性值。

关于键名(key)的几个细节:

  • 键名是字符串,不是标识符,可以包含任意字符(包括''' '、数字、中文、表情符号等)。

  • 引号可以省略,省略之后就只能写标识符,如果键名不符合标识名的条件且也不是数字,则必须加上引号,否则会报错。

  • 就算引号省略了,键名也还是字符串。(很重要)

let obj1 = {
  '': 1,
  ' ': 2,
  '中文': 3,
  '😀': 4,
  '77name': 'jack'
}

let obj2 = { 1: 111 }  //没有数字下标,键名只有字符串
Object.keys(obj2)      //得到 obj2 的所有 key:["1"]

一个值得注意的例子:

{ foo: 'a' }    // "a",在 Firefox 中可以验证

上面代码表示:代码块中有一个名为 foo 的标签(label),其内容为"a",它不是一个对象,而是一个代码块(block)。

奇怪的属性名

在 JavaScript 中,所有的属性名会自动转为字符串

let obj = {
    1: 'a',
    3.2: 'b',
    1e2: true,   //先把 1e2 变成数字100,再变成'100'
    1e-2: true,
    .234: true,
    0xFF: true   //十六进制,自动换算成数字255,然后变成"255"
};

obj;
// Object {
//   1: "a",
//   3.2: "b",
//   100: true,
//   0.01: true,
//   0.234: true,
//   255: true
// }

Object.keys(obj);  //["1", "3.2", "100", "0.01", "0.234", "255"]

变量作属性名

用变量做属性名的写法:[变量名]: 值

不加[]的属性名会自动变成字符串,加了[]则会当做变量求值,求出的值如果不是字符串,则会自动变成字符串。

let p1 = 'name'
let obj = { p1: 'jack' }   //这样写,属性名为 'p1'
let obj = { [p1]: 'jack' } //这样写,属性名为 'name'

对象的增删改查

删除对象的属性

delete 操作符用于删除对象的某个属性。使用 delete obj.xxxdelete obj['xxx'] 删除 objxxx 属性,删除成功后返回 true

let obj = { name: 'jack', age: 18 }

obj.name = undefined
obj    // { name: undefined, age: 18 },删除的是属性值 'jack'

delete obj.name    // true
obj    // { age: 18 },删除的是属性 name

delete obj['name'] // true,删除一个不存在的属性,delete 不报错,而且返回 true

注意区分 属性值为 undefined不含属性名

没有就是没有,undefined 就是 undefined,不能含糊。

属性是否存在:in 运算符

in 运算符用于检查对象是否包含某个属性(检查的是键名,不是键值),如果包含就返回 true,否则返回 false

let obj = { age: 18 }
'name' in obj  //false,name 不是 obj 的属性名
'age' in obj   //true,age 是 obj 的属性名

含有属性名,但是值为 undefined 的表示方法:

'xxx' in obj && obj.xxx === undefined

注意 obj.xxx === undefined 不能断定 'xxx' 是否为 obj 的属性,而是用 in 判断。

let obj1 = {}
let obj2 = { x: undefined }
obj1.x === undefined  //true
obj2.x === undefined //true
'x' in obj   //false
'x' in obj2  //true

查看对象的属性(读属性)

1. 查看自身所有属性 Object.keys(obj)

2. 查看自身 + 共有属性 console.dir(obj)

3. 判断一个属性是自身的还是共有的 obj.hasOwnProperty('toString')

let obj = { name: 'jack', age: 18 }

Object.keys(obj)    //["name", "age"],查看属性名 key
Object.values(obj)  //["jack", 18],查看属性值 value
Object.entries(obj) //查看 key 和 value

console.dir(obj)    //以目录的形式打印出所有自身和共有属性

'toString' in obj  //true,使用 in 不能区分一个属性是自身的还是共有的
obj.hasOwnProperty('toString') //false,说明 toString 是共有属性
obj.hasOwnProperty('name')     //true,说明 name 是自身属性

4. 查看某一属性

  • 中括号语法 obj['key'](优先使用)
  • 点语法 obj.key
  • 坑新人语法 obj[key] (key 是一个变量,值一般不为 'key')
let obj = {name: 'jack', age: 18 }

obj['name']       //"jack"
obj.name          //"jack"
obj['na' + 'me']  //"jack"

obj[name]           //undefined,此时 name 为变量,要先求 name 的值
name                //"",name 的值为 ''
window.name = 'age' //假如将 name 的值设为 'age'
obj[name]           //18

obj[console.log('name')] //undefined

上面代码中,console.log('name') 表达式的值为 undefined

obj[console.log('name')] 等价于 obj['undefined'],而 obj 没有 undefined 这个属性。

5. 区分 obj.name 与 obj[name]

关于 obj.name

  • obj.name 等价于obj['name']

  • obj.name 不等价于obj[name]

  • 这里的 name 是字符串,而不是变量。

关于 obj[name]

  • let name='jack'

  • obj[name] 等价于 obj['jack']

  • 而不是 obj['name']obj.name

  • 这里的 name 是变量

必须要搞清楚的思考题:

let list = ['name', 'age', 'gender']
let person = {
  name: 'jack',
  age: 18,
  gender: 'man'
}
for (let i = 0; i < list.length; i++) {
  let name = list[i]
  console.log(person__???__)
}

上面代码中的 console 语句应如何填写,使得 person所有属性被打印出来?

选项1:console.log(person.name) 选项2:console.log(person[name])

修改或增加对象的属性(写属性)

修改或增加自身属性

1. 直接赋值

let obj = { name: 'jack' }

obj.age = 18
obj.name = 'tom' //name 是字符串
obj['name'] = 'tom'
obj['na' + 'me'] = 'tom'
//若写成 obj[name] = 'tom' 是错误的,这里的 name 是变量,值不确定,可能是 'name' 或 'age'

let key = 'name'
obj[key] = 'tom'
//若写成 obj.key = 'tom' 是错误的,obj.key 等价于 obj['key']

2. 批量赋值 Object.assign(ES 6 新增 API)

Object.assign(obj, { p1: 1, p2: 2, p3:3, p4: 4, p5: 5})
obj  //{name: "tom", age: 18, p1: 1, p2: 2, p3: 3, p4: 4, p5: 5}

修改或增加共有属性

  1. 无法通过自身修改或增加共有属性
let obj1 = {}, obj2 = {} //共有 toString
obj1.toString = 'xxx'    //只是在改 obj1 自身属性
obj2.toString            //还是在原型上
  1. 如果偏要修改或增加原型上的属性
obj.__proto__.toString = 'xxx' //不推荐使用__proto__,会影响性能
Object.prototype.toString = 'xxx'

一般来说,不要修改原型,会引起很多问题。

修改隐藏属性

  1. 不推荐使用 __proto__
let obj = { name: 'jack' }
let obj2 = { name: 'tom' }
let common = { kind: 'human'}
obj.__proto__ = common
obj2.__proto__ = common
  1. 推荐使用 Object.create
let common = { kind: 'human' }
let obj = Object.create(common) //以 common 为原型创建 obj
obj.name = 'jack'
let obj2 = Object.create(common) //以 common 为原型创建 obj2
obj2.name = 'tom'

一般来说,不要修改原型,会引起很多问题。

'xxx' in obj 和 obj.hasOwnProperty('xxx') 的区别

'xxx' in obj

in 运算符用于判断对象 obj 是否包含 xxx 属性,但不能区分属性 xxx 是自身的还是从原型链上继承的。

obj.hasOwnProperty('xxx')

obj.hasOwnProperty('xxx') 用于指定对象 obj 的自身属性中是否具有 xxx 属性。

  • 返回true,说明 xxxobj 的自身属性
  • 返回 false,说明 xxxobj 的继承属性(共有属性)。
let obj = { name: 'jack', age: 18 }
'name' in obj      //true
'toString' in obj  //true
obj.hasOwnProperty('name')      //true,name 是自身属性
obj.hasOwnProperty('toString')  //false,toString 是继承属性