什么是对象?简单说,对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。

声明对象

  1. let obj = {
  2. 'name':'frank',
  3. 'age':18
  4. }
  5. let obj = new Object({'name':'frank'}) //和上面的写法是一样的,只不过这种写法是正规写法,上面是简单的写法。

键值对

  1. console.log({'name':'frank','age':18}) //直接打印一个没有名字的对象
  2. //注意:花括号前面有点东西才是对象(设计上的坑)
  3. //问:{foo:123}是不是对象?
  4. //答:这是语句,因为设计上的坑,所以浏览器不知道是不是对象,所以直接视为语句。但是,如果加上括号就可以认为是对象了。
  5. ({foo:123}) //这样浏览器就认为这是对象

注意对象的所有键名都是字符串,可以包含任意字符,所以进一步说明键名不是标识符而是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。

但是如果忽略引号,键名就必须按照标识符的规则来写,不然报错(在省略引号的情况下除了纯数字可以合法,数字开头后面加别的字符就会报错)。

最后要知道的是,不管加不加引号,键名都是字符串。

:::info 特殊:如果键名是其他进制的数字,如 0xFF ,会在变成字符串前,先转成十进制,再变成字符串,如图
image.png
如果要避免的话,添加引号即可! :::

在对象中,每个Key都是对象的属性名(property),每个value都是对象的属性值。

在属性名中,可以将变量作为属性名,只需要加 [] 即可:

  1. let p1 = 'name'
  2. let obj = {p1:'frank'} //这样写,属性名为'p1'
  3. let obj = {[p1]:'frank'} //这样写,属性名为'name'

增删改查

删除属性

语法: delete obj.xxx or delete obj['xxx'] ,即可删除obj下的名为xxx的属性。

在这里,请区分 属性值为undefined不含属性名 :

  1. //在之前先介绍in运算符
  2. 'xxx' in obj //in运算符用于检测对象是否包含某属性,如果包含返回ture,否则返回false。

举个栗子:
image.png
obj对象有name和age的属性,当我打出 obj.age 时就会返回 18 ,很正常。

但是在打出 obj.name 的时候却返回 undefined ,在不知道obj对象里的属性是什么的情况下,还能知道name是否是obj的对象吗?
就好像这对象本来就没有 heighe 属性时打出 obj.height 时候也会返回 undefined

所以,只需要用到 in 运算符即可。如:

  1. 'name' in obj //true
  2. 'height' in obj //false

当一个对象含有 xxx 属性名,可是这属性名的值却为 undefined 。所以配合 in 可以这样判断:

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

查看属性

  1. let obj = {
  2. name:'小明',
  3. age:16
  4. }
  5. Object.keys(obj) //可以查看对象自身所有属性。但只能查看属性名以及对应的下标。
  6. //
  7. console.dir(obj) //可以查看对象自身所有的属性,并且可以查看对应的属性值。

前置知识: 原型

有时候,有一些属性是属于原型那边共有的属性的,并不属于自身,那么在不知道对象有什么属性的情况下,如何知道某个属性是否属于对象自身?方法如下:

  1. let obj = {
  2. name:'小明',
  3. age:16
  4. }
  5. obj.hasOwnProperty('toString')//false
  6. //该方法意思是‘括号内的属性是否属于该对象’,如果是返回true,如果不是返回false。

前面学习了 in语句 ,为什么 in语句 不可以而 obj.hasOwnProperty() 可以?这两者有什么区别?

因为, in语句 查看属性的时候,会把公共属性也当成obj的属性一起查看, toString in 'obj' 会返回true,这样根本判断不了该属性是否属于obj还是属于原型的。所以 hasOwnProperty 会更好一些!

:::danger 这里开始要注意区分正确,否则就会不明白! :::

除了上面,还有有两种可以查看属性

  1. obj['key'] //中括号语法,注意这个可以是字符串,字符串,字符串!优先使用该语法
  2. obj.key //点语法,与上面的中括号方法是一样的,而且这个语法的key也是字符串,只不过没有加中括号而已。
  3. obj[key] //注意没有加引号,这是个变量。

:::danger 注意:
obj.name 等于 obj['name']

obj.name 不等于不等于不等于 obj.[name] :::

关于 obj[key] 的例子:

  1. let name = 'frank'
  2. obj[name] //该语句相当于 obj['frank']

修改(增加)属性

点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。

  1. let obj = {
  2. name:"小明"
  3. };
  4. obj.foo = 'Hello';
  5. obj['bar'] = 'World'; //注意必须要加引号,不然会因为值不确定而报错。除非前面已经声明了对应的变量。
  6. //也可以批量赋值,如下
  7. Object.assign(obj,{age:18, gender:'man'})

以上代码都可以给obj对象赋值,也可以修改!

:::danger 注意:
无法通过自身修改或增加原型里的共有属性!! :::

除非直接指定原型进行修改,如 obj.__proto__.toString='xxx' or Object.prototype.toString='xxx' ,该方法极其不推荐,这里只是实验尝试有这种可能,知道就可以了。

那么在不改变原型的情况下可以增加共有属性吗?如下

方法一(依旧不推荐)

  1. let obj = {name:'frank'}
  2. let obj2 = {name:'jack'}
  3. let common = {kind:'human'}
  4. obj.__proto__ = common
  5. obj2.__proto__ = common

这个方法很简单,直接创建一个新的对象 common 作为共有属性,然后把 common 赋值给对象 obj 的原型,这样 obj对象 的原型直接指向了 common对象obj2 同理!

但这方法依旧不太好,因为代码直接涉及到了 __proto__ ,不推荐!

方法二 (解决方法一的问题)

推荐使用 Object.create

  1. let common = {kind:'human'}
  2. let obj = Object.create(common)
  3. obj.name = "frank"
  4. let obj2 = object.create(common)
  5. obj2.name = 'jack'

意思是跟上面的方法是一样的,先创建一个对象 common 作为原型,然后 let obj = Object.create(common) 声明一个对象并且该对象的原型指定为 common ,然后才对 ogj对象 赋值属性(需要一次性赋值,尽量别赋值一下又一下,可以用批量赋值的方法)!!

:::tips 总结,只要是涉及到 __proto__ 代码,都是强烈不推荐写的。 :::