深入理解javascript对象系列第二篇——属性操作
2016-08-06 10:20
537 查看
×
目录
[1]查询 [2]设置 [3]删除[4]继承
[注意]变量中可以存在中文,因为中文相当于字符,与英文字符同样对待,因此可以写成person.白或person['白']
【点运算符】
点运算符是很多面向对象语句的通用写法,由于其比较简单,所以较方括号运算符相比,更常用
由于javascript是弱类型语言,在任何对象中都可以创建任意数量的属性。但当通过点运算符(.)访问对象的属性时,属性名用一个标识符来表示,标识符要符合变量命名规则。标识符必须直接出现在javascript程序中,它们不是数据类型,因此程序无法修改它们
【方括号运算符】
当通过方括号运算符([])来访问对象的属性时,属性名通过字符串来表示。字符串是javascript的数据类型,在程序运行中可以修改和创建它们
使用方括号运算符有两个优点
【1】可以通过变量来访问属性
【2】属性名称可以为javascript无效标识符
方括号中的值若是非字符串类型会使用String()隐式转换成字符串再输出;如果是字符串类型,若有引号则原值输出,否则会被识别为变量,若变量未定义,则报错
可计算属性名
在方括号运算符内部可以使用表达式
但如果要在对象字面量内部对属性名使用表达式,则需要使用ES6的可计算属性名
ES6增加了可计算属性名,可以在文字中使用[]包裹一个表达式来当作属性名
属性查询错误
【1】查询一个不存在的属性不会报错,而是返回undefined
【2】如果对象不存在,试图查询这个不存在的对象的属性会报错
可以利用这一点,来检查一个全局变量是否被声明
在给对象设置属性之前,一般要先检测对象是否存在
上面代码可以简化为
[注意]关于逻辑与&&运算符的应用移步至此
null和undefined不是对象,给它们设置属性会报错
由于string、number和boolean有对应的包装对象,所以给它们设置属性不会报错
[注意]给对象属性置null或undefined,并没有删除该属性
使用delete删除数组元素时,不会改变数组长度
delete运算符只能删除自有属性,不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响到所有继承自这个原型的对象)
返回值
delete操作符的返回值是个布尔值true或false
【1】当使用delete操作符删除对象属性或数组元素删除成功时,返回true
【2】当使用delete操作符删除不存在的属性或非左值时,返回true
【3】当使用delete操作符删除变量时,返回false,严格模式下会抛出ReferenceError错误
【4】当使用delete操作符删除不可配置的属性时,返回false,严格模式下会抛出TypeError错误
[注意]Object.prototype的原型对象是null,所以它不继承任何属性
对象本身具有的属性叫自有属性(own property),从原型对象继承而来的属性叫继承属性
in
in操作符可以判断属性在不在该对象上,但无法区别自有还是继承属性
for-in
通过for-in循环可以遍历出该对象中所有的可枚举的属性
hasOwnProperty()
通过hasOwnProperty()方法可以确定该属性是自有属性还是继承属性
Object.keys()
Object.keys()方法返回所有可枚举的自有属性
Object.getOwnPropertyNames()
与Object.keys()方法不同,Object.getOwnPropertyNames()方法返回所有自有属性(包括不可枚举的属性)
【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章 对象的扩展
// var all = document.getElementById('cnblogs_post_body').children;
var select = [];
for(var i = 1; i < all.length; i++){
if(all[i].getAttribute('id')){
if(all[i].getAttribute('id').match(/anchor\d+$/)){
select.push(all[i]);
}
}
}
var wheel = function(e){
e = e || event;
var data;
if(e.wheelDelta){
data = e.wheelDelta;
}else{
data = -e.detail * 40;
}
for(var i = 0; i < select.length; i++){
if(select[i].getBoundingClientRect().top > 0){
return;
}
if(select[i].getBoundingClientRect().top <= 0 && select[i+1]){
if(select[i+1].getBoundingClientRect().top > 0){
change(oCon.children[i+2])
}
}else{
change(oCon.children[select.length+1])
}
}
}
document.body.onmousewheel = wheel;
document.body.addEventListener('DOMMouseScroll',wheel,false);
var oCon = document.getElementById("content");
var close = oCon.getElementsByTagName('span')[0];
close.onclick = function(){
if(this.innerHTML == '显示目录'){
this.innerHTML = '×';
this.style.background = '';
oCon.style.border = '2px solid #ccc';
oCon.style.width = '';
oCon.style.height = '';
oCon.style.overflow = '';
oCon.style.lineHeight = '30px';
}else{
this.innerHTML = '显示目录';
this.style.background = '#3399ff';
oCon.style.border = 'none';
oCon.style.width = '60px';
oCon.style.height = '30px';
oCon.style.overflow = 'hidden';
oCon.style.lineHeight = '';
}
}
for(var i = 2; i < oCon.children.length; i++){
oCon.children[i].onmouseover = function(){
this.style.color = '#3399ff';
}
oCon.children[i].onmouseout = function(){
this.style.color = 'inherit';
if(this.mark){
this.style.color = '#3399ff';
}
}
oCon.children[i].onclick = function(){
change(this);
}
}
function change(_this){
for(var i = 2; i < oCon.children.length; i++){
oCon.children[i].mark = false;
oCon.children[i].style.color = 'inherit';
oCon.children[i].style.textDecoration = 'none';
oCon.children[i].style.borderColor = 'transparent';
}
_this.mark = true;
_this.style.color = '#3399ff';
_this.style.textDecoration = 'underline';
_this.style.borderColor = '#2175bc';
}
// ]]>
目录
[1]查询 [2]设置 [3]删除[4]继承
前面的话
对于对象来说,属性操作是绕不开的话题。类似于“增删改查”的基本操作,属性操作分为属性查询、属性设置、属性删除,还包括属性继承。本文是对象系列的第二篇——属性操作属性查询
属性查询一般有两种方法,包括点运算符和方括号运算符var o = { p: 'Hello World' }; o.p // "Hello World" o['p'] // "Hello World"
[注意]变量中可以存在中文,因为中文相当于字符,与英文字符同样对待,因此可以写成person.白或person['白']
var person = { 白 : 1 } person.白;//1 person['白'];//1
【点运算符】
点运算符是很多面向对象语句的通用写法,由于其比较简单,所以较方括号运算符相比,更常用
由于javascript是弱类型语言,在任何对象中都可以创建任意数量的属性。但当通过点运算符(.)访问对象的属性时,属性名用一个标识符来表示,标识符要符合变量命名规则。标识符必须直接出现在javascript程序中,它们不是数据类型,因此程序无法修改它们
var o = { a:1, 1:2 }; console.log(o.a);//1 //由于变量不可以以数字开头,所以o.1报错 console.log(o.1);//Uncaught SyntaxError: missing ) after argument list
【方括号运算符】
当通过方括号运算符([])来访问对象的属性时,属性名通过字符串来表示。字符串是javascript的数据类型,在程序运行中可以修改和创建它们
使用方括号运算符有两个优点
【1】可以通过变量来访问属性
var a = 1; var o = { 1: 10 } o[a];//10
【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;
[注意]关于逻辑与&&运算符的应用移步至此
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
返回值
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对象都和另一个对象相关联。“另一个对象”就是我们熟知的原型,每一个对象都从原型继承属性。所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过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);//1 //自有属性b console.log(obj.b);//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
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章 对象的扩展
// var all = document.getElementById('cnblogs_post_body').children;
var select = [];
for(var i = 1; i < all.length; i++){
if(all[i].getAttribute('id')){
if(all[i].getAttribute('id').match(/anchor\d+$/)){
select.push(all[i]);
}
}
}
var wheel = function(e){
e = e || event;
var data;
if(e.wheelDelta){
data = e.wheelDelta;
}else{
data = -e.detail * 40;
}
for(var i = 0; i < select.length; i++){
if(select[i].getBoundingClientRect().top > 0){
return;
}
if(select[i].getBoundingClientRect().top <= 0 && select[i+1]){
if(select[i+1].getBoundingClientRect().top > 0){
change(oCon.children[i+2])
}
}else{
change(oCon.children[select.length+1])
}
}
}
document.body.onmousewheel = wheel;
document.body.addEventListener('DOMMouseScroll',wheel,false);
var oCon = document.getElementById("content");
var close = oCon.getElementsByTagName('span')[0];
close.onclick = function(){
if(this.innerHTML == '显示目录'){
this.innerHTML = '×';
this.style.background = '';
oCon.style.border = '2px solid #ccc';
oCon.style.width = '';
oCon.style.height = '';
oCon.style.overflow = '';
oCon.style.lineHeight = '30px';
}else{
this.innerHTML = '显示目录';
this.style.background = '#3399ff';
oCon.style.border = 'none';
oCon.style.width = '60px';
oCon.style.height = '30px';
oCon.style.overflow = 'hidden';
oCon.style.lineHeight = '';
}
}
for(var i = 2; i < oCon.children.length; i++){
oCon.children[i].onmouseover = function(){
this.style.color = '#3399ff';
}
oCon.children[i].onmouseout = function(){
this.style.color = 'inherit';
if(this.mark){
this.style.color = '#3399ff';
}
}
oCon.children[i].onclick = function(){
change(this);
}
}
function change(_this){
for(var i = 2; i < oCon.children.length; i++){
oCon.children[i].mark = false;
oCon.children[i].style.color = 'inherit';
oCon.children[i].style.textDecoration = 'none';
oCon.children[i].style.borderColor = 'transparent';
}
_this.mark = true;
_this.style.color = '#3399ff';
_this.style.textDecoration = 'underline';
_this.style.borderColor = '#2175bc';
}
// ]]>
相关文章推荐
- 深入理解javascript对象系列第三篇——神秘的属性描述符
- Android源码系列之深入理解ImageView的ScaleType属性
- 深入理解闭包系列第二篇——从执行环境角度看闭包
- 深入理解DOM事件机制系列第二篇——事件处理程序
- 深入理解this机制系列第二篇——this绑定优先级
- 深入理解脚本化CSS系列第二篇——查询计算样式
- 深入理解javascript作用域系列第二篇——词法作用域和动态作用域
- 深入理解DOM事件类型系列第二篇——键盘事件
- ElasticSearch-深入理解系列6 -文档操作
- 深入理解ajax系列第二篇——请求方式
- 深入理解DOM事件类型系列第二篇——键盘事件
- 深入理解javascript函数系列第三篇——属性和方法
- 深入理解脚本化CSS系列第二篇——查询计算样式
- 深入理解javascript对象系列第一篇——初识对象
- 深入理解Django中的ORM数据库操作(Django系列1)
- 深入理解webkit内核系列第二篇:JavaScript引擎深度解析
- 深入理解闭包系列第二篇——从执行环境角度看闭包
- 深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame
- 深入理解javascript选择器API系列第二篇——getElementsByClassName
- 深入理解DOM事件机制系列第二篇——事件处理程序