前面的话

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

属性查询

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

  1. var o = {
  2. p: 'Hello World'
  3. };
  4. o.p // "Hello World"
  5. o['p'] // "Hello World"

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

  1. var person = {
  2. : 1
  3. }
  4. person.白;//
  5. person['白'];//

【点运算符】

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

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

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

【方括号运算符】

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

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

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

  1. var a = 1;
  2. var o = {
  3. 1: 10
  4. }
  5. o[a];//

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

  1. var myObject = {
  2. 123:'zero',
  3. class:'foo'
  4. };
  5. console.log(myObject['123'],myObject['class']);//'zero' 'foo'
  6. console.log(myObject.123);//报错

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

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

可计算属性名

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

  1. var a = 1;
  2. var person = {
  3. 3: 'abc'
  4. };
  5. person[a + 2];//'abc'

  但如果要在对象字面量内部对属性名使用表达式,则需要使用ES6的可计算属性名

  1. var a = 1;
  2. //Uncaught SyntaxError: Unexpected token +
  3. var person = {
  4. a + 3: 'abc'
  5. };

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

  1. var a = 1;
  2. var person = {
  3. [a + 3]: 'abc'
  4. };
  5. person[4];//'abc'

属性查询错误

  【1】查询一个不存在的属性不会报错,而是返回undefined

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

  【2】如果对象不存在,试图查询这个不存在的对象的属性会报错

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

  可以利用这一点,来检查一个全局变量是否被声明

  1. // 检查a变量是否被声明
  2. if (a) {...} // 报错
  1. //所有全局变量都是window对象的属性。window.a的含义就是读取window对象的a属性,如果该属性不存在,就返回undefined,并不会报错
  2. if (window.a) {...} // 不报错

属性设置

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

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

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

  1. var len = undefined;
  2. if(book){
  3. if(book.subtitle){
  4. len = book.subtitle.length;
  5. }
  6. }

  上面代码可以简化为

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

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

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

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

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

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

属性删除

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

  1. var o = {
  2. a : 1
  3. };
  4. console.log(o.a);//
  5. console.log('a' in o);//true
  6. console.log(delete o.a);//true
  7. console.log(o.a);//undefined
  8. console.log('a' in o);//false

  [注意]给对象属性置null或undefined,并没有删除该属性

  1. var o = {
  2. a : 1
  3. };
  4. o.a = undefined;
  5. console.log(o.a);//undefined
  6. console.log('a' in o);//true
  7. console.log(delete o.a);//true
  8. console.log(o.a);//undefined
  9. console.log('a' in o);//false

  使用delete删除数组元素时,不会改变数组长度

  1. var a = [1,2,3];
  2. delete a[2];
  3. 2 in a;//false
  4. a.length;//

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

  1. var o = {
  2. a:1
  3. }
  4. var obj = Object.create(o);
  5. obj.a = 2;
  6.  
  7. console.log(obj.a);//
  8. console.log(delete obj.a);//true
  9. console.log(obj.a);//
  10. console.log(delete obj.a);//true
  11. console.log(obj.a);//

返回值

  delete操作符的返回值是个布尔值true或false

  【1】当使用delete操作符删除对象属性或数组元素删除成功时,返回true

  1. var o = {a:1};
  2. var arr = [1];
  3. console.log(delete o.a);//true
  4. console.log(delete arr[0]);//true

  【2】当使用delete操作符删除不存在的属性或非左值时,返回true

  1. var o = {};
  2. console.log(delete o.a);//true
  3. console.log(delete 1);//true
  4. console.log(delete {});//true

  【3】当使用delete操作符删除变量时,返回false,严格模式下会抛出ReferenceError错误

  1. var a = 1;
  2. console.log(delete a);//false
  3. console.log(a);//
  4.  
  5. 'use strict';
  6. var a = 1;
  7. //Uncaught SyntaxError: Delete of an unqualified identifier in strict mode
  8. console.log(delete a);

  【4】当使用delete操作符删除不可配置的属性时,返回false,严格模式下会抛出TypeError错误

  1. var obj = {};
  2. Object.defineProperty(obj,'a',{configurable:false});
  3. console.log(delete obj.a);//false
  4.  
  5. 'use strict';
  6. var obj = {};
  7. Object.defineProperty(obj,'a',{configurable:false});
  8. //Uncaught TypeError: Cannot delete property 'a' of #<Object>
  9. console.log(delete obj.a);

属性继承

  每一个javascript对象都和另一个对象相关联。“另一个对象”就是我们熟知的原型,每一个对象都从原型继承属性。所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过Object.prototype获得对原型对象的引用

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

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

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

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

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

in

  in操作符可以判断属性在不在该对象上,但无法区别自有还是继承属性

  1. var o = {a:1};
  2. var obj = Object.create(o);
  3. obj.b = 2;
  4. console.log('a' in obj);//true
  5. console.log('b' in obj);//true
  6. console.log('b' in o);//false

