什么是对象?简单说,对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。
声明对象
let obj = {
'name':'frank',
'age':18
}
let obj = new Object({'name':'frank'}) //和上面的写法是一样的,只不过这种写法是正规写法,上面是简单的写法。
键值对
console.log({'name':'frank','age':18}) //直接打印一个没有名字的对象
//注意:花括号前面有点东西才是对象(设计上的坑)
//问:{foo:123}是不是对象?
//答:这是语句,因为设计上的坑,所以浏览器不知道是不是对象,所以直接视为语句。但是,如果加上括号就可以认为是对象了。
({foo:123}) //这样浏览器就认为这是对象
注意对象的所有键名都是字符串,可以包含任意字符,所以进一步说明键名不是标识符而是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。
但是如果忽略引号,键名就必须按照标识符的规则来写,不然报错(在省略引号的情况下除了纯数字可以合法,数字开头后面加别的字符就会报错)。
最后要知道的是,不管加不加引号,键名都是字符串。
:::info
特殊:如果键名是其他进制的数字,如 0xFF
,会在变成字符串前,先转成十进制,再变成字符串,如图
如果要避免的话,添加引号即可!
:::
在对象中,每个Key都是对象的属性名(property),每个value都是对象的属性值。
在属性名中,可以将变量作为属性名,只需要加 []
即可:
let p1 = 'name'
let obj = {p1:'frank'} //这样写,属性名为'p1'
let obj = {[p1]:'frank'} //这样写,属性名为'name'
增删改查
删除属性
语法: delete obj.xxx
or delete obj['xxx']
,即可删除obj下的名为xxx的属性。
在这里,请区分 属性值为undefined
和 不含属性名
:
//在之前先介绍in运算符
'xxx' in obj //in运算符用于检测对象是否包含某属性,如果包含返回ture,否则返回false。
举个栗子:
obj对象有name和age的属性,当我打出 obj.age
时就会返回 18
,很正常。
但是在打出 obj.name
的时候却返回 undefined
,在不知道obj对象里的属性是什么的情况下,还能知道name是否是obj的对象吗?
就好像这对象本来就没有 heighe
属性时打出 obj.height
时候也会返回 undefined
。
所以,只需要用到 in
运算符即可。如:
'name' in obj //true
'height' in obj //false
当一个对象含有 xxx
属性名,可是这属性名的值却为 undefined
。所以配合 in
可以这样判断:
'xxx' in obj && obj.xxx === undefined
查看属性
let obj = {
name:'小明',
age:16
}
Object.keys(obj) //可以查看对象自身所有属性。但只能查看属性名以及对应的下标。
//
console.dir(obj) //可以查看对象自身所有的属性,并且可以查看对应的属性值。
前置知识: 原型
有时候,有一些属性是属于原型那边共有的属性的,并不属于自身,那么在不知道对象有什么属性的情况下,如何知道某个属性是否属于对象自身?方法如下:
let obj = {
name:'小明',
age:16
}
obj.hasOwnProperty('toString')//false
//该方法意思是‘括号内的属性是否属于该对象’,如果是返回true,如果不是返回false。
前面学习了 in语句
,为什么 in语句
不可以而 obj.hasOwnProperty()
可以?这两者有什么区别?
因为, in语句
查看属性的时候,会把公共属性也当成obj的属性一起查看, toString in 'obj'
会返回true,这样根本判断不了该属性是否属于obj还是属于原型的。所以 hasOwnProperty
会更好一些!
:::danger 这里开始要注意区分正确,否则就会不明白! :::
除了上面,还有有两种可以查看属性
obj['key'] //中括号语法,注意这个可以是字符串,字符串,字符串!优先使用该语法
obj.key //点语法,与上面的中括号方法是一样的,而且这个语法的key也是字符串,只不过没有加中括号而已。
obj[key] //注意没有加引号,这是个变量。
:::danger
注意:obj.name
等于 obj['name']
obj.name
不等于不等于不等于 obj.[name]
:::
关于 obj[key]
的例子:
let name = 'frank'
obj[name] //该语句相当于 obj['frank']
修改(增加)属性
点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。
let obj = {
name:"小明"
};
obj.foo = 'Hello';
obj['bar'] = 'World'; //注意必须要加引号,不然会因为值不确定而报错。除非前面已经声明了对应的变量。
//也可以批量赋值,如下
Object.assign(obj,{age:18, gender:'man'})
以上代码都可以给obj对象赋值,也可以修改!
:::danger
注意:
无法通过自身修改或增加原型里的共有属性!!
:::
除非直接指定原型进行修改,如 obj.__proto__.toString='xxx'
or Object.prototype.toString='xxx'
,该方法极其不推荐,这里只是实验尝试有这种可能,知道就可以了。
那么在不改变原型的情况下可以增加共有属性吗?如下
方法一(依旧不推荐)
let obj = {name:'frank'}
let obj2 = {name:'jack'}
let common = {kind:'human'}
obj.__proto__ = common
obj2.__proto__ = common
这个方法很简单,直接创建一个新的对象 common
作为共有属性,然后把 common
赋值给对象 obj
的原型,这样 obj对象
的原型直接指向了 common对象
, obj2
同理!
但这方法依旧不太好,因为代码直接涉及到了 __proto__
,不推荐!
方法二 (解决方法一的问题)
推荐使用 Object.create
let common = {kind:'human'}
let obj = Object.create(common)
obj.name = "frank"
let obj2 = object.create(common)
obj2.name = 'jack'
意思是跟上面的方法是一样的,先创建一个对象 common
作为原型,然后 let obj = Object.create(common)
声明一个对象并且该对象的原型指定为 common
,然后才对 ogj对象
赋值属性(需要一次性赋值,尽量别赋值一下又一下,可以用批量赋值的方法)!!
:::tips
总结,只要是涉及到 __proto__
代码,都是强烈不推荐写的。
:::