对象的属性操作包括属性查询、属性设置、属性删除和属性继承。

属性查询

属性查询有两种方式:点运算符和方括号运算符。

【点运算符】使用点运算符访问对象属性时,属性名用一个标识符来表示,属性名必须符合变量命名规则,否则会报错。

var o = {
  1: 'a',
  name: 'b'
}

o.name // 'b'
o.1 // Uncaught SyntaxError: Unexpected number

【方括号运算符】使用方括号运算符访问对象属性时,属性名用一个字符串表示。方括号运算符的好处是可以用变量定义这个字符串,并且属性名可以是JavaScript无效标识符。

var o = {
  1: 'a',
  name: 'b'
}

var n = 'name';
o[n] // 'b'
o[1] // 'a'

方括号中的值如果不是字符串类型,默认会调用String()转型函数转化成字符串。

var o = {
  1: 'a',
  name: 'b'
}

o[true] // 不会报错

可计算属性名

ES6增加了可计算属性名,可以在属性名上使用[]包裹一个表达式来当作属性名。

var n = 'name'
var o = {
  [n]: 'a'
}

o[n] // 'a'
o.name // 'a'

属性查询错误

当查询一个对象上不存在的属性时,会返回undefiend,不会报错。如果对象不存在的情况下查询不存在的属性会报错。

var person = {};
console.log(person.a);//undefined

console.log(person2.a); //Uncaught ReferenceError: person2 is not defined

所以获取属性值前一定要检查对象是否存在

var len = book && book.subtitle && book.subtitle.length;

属性设置

属性设置就是属性赋值,和属性查询相同,有点运算符和方括号运算符两种方法。

var o = {}
o.name = 'hello'
o['age'] = 10

console.log(o) // {name: 'hello',age: 10}

给对象设置属性前一定要检测对象是否存在。

if(book && book.subtitle) {
  book.subtitle = '子标题'
}

null和undefined不是对象,所以设置属性会报错。

null.name = 'hello'; // Uncaught TypeError: Cannot set property 'name' of null
undefined.name = 'hello'; // Uncaught TypeError: Cannot set property 'name' of undefined

String、Number和Boolean类型有对应的包装类型,所以设置属性不会报错。

'a'.name = 'hello'; // 'hello'
(1).name = 'hello'; // 'hello'
true.name = 'hello'; // 'hello'

属性删除

使用delete运算符可以删除对象的属性。

var o = {name: 'hello'}
delete o.name

console.log(o.name) // undefined
console.log('name' in o) // false

把对象的属性设置为null或undefined,不能删除该属性。

var o = {name: 'hello'}
o.name = null

console.log(o.name) // null
console.log('name' in o) // true

delete运算符只能删除自有属性,不能删除继承属性。要想删除继承属性必须从定义该属性的原型对象上删除,这会影响所有继承自这个原型的对象。

var o = {name: 'hello'}
var o2 = Object.create(o)

delete o2.name
console.log(o2.name) // 'hello'
console.log('name' in o2) // true

delete操作符会返回一个布尔值:

  1. 删除对象属性或数组元素删除成功时,返回true
  2. 删除不存在的属性或非左值时,返回true
  3. 删除变量时,返回false,严格模式报错。
  4. 删除不可配置的属性时,返回false,严格模式报错。
var o = {name: 'hello'}
var arr = ['hello']

console.log(delete o.name) // true
console.log(delete arr[0]) // true

var o2 = {}
console.log(delete o.name) // true  不存在属性
console.log(delete {}) // true  非左值
console.log(delete o2) // false  左值
var str = 'hello'
console.log(delete str) // false

'use strict'
var str = 'hello'
console.log(delete str) //  Delete of an unqualified identifier in strict mode.
var o = {}
Object.defineProperty(o, 'name',{configurable: false})
console.log(delete o.name) // false

'use strict'
var o = {}
Object.defineProperty(o, 'name',{configurable: false})
console.log(delete o.name) // Cannot delete property 'name' of #<Object>

【扩展】什么是左值和右值?

L-value(左值)中的L表示Location,表示可寻址,相当于地址值。
R-value(右值)中的R表示Read,表示可读取值,相当于数据值。

var a,b;
b = 0;
a = b;

上面的示例中,计算机读取b的左值(b在内存中的地址)和0的右值(就是0),把0赋值给b。然后读取b的右值(就是0)和a的左值(a在内存中的地址),把b的右值赋值给a。

b的左右值是根据他的位置判断的,在赋值符号右边表示要获取他的右值,在左边表示要获取左值。左值必须是可写入的,如果左值是常量会报错。

const a;
a = 10; // Uncaught SyntaxError: Missing initializer in const declaration

属性继承

每个对象都和一个原型对象相关联,对象从原型对象上继承属性和方法。所有通过对象字面量创建的对象都具有同一个原型对象,并且可以通过Object.prototype获得对原型对象的引用。

var o = {}
o.__proto__ === Object.prototype // true

注意: Object.prototype的原型对象是null,所以它不继承任何属性。

Object.prototype.__proto__ === null // true

对象本身具有的属性叫做自有属性,从原型对象上继承的属性叫做继承属性。

var o = {a: 1}
var o1 = Object.create(o)

o1.b = 2

console.log(o1.a) // 1 继承属性
console.log(o1.b) // 2 自有属性

【in操作符】in操作符可以判断属性是否在对象上,无论是继承还是自有属性。

var o = {a: 1}
var o1 = Object.create(o)

o1.b = 2

console.log('a' in o1) // true
console.log('b' in o1) // true 

【for-in】for-in循环可以遍历对象中所有可枚举属性。

var o = {a: 1}
var o1 = Object.create(o)

o1.b = 2
for(var i in o1) {
  console.log(o1[i]) // 2 1
}

【hasOwnProperty()】hasOwnProperty()方法可以确定是对象的自有属性还是继承属性。

var o = {a: 1}
var o1 = Object.create(o)

o1.b = 2

console.log(o1.hasOwnProperty('a')) // false
console.log(o1.hasOwnProperty('b')) // true

【Object.keys()】Object.keys()方法返回所有可枚举且可配置的自有属性。


var o = {a: 1}
var o1 = Object.create(o, {
  c: {value: 3, enumerable: false}
})
o1.b = 2

console.log(Object.keys(o1)) // ["b"]

【Object.getOwnPropertyNames()】Object.getOwnPropertyNames()方法返回所有自有属性,包括不可枚举和不可配置属性。

var o = {a: 1}
var o1 = Object.create(o, {
  c: {value: 3, enumerable: false}
})
o1.b = 2

console.log(Object.getOwnPropertyNames(o1)) // ["c", "b"]