for-in

  通过for-in循环可以遍历出该对象中所有可枚举属性 

  1. var o = {a:1};
  2. var obj = Object.create(o);
  3. obj.b = 2;
  4. for(var i in obj){
  5. console.log(obj[i]);//2 1
  6. }

hasOwnProperty()

  通过hasOwnProperty()方法可以确定该属性是自有属性还是继承属性

  1. var o = {a:1};
  2. var obj = Object.create(o);
  3. obj.b = 2;
  4. console.log(obj.hasOwnProperty('a'));//false
  5. console.log(obj.hasOwnProperty('b'));//true

Object.keys()

  Object.keys()方法返回所有可枚举的自有属性

  1. var o = {a:1};
  2. var obj = Object.create(o,{
  3. c:{value:3,configurable: false}
  4. });
  5. obj.b = 2;
  6. console.log(Object.keys(obj));//['b']

Object.getOwnPropertyNames()

  与Object.keys()方法不同,Object.getOwnPropertyNames()方法返回所有自有属性(包括不可枚举的属性)

  1. var o = {a:1};
  2. var obj = Object.create(o,{
  3. c:{value:3,configurable: false}
  4. });
  5. obj.b = 2;
  6. 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章 对象的扩展

深入理解javascript对象系列第二篇——属性操作的更多相关文章

  1. 深入理解javascript函数系列第二篇——函数参数

    × 目录 [1]arguments [2]内部属性 [3]函数重载[4]参数传递 前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传 ...

  2. 深入理解javascript作用域系列第二篇——词法作用域和动态作用域

    × 目录 [1]词法 [2]动态 前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极 ...

  3. 深入理解javascript作用域系列第二篇

    前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极易出错.这实际上是由两种作用域工作 ...

  4. 深入理解javascript对象系列第一篇——初识对象

    × 目录 [1]定义 [2]创建 [3]组成[4]引用[5]方法 前面的话 javascript中的难点是函数.对象和继承,前面已经介绍过函数系列.从本系列开始介绍对象部分,本文是该系列的第一篇——初 ...

  5. 深入理解javascript函数系列第一篇——函数概述

    × 目录 [1]定义 [2]返回值 [3]调用 前面的话 函数对任何一门语言来说都是一个核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即 ...

  6. 深入理解javascript函数系列第一篇

    前面的话 函数对任何一门语言来说都是核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即对象,程序可以随意操控它们.函数可以嵌套在其他函数中 ...

  7. 深入理解javascript作用域系列第一篇——内部原理

    × 目录 [1]编译 [2]执行 [3]查询[4]嵌套[5]异常[6]原理 前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域 ...

  8. 深入理解javascript作用域系列第一篇

    前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域貌似简单,实则复杂,由于作用域与this机制非常容易混淆,使得理解作用域的原 ...

  9. 深入理解javascript对象系列第三篇——神秘的属性描述符

    × 目录 [1]类型 [2]方法 [3]详述[4]状态 前面的话 对于操作系统中的文件,我们可以驾轻就熟将其设置为只读.隐藏.系统文件或普通文件.于对象来说,属性描述符提供类似的功能,用来描述对象的值 ...

随机推荐

  1. WindowManager massge和handler

    在一个可移动浮动按钮的demo源码学习中,有一些WindowManager的使用,在此做下总结. 1.翻译过来就是窗口管理,是和应用框架层的窗口管理器交互的接口,通过 mWindowManager = ...

  2. 命名困惑系列之一:关于state和status的粗浅研究

    牛津高阶词汇的解释 state: CONDITION OF SB/STH  状态:the mental,emotional or physical condition that a person or ...

  3. call,apply学习小结

    之前一直不太清楚js的call,apply的作用是什么,直到看到了这篇博文 http://blog.csdn.net/myhahaxiao/article/details/6952321 functi ...

  4. Python之路【第五篇】python基础 之初识函数(一)和文件管理

    转载请注明出处http://www.cnblogs.com/wupeiqi/articles/5453708.html 函数 一.背景                                 ...

  5. C++ 小知识积累

    (1)setw和setfill函数 #include<iomanip> 代码: #include<iostream> #include<iomanip> using ...

  6. Ubuntu安装c++编译器

    打开终端输入sudo apt-get install build-essential 安装gcc和一些库函数.提供C/C++的编译环境 注意编译c++程序要用g++

  7. 一鼓作气 博客--第七篇 note7

    面向对象相关知识简介 类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类变量:类变量在整个实例化的对象中是公用的.类变量定义 ...

  8. ICollection

    ICollection 接口是 System.Collections 命名空间中类的基接口.ICollection 接口扩展 IEnumerable:IDictionary 和 IList 则是扩展 ...

  9. min.js反压缩

    给个网址自己体会.. http://jsbeautifier.org/ 当需要修改min.js中的代码时,把min.js文件ctrl+c   ctrl+v扔到上面的网页里,点击beautify 即可

  10. C# DataSet

    一.基本概念 DataSet是ADO.NET的中心概念.可以把DataSet当成内存中的数据库,DataSet是不依赖于数据库的独立数据集合.所谓独立,就是说,即使断开数据链路,或者关闭数据库,Dat ...