【JS全解】JS对象

207 阅读4分钟

Object

  • Object:无序、键值对(key = value)的数据集合。
  • 唯一一种复杂数据类型,因为它能包含其它的数据类型,乃至它自己本身。
  • 语法:
    	let 对象名 = {
    	    '键名1': 键值,
    	    '键名2': 键值
    	}
    	```
    
  • 多个键值对之间使用,分隔。
  • 键值可以是属性,也可以是方法。
  • Object.keys(对象名)可以得到对象的所有key(键名)。
  • 注意
    • 键名是字符串,不是标识符,可以包含任意字符。
    • 键名的引号可省略,省略之后就只能写标识符或数字
    • 就算引号省略了,键名也还是字符串

奇怪的属性名

let obj = {
  1e2: true,
  1e-2: true,
  .234: true,
  0xFF: true
};
Object.keys(obj) // ['100', '255', '0.01', '0.234']
  • 1e2对应'100'
  • .234对应'0.234'
  • 0xFF对应'255'

变量作属性名

let x = 'str'
let obj1 = {
    x : 1
}
Object.keys(obj1) // ['x']
let obj2 = {
    [x] : 1
}
Object.keys(obj2) // ['str']
  • 如果想用变量的值作属性名,必须要用[]将变量包裹起来。
  • 不加[]的属性名会自动变成字符串。
  • 加了[]则会当做变量求值。

“__proto__”属性和原型

“__proto__”属性

  • JS中每一个对象都有一个隐藏属性__proto__。
  • 所有Object都有它们的共有属性。
  • 它们的共有属性存放的地址,是__proto__的属性值。
  • 注意
    • __proto__已经从 Web 标准中删除,虽然在一部分浏览器中还支持,但在未来可能会停止支持。
    • 不同浏览器对于__proto__可能有不同的命名,它并不是一个统一规范的称呼。因此所有相关语句都不推荐写。

原型

  • 对于Object来说,有一个包含且只包含它们所有共有属性的Object,被称为它们的原型(prototype)。
  • 原型的三段论推理
    • 每个对象都有原型(大前提)
    • 原型也是对象(小前提)
    • 原型也有原型(结论)
  • 非prototype和prototype的联系是:非prototype的__proto__属性的属性值为prototype的地址。
let obj = {a: 1}
obj.__proto__ === Object.prototype // true
  • JS中标识符Object,实际是一个Object的构造方法,即Object()。在这个方法中有一个属性prototype,即为原型。
  • prototype也有__proto__。
    • Object.prototype.__proto__的值为null。
    • Array.prototype.__proto__的值为Object.prototype
  • 注意
    • Object是可以包含Object的,所以Object()方法中的prototype属性,其实也是一个Object,即原型。
    • Object()函数也是Object,自然有__proto__属性。Object.__proto__的值为ƒ () { [native code] }

修改或增加共有属性

  • 无法直接通过自身修改或增加共有属性。
    • 试图直接通过自身修改,新的属性只会添加在自身属性,而不会添加到原型。
  • 可以通过原型来修改或增加共有属性。
    • obj.__proto__.toString = '这里修改了原型的toString'不推荐
    • Object.prototype.toString = '这里修改了原型的toString'
  • 修改原型会引起很多问题,一般来说不要修改。

修改隐藏属性

  • 使用__proto__修改:对象.__proto__ = '这里修改了对象的__proto__'不推荐
  • 使用指定Object为原型来创造对象:Object.create(指定Object)
    var common = {'国籍': '中国', haircolor: 'black'}
    var person = Object.create(common)
    

查看对象属性

  • 查看属性
    • 对象['key']推荐
    • 对象.key
    • obj[代表key的变量]
  • 查看对象中是否有指定属性:'属性名' in 对象
  • 判断对象的一个属性是自身的还是共有的:对象.hasOwnProperty('属性名')
  • 查看对象所有属性名:Object.keys(对象)
  • 查看对象所有属性值:Object.values(对象)
  • 查看对象所有键值对:Object.entries(对象)
  • 查看对象的共有属性:对象.__proto__不推荐
  • 查看对象自身+共有属性:console.dir(对象)

删除对象属性

  • delete obj.xxxdelete obj['xxx']
  • 即可删除 obj 的xxx属性
  • 注意
    • “属性值为 undefined”和“不含属性”是不一样的概念。
      • 不含属性:'xxx' in obj === false
      • 含有属性名,但是值为 undefined:'xxx' in obj && obj.xxx === undefined
    • obj.xxx === undefined不能断定 'xxx'是否为obj的属性,可能它的属性值本身就是undefined。
      var obj1 = {}
      var obj2 = {x:undefined}
      obj1.x === undefined // true
      obj2.x === undefined // true
      
    • 在JS中,删除Object不存在的属性,不会报错、且返回值为true。

修改或增加属性

  • JS中修改属性和增加属性的操作是相同的。
  • 直接赋值
    let person = {
    	name : 'Andy',
    	age : 18
    }
    person['gender'] = '男'
    person.hobby = '足球'
    
  • 批量赋值
    • Object.assign(对象, {key1: value, key2: value})
    • 例:
    let person = {
    	name : 'Andy',
    	age : 18
    }
    Object.assign(person, {
    	'gender': '男', 
    	'hobby': '足球'
    })
    

拓展

Symbol作属性名

let a = Symbol()
let obj = {
	[a]: 'Hello'
}
  • Symbol值也能作属性名。
  • 在“迭代”中可能会用到。

原型链在增删改查中

  • 改、增、删都不会追溯原型链。
  • 只有查询操作才会追溯原型链。

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

  • 'name' in obj是查询obj对象中是否有name这个属性。但无法判断name属性是它自身的,还是它原型的。只有当obj对象本身以及其原型都没有name属性时,才会返回false。
  • obj.hasOwnProperty('name')是查询obj对象自身是否有name这个属性,有两种情况它会返回false:
    1. 该obj对象没有name属性。
    2. 该obj对象有name属性,但是是在它原型中。