前面的话

  对于对象来说,属性操作是绕不开的话题。类似于“增删改查”的基本操作,属性操作分为属性查询、属性设置、属性删除,还包括属性继承。本文是对象系列的第二篇——属性操作

属性查询

  属性查询一般有两种方法,包括点运算符和方括号运算符

var o = {
p: 'Hello World'
};
o.p // "Hello World"
o['p'] // "Hello World"

  [注意]变量中可以存在中文,因为中文相当于字符,与英文字符同样对待,因此可以写成person.白或person['白']

var person = {
白 : 1
}
person.白;//
person['白'];//

【点运算符】

  点运算符是很多面向对象语句的通用写法,由于其比较简单,所以较方括号运算符相比,更常用

  由于javascript是弱类型语言,在任何对象中都可以创建任意数量的属性。但当通过点运算符(.)访问对象的属性时,属性名用一个标识符来表示,标识符要符合变量命名规则。标识符必须直接出现在javascript程序中,它们不是数据类型,因此程序无法修改它们

var o = {
a:1,
1:2
};
console.log(o.a);//
//由于变量不可以以数字开头,所以o.1报错
console.log(o.1);//Uncaught SyntaxError: missing ) after argument list

【方括号运算符】

  当通过方括号运算符([])来访问对象的属性时,属性名通过字符串来表示。字符串是javascript的数据类型,在程序运行中可以修改和创建它们

  使用方括号运算符有两个优点

  【1】可以通过变量来访问属性

var a = 1;
var o = {
1: 10
}
o[a];//

  【2】属性名称可以为javascript无效标识符

var myObject = {
123:'zero',
class:'foo'
};
console.log(myObject['123'],myObject['class']);//'zero' 'foo'
console.log(myObject.123);//报错

  方括号中的值若是非字符串类型会使用String()隐式转换成字符串再输出;如果是字符串类型,若有引号则原值输出,否则会被识别为变量,若变量未定义,则报错

var person = {};
person[0]; //[]中的数字不会报错,而是自动转换成字符串
person[a]; //[]中符合变量命名规则的元素会被当成变量,变量未被定义,而报错
person['']; //[]中的空字符串不会报错,是实际存在的且可以调用,但不会在控制台右侧的集合中显示 person[undefined];//不会报错,而是自动转换成字符串
person[null];//不会报错,而是自动转换成字符串
person[true];//不会报错,而是自动转换成字符串
person[false];//不会报错,而是自动转换成字符串

可计算属性名

  在方括号运算符内部可以使用表达式

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'

属性查询错误

  【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) {...} // 不报错

属性设置

  属性设置又称为属性赋值,与属性查询相同,具有点运算符和方括号运算符这两种方法

o.p = 'abc';
o['p'] = 'abc';

  在给对象设置属性之前,一般要先检测对象是否存在

var len = undefined;
if(book){
if(book.subtitle){
len = book.subtitle.length;
}
}

  上面代码可以简化为

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

  [注意]关于逻辑与&&运算符的应用移步至此

  nullundefined不是对象,给它们设置属性会报错

null.a = 1;//Uncaught TypeError: Cannot set property 'a' of null
undefined.a = 1;//Uncaught TypeError: Cannot set property 'a' of undefined

  由于stringnumberboolean有对应的包装对象,所以给它们设置属性不会报错

'abc'.a = 1;//
(1).a = 1;//
true.a = 1;//

属性删除

  使用delete运算符可以删除对象属性(包括数组元素)

var o = {
a : 1
};
console.log(o.a);//
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;//

  delete运算符只能删除自有属性,不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响到所有继承自这个原型的对象)

var o  = {
a:1
}
var obj = Object.create(o);
obj.a = 2; console.log(obj.a);//
console.log(delete obj.a);//true
console.log(obj.a);//
console.log(delete obj.a);//true
console.log(obj.a);//

返回值

  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);// '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对象都和另一个对象相关联。“另一个对象”就是我们熟知的原型,每一个对象都从原型继承属性。所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过Object.prototype获得对原型对象的引用

var obj = {};
console.log(obj.__proto__ === Object.prototype);//true

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

console.log(Object.prototype.__proto__ === null);//true

  对象本身具有的属性叫自有属性(own property),从原型对象继承而来的属性叫继承属性

var o = {a:1};
var obj = Object.create(o);
obj.b = 2;
//继承自原型对象o的属性a
console.log(obj.a);//
//自有属性b
console.log(obj.b);//

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

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
}

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

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']

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']

参考资料

【1】 W3School-Javascript高级教程——对象应用 http://www.w3school.com.cn/js/
【2】 阮一峰Javascript标准参考教程——对象 http://javascript.ruanyifeng.com/grammar/object.html
【3】《javascript权威指南(第6版)》第6章 对象
【4】《javascript高级程序设计(第3版)》第6章 面向对象的程序设计
【5】《javascript语句精粹》第3章 对象
【6】《javascript面向对象精要》 第3章 理解对象
【7】《你不知道的javascript上卷》第3章 对象
【8】《ECMAScript6入门》 第7章 对象的扩展

最新文章

  1. FFT 模板
  2. NuGet的几个小技巧
  3. POJ 1860 Currency Exchange (最短路)
  4. 浅谈 Active Learning
  5. [LeetCode#277] Find the Celebrity
  6. Java基础知识强化99:Java 常见异常及趣味解释
  7. Android开发系列(十八):自己定义控件样式在drawable目录下的XML实现
  8. DELL RACADM 工具使用介绍
  9. HTTP methods 与 RESTful API
  10. java.lang.NoClassDefFoundError 异常
  11. 团队作业1 团队展示&amp;选题
  12. HDOJ--4893--Wow! Such Sequence!【线段树+单点、区间更新】
  13. 快速了解react
  14. 从壹开始 [ Id4 ] 之二║ 基础知识集合 &amp; 项目搭建一
  15. day1.接口测试(概念、Postman、SoapUI、jmeter)
  16. [Android Pro] AndroidX了解一下
  17. C++11 列表初始化
  18. php __FILE__ symlink
  19. innerHTML用法及错误:无法设置未定义或null引用的属性“innerHTML”解决
  20. Warning:The /usr/local/mysql/data directory is not owned by the &#39;mysql&#39; or &#39;_mysql&#39;

热门文章

  1. Linux 时间时区同步
  2. js基础3
  3. Poco::JSON::Array 中object 设置preserveInsertionOrder 时,stringify出错--&gt;深入解析
  4. Unity3D 与android交互流程步骤
  5. 爬虫初探(1)之urllib.request
  6. asp.net 生成图形验证码(字母和数字混合)
  7. poj3750-小孩报数问题(约瑟夫环)
  8. 自定义cell右侧 多按钮
  9. Servant:基于Web的IIS管理工具
  10. 尝试解决在构造函数中同步调用Dns.GetHostAddressesAsync()引起的线程死锁