JS对象基本用法

190 阅读5分钟

声明对象

JavaScript的对象是一种无序的集合数据类型,它由若干键值对组成。

写法

let obj = { 'name': 'frank', 'age': 18 } 
let obj = new Object({'name': 'frank'})

上面代码中,键名是字符串,不是标识符,可以包含任何字符串

可以省略掉引号,省略后就只能写标识符

let obj = { name: 'frank', 'age': 18 }
// name 依旧是字符串

但是,就算是省略了引号,键名也还是字符串

属性名和属性值

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

每一个 value 都是对象的属性值

奇怪的属性名

所有属性名都会自动变成字符串

let obj = {
    1 : 'a',  
    3.2 : 'b',
    1e2 : 'c',
    1e-2 : 'd',
    .234 : 'e',
    0xFF : 'f'
}
Object.keys(obj) //得到对象所有的 key

//结果为:['1', '100', '255', '3.2', '0.01', '0.234']

上面代码中的属性名发生了变化,JS会先运算出结果,再将结果变成字符串作为属性名

另外 Object.keys() 可以得到对象所有的 key

对象作为属性名

let a = 'name'
let obj = { a : 'frank'}      //属性名为 'a'
let obj2 = { [a] : 'frank'}   //属性名为变量 a

//结果: obj{a:'frank'} ; obj{name:'frank'}

上面代码中,不加 [] 的属性名会自动变成字符串,加上 [] 则会当做变量求值

变量的值如果不是字符串,则会自动变成字符串

对象中的隐藏属性

JS 中每一个对象都有一个隐藏属性

这个隐藏属性中储存着其共同属性组成的对象地址

这个共同属性组成的对象叫做原型,就是说隐藏属性储存着原型的地址

例子:

//声明 2 个对象
let obj = { name : 'frank' , age : 18}
let obj2 = { name : 'jack' , age : 20}

内存图:

内存图.png

let obj = { name : 'frank' , age : 18}
obj.toString()

不会报错,因为 obj 的隐藏属性对应的对象上有 toString()

上图中, #409 为原型,原型其实也是一个对象 ,是对象就会有隐藏属性,#409 原型的隐藏属性指向的原型为 null ,也就是说 #409 原型就是对象的根。

测试:

let obj = { name : 'frank' , age : 18}
obj.__proto__.__proto__

//结果:null

上面代码中, null 并不代表 __proto__ 不存在,而是它的值为 null

增删查改

属性删除

删除对象中的属性

delete obj.xxx
//或者
delete obj['xxx']

undefined

let obj = { name : 'frank' , age : 18}
obj.name = undefined
// 结果:[name : undefined ,age : 18]

let obj = { name : 'frank' , age : 18}
delete obj.name
// 结果:[age : 18]

上面代码中,将属性值赋值为 undefined 并不能将属性删除

判断是否删除

let obj = { name : 'frank' , age : 18}
delete obj.name
'name' in obj
//结果: false,说明 name 不在 obj 对象中

上面代码中, in 判断属性是否在对象中

注意 obj.xxx === undefined 不能判断 xxx 是否为 obj 的属性 例子:

let obj = { name : undefined}
let obj2 = {}
obj.name === undefined
// 结果:true
obj2.name === undefined
// 结果:true

属性查找

查看所有属性

let obj = { name : 'frank' , age : 18}
Object.keys(obj)
// 查看自身所有 key
Object.values(obj)
// 查看自身所有属性值

上面代码中,查看自身所有 keyvalue

let obj = { name : 'frank' , age : 18}
console.dir(obj)

上面代码可以查看自身 + 共用属性

判断属性是自身还是共有
let obj = { name : 'frank' , age : 18}
obj.hasOwnProperty('toString')
// 结果:false

上面代码中, hasOwnProperty 判断是否为自身属性, toString 为共有属性,所有为 false

in 与 hasOwnProperty 的区别
let obj = { name : 'frank' , age : 18}
'toString' in obj
// 结果: true ,toString 在 obj 中
obj.hasOwnProperty('toString')
// 结果: false , toString 不是 obj 自身属性

上面代码中, in 无法判断属性是否为自身还是共有属性, hasOwnProperty 可以

查找单个属性

let obj = { name : 'frank' , age : 18}
obj['name']
//或者
obj.name

obj[name]  //错误写法
// 结果: undefined

上面代码中,可以通过 key 来查找单个属性,但是 obj[name] 中的 name 会被当做变量,而不是 key

obj.name
// 等于
obj['name']
// 不等于
obj[name]

这里的 name 应该是一个字符串,而不是变量

let name = 'jack'
obj[name]
// 等于 
obj['jack']

属性增和改

属性增加跟改一样,有属性则改,没属性则增

直接赋值

let obj = {name: 'frank'}
obj.name = 'jack'
// 或者
obj['name'] = 'jack' 
// 或者
obj['na'+'me'] = 'jack'
// 或者
let key = 'name'
obj[key] = 'jack'

错误写法:

let obj = {name: 'frank'}

obj[name] = 'jack'  
//错误,name 为变量,值不确定

let key = 'name'
obj.key = 'jack'
//错误, obj.key 等于 obj['key']

批量赋值

let obj = {name: 'frank'}

Object.assign(obj,{name: 'jack',age: 18,gender: 'man'})

上面代码中, assign 可以进行批量增加或修改,有属性则改,没属性则增

增加或修改 原型属性

let obj = {} , obj2 = {}

obj.toString = 'xxx' // 修改 toString

obj2.toString //obj2 还在原型上

上面代码说明,我们无法直接修改原型的属性,在读取时会走原型,但是在写入时就不会走原型

如何修改原型属性
let obj = {} , obj2 = {}

obj.__proto__.toString = 'xxx'  //修改原型 toString

obj2.toString   // toString 变成了 'xxx'

上面代码中,我们可以利用 obj.__proto__.toString 修改原型属性,但不推荐使用 __proto__

另一种方法:

let obj = {} , obj2 = {}

//obj 对象原型等于 Object.prototype
//测试
obj.__proto__.toString === Object.prototype.toString
//结果:true , 说明两者相等

Object.prototype.toString = 'xxx'  //修改原型属性
obj.toString
obj2.toString
// 两个都是 'xxx'

上面代码中,发现 obj.__proto__.toString 等于 Object.prototype.toString ,说明是同一原型,所以我们可以直接修改,但一般来说,不要修改原型,会引起很多问题。

修改隐藏属性

let obj = {name : 'frank'} 
let obj2 = {name : 'jack'}

obj.__proto__ = obj2  //修改隐藏属性 __proto__
obj  //查看 obj 对象
obj.toString //依旧可以调用

上面代码中,我们修改了 obj 的隐藏属性, obj 中隐藏属性中有 obj2 的属性,toString 依旧可以调用,因为 obj2 中也有 __proto__ 可以指向原型,所有 obj 依旧可以调用 toString ,这种称之为原型链。

依旧不推荐使用 __proto__

另一种方法:

let obj2 = {name : 'jack'}

let obj = Object.create(obj2) //指定 obj2 为原型

obj.name = 'frank' //obj 里面添加属性

obj  // 查看 obj 对象

上面代码中,通过 create 方法,在创建 obj 对象时就指定了 obj2 为原型,要改就一开始就改,别后来再改