详解JavaScript权威指南之对象


Posted in Javascript onSeptember 27, 2016

JavaScript对象可以看作是属性的无序集合,每个属性就是一个键值对,可增可删。

JavaScript中的所有事物都是对象:字符串、数字、数组、日期,等等。

JavaScript对象除了可以保持自有的属性外,还可以从一个称为原型的对象继承属性。对象的方法通常是继承的属性。这种“原型式集成”是JavaScript的的核心特征。

1.创建对象

第一种:对象直接量表示法创建对象。

这是最简单的对象创建方式,对象直接量由若干key:value键值对属性组成,属性之间用逗号分隔,整个对象用花括号括起来。

var empty = {}; //不包含任何属性的对象
var point = { x: 3, y: 5 }; //包含两个属性的对象
var point2 = { x: point.x + 1, y: point.y + 1 }; //属性值可以是表达式
var book = {
"main title": "JavaScript", //属性名有空格,必须用字符串表示
"sub-title": "The Defintive Guide", //属性名有连字符,必须用字符串表示
"for": "all audiences", //属性名是保留字,必须用字符串表示
author: { //这个属性的值是一个对象
firstname: "David",
surname: "Flanagan"
}

ECMAScript 5版本中,使用保留字属性名可以不用引号引起来。对象直接量最后一个属性后的逗号自动忽略。

第二种:通过关键字创建对象。

关键字new用来创建并初始化对象,后面跟一个构造函数。JavaScript语言核心中原始类型都包含内置构造函数,下面是内置对象创建演示。

var o = new Object(); //创建一个空对象,等价于 0={}
var a = new Array(); //创建一个空数组
var d = new Date(); //创建一个代表当前时间的Date对象
var r = new RegExp("js"); //创建一个正则表达式对象

除了这些内置构造函数,使用自定义构造函数来初始化新对象也很常见。

介绍第三种方法之前需要先简单了解“原型”的概念。每一个JavaScript对象(null除外)都有一个关联对象,并且可以从关联对象继承属性。这个关联对象就是所谓的“原型”,类似于C#中的基类。

所有通过对象直接量和构造函数创建的对象都可以通过Object.prototype获得原型对象的引用。没有原型的对象为数不多,Object.prototype就是其中之一。

普通对象都有原型,比如Array数组对象的原型是Array.prototype。同时,内置构造函数都具有一个继承Object.prototype的原型。因此,通过new Array()创建的数组对象的属性同时继承至Array.prototype和Object.prototype,当对象出现多继承关系时,那么这一系列链接的原型对象就被称作“原型链”。

第三种:使用Object.create()函数创建对象。

Object.create(Object[,Properties])是ECMAScript 5版本出现的一个静态函数,用来创建对象。它接收两个参数:第一个是要创建对象的原型;第二个是可选参数,用来描述对象属性。

使用它创建对象,只需传入所需原型对象即可:

var a = Object.create({ 'isLock': true }); //为对象a指定一个原型
console.log(a.isLock); //=> true o继承原型对象属性isLock
console.log(a.hasOwnProperty('isLock')); //=> false 验证isLock并非o的自有属性

创建一个普通的空对象,需要传入参数Object.prototype:

var b = Object.create(Object.prototype);

可以通过传入参数null来创建没有原型的对象,该类对象不会继承任何东西:

var b = Object.create(null); //该对象不包括任何对象的基础方法

通过原型创建对象,可以使任意对象可继承,这是一个强大的特性。比如可以防止程序无意修改不受控制的对象。程序不直接操作对象,而是操作通过Object.create()创建的继承对象。

2.查询和设置属性

对象属性值可以通过点.和方括号[]运算符来查询或设置。

var book = { 'author': 'Tom', 'main title': 'Hello JavaScript' };
var author = book.author; //1.获取book的“author”属性值
var title = book["main title"]; //2.获取book的“main title”属性值
book.edition = 6; //3.给book创建一个“edition”属性
book["main title"] = "ECMAScript"; //4.修改"main title"属性值

ES3版本中,如果属性名是关键字必须通过方括号的形式访问。ES5版本放宽了要求,可以直接在点运算符后面直接使用保留字。

关联数组对象

上面提到可以通过object["property"]操作对象属性,这种语法看起来更像数组,只是这个数组元素是通过字符串索引而不是数字索引,这类数组被称为关联数组。JavaScript对象都是关联数组,通过[]访问对象属性时,在程序运行时可以创建或修改它们,更有灵活性。

继承

JavaScript对象的属性分两种,一种是自己定义的,被称为“自有属性”。也有一些属性是从原型对象继承过来的。对象属性的多继承关系构成了原型链。

对象属性在赋值前会先检查原型链,以此判断是否允许赋值操作。例如,如果对象o继承自一个只读属性x,那么对x属性赋值是不允许的。如果允许属性赋值,也只是在原始对象上创建或对已有的属性赋值,而不会修改原型链。

JavaScript中,一般只有在查询属性的时候才能体会到继承的存在,而设置属性和继承无关。通过这个特性可以有选择的覆盖继承的属性。

属性访问错误

查询一个不存在的属性不会报错。如果在对象自身属性和继承的属性中没有找到指定属性,则返回undefined。通过下面一小段代码验证下:

var a = { name: 'admin' }; //定义一个原型对象a
var b = Object.create(a); //定义一个对象b继承至对象a
console.log(b.name); //=> admin b继承a的name属性,正常输出
console.log(b.age); //=>undefined b本身和继承对象都没有age属性,故输出undefined

但有一种情况:假如对象不存在,试图访问这个不存在对象的属性时则会抛异常。例如:

console.log(c.name); //Uncaught ReferenceError: c is not defined
var d = null;
console.log(d.name); //Uncaught TypeError: Cannot read property 'name' of null

所以,这就要求我们在访问不确定对象属性时需要验证一下。

var book = { "length": 21 };
var len = book && book.length; //这里用&&的第三种用法代替if。
console.log(len); //=>21

3.删除属性

delete运算符可以删除对象的属性,删除成功返回true。但是delete不能删除那些可配置型为false的属性。只能删除自身属性,不能删除继承属性。

delete book.author // 返回true

删除全局属性时,可以直接省略全局对象,delete后面跟上要删除的属性即可。

this.x=1; //创建一个全局属性
console.log(delete x); //=>true

4.检测属性

所谓检测属性就是判断某个属性时候存在与某个对象中。一般可以通过in运算符、hasOwnProperty()和propertyIsEnumerable()方法来完成验证工作。

in运算符判断,如果对象自有属性或继承属性包含这个属性则返回true。

var o = { "x": 5 };
console.log("x" in o); //=>true 对象o有属性x
console.log("y" in o); //=>false 对象o没有属性x
console.log("toString" in o); //=>true 对象o继承属性toString 
hasOwnProperty()方法用来检测给定属性是否为对象的自有属性,对于继承属性返回false。
var o = { "x": 5 };
console.log(o.hasOwnProperty("x")); //=>true
console.log(o.hasOwnProperty("toString")); //=>false 
propertyIsEnumerable()方法是hasOwnProperty()的增强版。只有检测到属性为对象的自有属性并且这个属性可枚举性时才返回true。
var o = Object.create({ "y": 5 });
o.x = 6;
console.log(o.propertyIsEnumerable("x")); //=>true x为自有属性
console.log(o.propertyIsEnumerable("y")); //=>false y是继承属性
console.log(Object.prototype.propertyIsEnumerable("toString")); //=>false toString不可枚举

5.属性存取器

ECMAScript 5版本中,对象可以用get和set关键字定义像C#、Java等高级语言一样的保护属性。这种属性被称为“存取器属性”,它是可以继承的。

var obj = {
//数据属性(可看成字段)
data: null,
//存取器属性(保护属性)
get Data() { return this.data; },
set Data(value) { this.data = value; }
};
obj.Data = "admin";
console.log(obj.data); //=>admin

怎么样,有没有感觉和JAVA中的保护属性写法很像。因为JavaScript本身就是一种面向对象的编程语言。

如果对象属性同时具有get和set方法,那么它是一个可读/写的属性。如果属性只有一个get方法,那么它是一个只读属性。如果属性只有一个set方法,那么它是一个只写属性,读取只写属性总是返回undefined。

6.属性的特性

ECMAScript 3版本下对象的属性都是否可写、可配置和可枚举的,但是到ECMAScript 5版本下是属性是可以通过一些API来标识是否为可写、可配置和可枚举的。这API也就是所谓的属性的特性。

•普通数据属性的4个特性:value(值)、writable(可写性)、enumerable(可枚举性)、configurable(可配置性)。

•存储器属性的4个特性:get(读取)、set(写入)、enumerable(可枚举性)、configurable(可配置性)。

ECMAScript 5中定义了一个Object.getOwnPropertyDescriptor()方法用来查询对象特定属性的特性,返回一个“属性描述符”对象,该对象就代表对象属性的4个特性。

var descriptor = Object.getOwnPropertyDescriptor({ length: 50 }, "length");
console.log(descriptor); 
//=> descriptor = { value: 50, writable: true, enumerable: true, configurable: true }
//------------------------------------------------------------------
var random = {
//只读属性:返回一个0-255之间的随机数
get octet() { return Math.floor(Math.random() * 256); }
};
var descriptor1= Object.getOwnPropertyDescriptor(random,"octet");
console.log(descriptor1); 
//=> descriptor1 = Object {set: undefined, enumerable: true, configurable: true}

从名字可以看出该方法只能得到对象自有属性的描述符,所以对于继承属性和不存在的属性,返回undefined。要获得继承属性的特性,需要遍历原型链。

要想设置属性或让新创建属性具有某种特性,则需要调用Object.defineProperty()方法,第一个参数是要修改的对象;第二个参数是要修改的属性;第三个是属性描述符对象。返回值为修改后的对象副本。

var o = {}; //创建一个空对象
Object.defineProperty(o, "x", {
value: 1, //定义一个x属性,赋值为1
writable: true, //可写
enumerable: false, //不可枚举
configurable: true //可配置
});
if (o.x) console.log(Object.keys(o)); //=> props = [] 属性存在,但是不能枚举
Object.defineProperty(o, "x", { writable: false }); //让属性x变为只读
o.x = 2; //试图修改属性x的值失败,但不报错
console.log(o.x); //=>1 
Object.defineProperty(o, "x", { value: 2 }); //但属性x依然为可配置,可以直接修改value值特性。
console.log(o.x); //=>2
Object.defineProperty(o, "x", { //将数据属性修改为存取器属性
get: function () {
return 0;
}
});
console.log(o.x); //=>0

该方法同样不能设置继承属性的特性。如果需要同时修改多个自有属性的特性可以使用Object.defineProperties()方法。第一个参数是要修改的对象;第二参数是一个映射表对象,它包含属性名称和对应属性的描述符对象。

var p = Object.defineProperties({}, {
x: { value: 3, writable: true, enumerable: true, configurable: true },
y: { value: 4, writable: true, enumerable: true, configurable: true },
r: {
get: function () {
return Math.sqrt(this.x * this.x + this.y * this.y);
},
enumerable: true,
configurable: true
}
});
console.log(p.r); //=>5

7.对象的三个属性

原型属性

对象的原型是用来继承属性的,这个属性非常重要,以至于经常把“o的原型属性”直接叫做“o的原型”。

原型属性是在对象创建之初就设置好的。前面已对原型做过介绍,但这里还是要补充补充。

•通过对象直接量创建的对象使用Object.prototype作为原型;

•通过new关键字创建的对象使用构造函数的prototype作为原型;

•通过Object.create()创建的对象使用第一个参数作为原型。

在ES5版本中,将对象传入Object.getPrototypeOf()方法可以查询它的原型对象。

想要检测一个对象是否是另一个对象的原型可以使用isPrototypeOf()方法。

var a = { x: 2 };
var b = Object.create(a);
console.log(a.isPrototypeOf(b)); //=> true
console.log(Object.prototype.isPrototypeOf(b));//=> true

类属性

对象的类属性是一个字符串,用来表示对象的类型信息。但是JS中没有提供直接查询方法,只能用一种间接的方法查询,可以调用对象的toString()方法,然后提取返回字符串的第8个字符至倒数第二个位置之间的字符。如果对象继承的toString()方法重写了,这时必须间接通过Function.call()方法调用。

function classof(o) {
if (o === null) return "Null";
if (o === undefined) return "Undefined";
return Object.prototype.toString.call(o).slice(8,-1);
}

classof()可以接收任何类型的参数,并且该函数包含了对null和undefined的特殊处理。

console.log(classof(null)); //=> "Null"
console.log(classof(1)); //=> "Number"
console.log(classof("")); //=> "String"
console.log(classof(false)); //=> "Boolen"
console.log(classof({})); //=> "Object"
console.log(classof(/./)); //=> "Regexp"
console.log(classof(window)); //=> "Window"(浏览器宿主对象类)

可扩展性

对象的可扩展行用来表示是否可以给对象添加新属性。ECMAScript 5版本中,所有自定义对象、内置对象和宿主对象默认支持可扩展性。下面介绍几个检测和设置对象可扩展性的方法以及它们之间的区别。

Object.preventExtensions()方法能将传入对象设置为不可扩展的。需要注意的两点是:1.一旦对象转为不可扩展的,就无法再将其转换成可扩展的;2.如果给一个不可扩展的对象的原型添加属性,这个不可扩展的对象同样会继承这些新属性。

Object.isExtensible()方法可以检测传入对象的可扩展性。

Object.seal()方法能将传入对象设置为不可扩展的,并且将对象所有自有属性都设置为不可配置的。也就是说不能给这个对象添加新属性,而且也不能删除或配置已有属性。对于已经密封的对象同样不能解封,可以使用Object.isSealed()方法检测对象是否封闭。

Object.freeze()方法更“狠”,它会直接将对象冻结。除了将对象设置为不可扩展和其属性设置为不可配置之外,还将对象自有属性的所有数据属性设置为只读属性。可以使用Object.isFrozen()方法检测对象是否被冻结。

Object.preventExtensions()、Object.seal()和Object.freeze()三个方法都返回传入的对象。

8.序列化对象

相信大家对JSON都不陌生,其实该小节就是介绍JSON序列化。所谓序列化就是JS对象和字符串之间的互相转换,JSON作为数据交换格式。ECMAScript 5 中提供两个内置函数JSON.stringify()和JSON.parse()用来序列化和还原JS对象。

var obj = { x: 3, y: 5 }; //定义一个测试对象
var str = JSON.stringify(obj); //str = "{"x":3,"y":5}"
obj = JSON.parse(str); //obj = Object {x: 3, y: 5}

JSON的全称是“JavaScript Object Notation”---JavaScript对象表示法。JSON的语法并不能表示JavaScript里所有的所有值。支持序列化和还原的有对象、NaN、数组、字符串、无穷大数字、true\false和null。函数、RegExp、Error对象和undefined值不能序列化和还原。JSON.stringify()函数只能序列化对象可枚举的自有属性。日期对象序列化的结果是ISO格式的日期字符串。

以上所述是小编给大家介绍的JavaScript权威指南之对象,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript 禁止复制网页
Jun 11 Javascript
JavaScript 对象模型 执行模型
Dec 06 Javascript
jQuery学习笔记[1] jQuery中的DOM操作
Dec 03 Javascript
jquery ui对话框实例代码
May 10 Javascript
js实现一个链接打开两个链接地址的方法
May 12 Javascript
JavaScript遍历求解数独问题的主要思路小结
Jun 12 Javascript
JS实现二叉查找树的建立以及一些遍历方法实现
Apr 17 Javascript
使用JavaScript实现表格编辑器(实例讲解)
Aug 02 Javascript
Vue组件开发之LeanCloud带图形校验码的短信发送功能
Nov 07 Javascript
JS动画实现回调地狱promise的实例代码详解
Nov 08 Javascript
vue tab切换,解决echartst图表宽度只有100px的问题
Jul 19 Javascript
ant design charts 获取后端接口数据展示
May 25 Javascript
Web性能优化系列 10个提升JavaScript性能的技巧
Sep 27 #Javascript
JS点击某个图标或按钮弹出文件选择框的实现代码
Sep 27 #Javascript
ReactNative页面跳转实例代码
Sep 27 #Javascript
JS控制HTML元素的显示和隐藏的两种方法
Sep 27 #Javascript
js仿支付宝多方框输入支付密码效果
Sep 27 #Javascript
jQuery实现右键菜单、遮罩等效果代码
Sep 27 #Javascript
jQuery实现图片轮播效果代码
Sep 27 #Javascript
You might like
phpcms模块开发之swfupload的使用介绍
2013/04/28 PHP
PHP设计模式之解释器模式的深入解析
2013/06/13 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(二)
2014/06/23 PHP
各种快递查询--Api接口
2016/04/26 PHP
PHP curl批处理及多请求并发实现方法分析
2018/08/15 PHP
javascript 数组操作详解
2015/01/29 Javascript
javascript实现 百度翻译 可折叠的分享按钮列表
2015/03/12 Javascript
javascript作用域链(Scope Chain)用法实例解析
2015/11/30 Javascript
Node.js环境下JavaScript实现单链表与双链表结构
2016/06/12 Javascript
JS监听微信、支付宝等移动app及浏览器的返回、后退、上一页按钮的事件方法
2016/08/05 Javascript
Bootstrap基本组件学习笔记之按钮组(8)
2016/12/07 Javascript
BootStrap与Select2使用小结
2017/02/17 Javascript
js实现华丽的九九乘法表效果
2017/03/29 Javascript
基于VUE选择上传图片并页面显示(图片可删除)
2017/05/25 Javascript
微信小程序注册60s倒计时功能 使用JS实现注册60s倒计时功能
2017/08/16 Javascript
jquery中有哪些api jQuery主要API
2017/11/20 jQuery
JS实现点击复选框变更DIV显示状态的示例代码
2017/12/18 Javascript
Vue父子组建的简单通信之控制开关Switch的实现
2018/06/04 Javascript
浅谈在vue中使用mint-ui swipe遇到的问题
2018/09/27 Javascript
用Python从零实现贝叶斯分类器的机器学习的教程
2015/03/31 Python
python开发之thread实现布朗运动的方法
2015/11/11 Python
对Python 网络设备巡检脚本的实例讲解
2018/04/22 Python
详解python之heapq模块及排序操作
2019/04/04 Python
python使用itchat模块给心爱的人每天发天气预报
2019/11/25 Python
python如何实现单链表的反转
2020/02/10 Python
python实现微信打飞机游戏
2020/03/24 Python
python实现猜数游戏(保存游戏记录)
2020/06/22 Python
土耳其风格手工珠宝:Ottoman Hands
2019/07/26 全球购物
保加利亚服装和鞋类购物网站:Bibloo.bg
2020/11/08 全球购物
软件测试工程师结构化面试题库
2016/11/23 面试题
幼儿园教师培训方案
2014/02/04 职场文书
公司员工检讨书
2014/02/08 职场文书
审计局班子四风对照检查材料思想汇报
2014/10/07 职场文书
新郎接新娘保证书
2015/05/08 职场文书
2015医院个人工作总结范文
2015/05/21 职场文书
在职证明范本
2015/06/15 职场文书