详解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 相关文章推荐
JS动态添加option和删除option(附实例代码)
Apr 01 Javascript
JavaScript常用验证函数实例汇总
Nov 25 Javascript
jQuery实现表格行上下移动和置顶效果
Jun 05 Javascript
JS特效实现图片自动播放并可控的效果
Jul 31 Javascript
Jquery实现的简单轮播效果【附实例】
Apr 19 Javascript
原生的强大DOM选择器querySelector介绍
Dec 21 Javascript
Angular.JS中的指令引用template与指令当做属性详解
Mar 30 Javascript
jQuery使用bind函数实现绑定多个事件的方法
Oct 11 jQuery
Bootstrap-table使用footerFormatter做统计列功能
Sep 07 Javascript
点击按钮弹出模态框的一系列操作代码实例
Mar 29 Javascript
JavaScript中的惰性载入函数及优势
Feb 18 Javascript
js实现3D旋转相册
Aug 02 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
不用GD库生成当前时间的PNG格式图象的程序
2006/10/09 PHP
用PHP中的 == 运算符进行字符串比较
2006/11/26 PHP
php cookis创建实现代码
2009/03/16 PHP
php操作mysql数据库的基本类代码
2014/02/25 PHP
跟我学Laravel之配置Laravel
2014/10/15 PHP
详解php用curl调用接口方法,get和post两种方式
2017/01/13 PHP
php基于环形链表解决约瑟夫环问题示例
2017/11/07 PHP
jquery右下角弹出提示框示例代码
2013/10/08 Javascript
15个jquery常用方法、小技巧分享
2015/01/13 Javascript
jquery实现未经美化的简洁TAB菜单效果
2015/08/28 Javascript
js判断移动端是否安装某款app的多种方法
2015/12/18 Javascript
JS判断两个对象内容是否相等的方法示例
2017/04/10 Javascript
JS通过调用微信API实现微信支付功能的方法示例
2017/06/29 Javascript
React-Native 组件之 Modal的使用详解
2017/08/08 Javascript
AngularJS实现表单验证功能详解
2017/10/12 Javascript
vue中使用element-ui进行表单验证的实例代码
2018/06/22 Javascript
VUE 实现复制内容到剪贴板的两种方法
2019/04/24 Javascript
JS使用iView的Dropdown实现一个右键菜单
2019/05/06 Javascript
node使用mysql获取数据库数据中文乱码问题的解决
2019/12/02 Javascript
python实现zencart产品数据导入到magento(python导入数据)
2014/04/03 Python
python中元类用法实例
2014/10/10 Python
Python实现的简单发送邮件脚本分享
2014/11/07 Python
python解决字符串倒序输出的问题
2018/06/25 Python
在python中pandas读文件,有中文字符的方法
2018/12/12 Python
详解程序意外中断自动重启shell脚本(以Python为例)
2019/07/26 Python
python numpy 常用随机数的产生方法的实现
2019/08/21 Python
浅析Python的命名空间与作用域
2020/11/25 Python
Html5页面内使用JSON动画的实现
2019/01/29 HTML / CSS
AmazeUI导航的示例代码
2020/08/14 HTML / CSS
苹果音乐订阅:Apple Music
2018/08/02 全球购物
新闻系毕业生推荐信
2013/11/16 职场文书
2015年安全工作总结范文
2015/04/02 职场文书
学校禁毒宣传活动总结
2015/05/08 职场文书
Python 中数组和数字相乘时的注意事项说明
2021/05/10 Python
python 如何执行控制台命令与操作剪切板
2021/05/20 Python
python数据分析之单因素分析线性拟合及地理编码
2022/06/25 Python