Object 对象属性的操作
属性查询 属性查询一般有两种方法,包括点运算符和方括号运算符: var o = { p: 'Hello World' }; o.p // "Hello World" o['p'] // "Hello World" 1➢ 点运算 点运算符是很多面向对象语句的通用写法,由于其比较简单,所以较方括号运算符相比,更常用。 当通过点运算符访问对象的属性时,属性名用一个标识符来表示,标识符必须要符合变量命名规则。 标识符必须直接出现在javascript程序中,它们不是数据类型,因此程序无法修改它们。 var o = { a:1, 1:2 }; console.log(o.a);//1 //由于变量不可以以数字开头,所以o.1报错 console.log(o.1);//Uncaught SyntaxError: missing ) after argument list 2➢ 方括号运算 当通过方括号运算符来访问对象的属性时,属性名最终通过字符串来表示。字符串是javascript的数据类型,在程序运行中可以修改和创建它们。 使用方括号运算符有两个优点。 【一】可以通过变量来访问属性 var a = 1; var o = { 1: 10 } o[a];//10 【二】属性名称可以为 javascript无效标识符(即,不符合变量命名规则) var myObject = { 123:'zero', class:'foo' }; console.log(myObject['123'],myObject['class']);//'zero' 'foo' console.log(myObject.123);//报错 2.1➢ 判断调用String()隐式转换 【1】方括号中的值若是 字符串类型(外面有引号),就会正常按字符串访问对象的属性; 【2】方括号中的值若是 非字符串类型(外面没有引号),就会先判断是否符合变量命名规则, 【2-1】如果不符合,就会底层调用String()隐式转换成字符串再交由方括号运算; 【2-2】如果符合,就是变量了,被当作通过变量来访问属性的情况(这个时候,如果对应变量没有定义,当然就会报错)。 2.1.1➢ 看demo我们就很容易理解: var myObject = { 123:'this is 123', clasz:'this is clasz' }; console.log(myObject["123"]) // 正常访问'this is 123' console.log(myObject["clasz"]) // 正常访问'this is clasz' console.log(myObject[123]) // 123隐式转换成字符串"123",访问得到'this is 123' console.log(myObject[clasz]) // clasz符合变量命名规则,被当作变量:Error: clasz is not defined 2.1.2➢ 再细看【2-2】: var myObject = { 123:'this is 123', clasz:'this is clasz', extra: 'this is 补充' }; console.log(myObject[clasz]) // clasz符合变量命名规则,被当作变量:Error: clasz is not defined 对比: var myObject = { 123:'this is 123', clasz:'this is clasz', extra: 'this is 补充' }; var clasz = "extra" console.log(myObject["clasz"]) // 访问得到'this is 补充' 现在我们就能理解为什么【2】要这么设置了。 2.2➢ 可计算属性名 在方括号运算符内部可以使用表达式: var a = 1; var person = { 3: 'abc' }; person[a + 2];//'abc' 但如果要在对象字面量内部对属性名使用表达式,则需要使用ES6的可计算属性名: var a = 1; //Uncaught SyntaxError: Unexpected token + var person = { a + 3: 'abc' }; ES6增加了可计算属性名,可以在文字中使用[]包裹一个表达式来当作属性名: var a = 1; var person = { [a + 3]: 'abc' }; person[4];//'abc' 3➢ 属性查询错误 【1】查询一个不存在的属性不会报错,而是返回undefined: var person = {}; console.log(person.a);//undefined 【2】如果对象不存在,试图查询这个不存在的对象的属性会报错: console.log(person.a);//Uncaught ReferenceError: person is not defined 可以利用这一点,来检查一个全局变量是否被声明: // 检查a变量是否被声明 if (a) {...} // 报错 //-----------------------------------------// //所有全局变量都是window对象的属性。window.a的含义就是读取window对象的a属性,如果该属性不存在,就返回undefined,并不会报错 if (window.a) {...} // 不报错 属性设置 属性设置又称为属性赋值,与属性查询相同,具有点运算符和方括号运算符这两种方法。 在给对象设置属性之前,一般要先检测对象是否存在: var len = undefined; if(book){ if(book.subtitle){ len = book.subtitle.length; } } 上面代码可以简化为: var len = book && book.subtitle && book.subtitle.length; 1➢ 属性设置错误 null和undefined不是对象,给它们设置属性会报错: null.a = 1;//Uncaught TypeError: Cannot set property 'a' of null undefined.a = 1;//Uncaught TypeError: Cannot set property 'a' of undefined 由于string、number和boolean有对应的 包装对象 ,所以给它们设置属性不会报错: 'abc'.a = 1;//1 (1).a = 1;//1 true.a = 1;//1 属性删除 使用delete运算符可以删除对象属性(包括数组元素): var o = { a : 1 }; console.log(o.a);//1 console.log('a' in o);//true console.log(delete o.a);//true console.log(o.a);//undefined console.log('a' in o);//false 而如果给对象属性置null或undefined,其实并没有删除该属性: var o = { a : 1 }; o.a = undefined; console.log(o.a);//undefined console.log('a' in o);//true console.log(delete o.a);//true console.log(o.a);//undefined console.log('a' in o);//false 使用delete删除数组元素时,不会改变数组长度: var a = [1,2,3]; delete a[2]; 2 in a;//false a.length;//3 delete运算符只能删除自有属性,不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响到所有继承自这个原型的对象) var o = { a:1 } var obj = Object.create(o); obj.a = 2; console.log(obj.a);//2 console.log(delete obj.a);//true console.log(obj.a);//1 console.log(delete obj.a);//true console.log(obj.a);//1 1➢ 返回值 delete操作符的返回值是个布尔值true或false 【1】当使用delete操作符删除对象属性或数组元素删除成功时,返回true var o = {a:1}; var arr = [1]; console.log(delete o.a);//true console.log(delete arr[0]);//true 【2】当使用delete操作符删除 不存在的属性 或 非左值 时,返回true var o = {}; console.log(delete o.a);//true console.log(delete 1);//true console.log(delete {});//true 【3】当使用delete操作符删除变量时,返回false,严格模式下会抛出ReferenceError错误 var a = 1; console.log(delete a);//false console.log(a);//1 'use strict'; var a = 1; //Uncaught SyntaxError: Delete of an unqualified identifier in strict mode console.log(delete a); 【4】当使用delete操作符删除不可配置的属性时,返回false,严格模式下会抛出TypeError错误 var obj = {}; Object.defineProperty(obj,'a',{configurable:false}); console.log(delete obj.a);//false 'use strict'; var obj = {}; Object.defineProperty(obj,'a',{configurable:false}); //Uncaught TypeError: Cannot delete property 'a' of #<Object> console.log(delete obj.a); 属性继承 每一个javascript对象都和另一个对象相关联。“另一个对象”就是我们熟知的原型,每一个对象都从原型继承属性。 对象本身具有的属性叫自有属性(own property),从原型对象继承而来的属性叫继承属性: var o = {a:1}; var obj = Object.create(o); obj.b = 2; //继承自原型对象o的属性a console.log(obj.a);//1 //自有属性b console.log(obj.b);//2 1➢ hasOwnProperty() 通过hasOwnProperty()方法可以确定该属性是自有属性还是继承属性 var o = {a:1}; var obj = Object.create(o); obj.b = 2; console.log(obj.hasOwnProperty('a'));//false console.log(obj.hasOwnProperty('b'));//true 2➢ in in操作符可以判断属性在不在该对象上,但无法区别自有还是继承属性: var o = {a:1}; var obj = Object.create(o); obj.b = 2; console.log('a' in obj);//true console.log('b' in obj);//true console.log('b' in o);//false 3➢ for-in 通过for-in循环可以遍历出该对象中所有可枚举属性: var o = {a:1}; var obj = Object.create(o); obj.b = 2; for(var i in obj){ console.log(obj[i]);//2 1 } 4➢ Object.keys() Object.keys()方法返回所有可枚举的自有属性: var o = {a:1}; var obj = Object.create(o,{ c:{value:3,configurable: false} }); obj.b = 2; console.log(Object.keys(obj));//['b'] 5➢ Object.getOwnPropertyNames() 与Object.keys()方法不同,Object.getOwnPropertyNames()方法返回所有自有属性(包括不可枚举的属性) var o = {a:1}; var obj = Object.create(o,{ c:{value:3,configurable: false} }); obj.b = 2; console.log(Object.getOwnPropertyNames(obj));//['c','b']