JavaScript高级程序设计(第3版)学习笔记10 再访js对象


Posted in Javascript onOctober 11, 2012

1、对象再认识

(1)对象属性和特性

什么是属性(Property),什么是特性(Attribute),这有什么区别?我不想也不会从语义学上去区分,对于这系列文章来说,属性就是组成对象的一个部分,广义上也包括对象的方法,而特性则是指被描述主体所具有的特征,换句话说,属性是我们可以通过编码来访问的具体存在,而特性则主要是为了便于理解概念的抽象存在,当然,特性也可以通过相应的属性来具体外化。这一小节所讲的对象属性的特性就是对对象属性特征的一个描述,主要来自于ECMA-262规范的第5版,该规范使用两个中括号的形式来描述不能直接访问的内部特性。

A、属性类型(先给属性分下类):

  • 数据属性:直接访问属性值的属性
  • 访问器属性:通过getter/setter方法来访问属性值的属性
  • 内部属性:不能通过代码直接访问的属性,只是为了规范说明目的而存在,在规范中也使用两个中括号的形式来描述

B、对象内部属性

内部属性不能通过代码直接访问,它主要是为了描述规范,也是给ECMAScript实现者参考的,而对于开发者来说,了解这些可以便于理解一些内部机制。比如在给一个属性赋值时,在实现中会调用[[Put]]内部方法,而读取一个属性值时,则调用[[Get]]方法。

所有对象公共的内部属性 个别对象特有的内部属性
名称 规范 名称 规范 对象
[[Prototype]] Object/Null [[PrimitiveValue]] primitive Boolean|Date|Number|String
[[Class]] String [[Construct]] SpecOp(a List of any) → Object new
[[Extensible]] Boolean [[Call]] SpecOp(any, a List of any) → any|Reference call
[[Get]] SpecOp (propName) →any [[HasInstance]] SpecOp(any) → Boolean Function
[[GetOwnProperty]] SpecOp (propName) →Undefined|Property Descriptor [[Scope]] Lexical Environment Function
[[GetProperty]] SpecOp (propName) →Undefined|Property Descriptor [[FormalParameters]] List of Strings Function
[[Put]] SpecOp (propName, any, Boolean) [ ] ECMAScript code Function
[[CanPut]] SpecOp (propName) → Boolean [[TargetFunction]] Object Function.prototype.bind
[[HasProperty]] SpecOp (propName) → Boolean [[BoundThis]] any Function.prototype.bind
[[Delete]] SpecOp (propName, Boolean) → Boolean [[BoundArguments]] List of any Function.prototype.bind
[[DefaultValue]] SpecOp (Hint) → primitive [[Match]] SpecOp(String, index) → MatchResult RegExp
[[DefineOwnProperty]] SpecOp (propName, PropDesc, Boolean) → Boolean [[ParameterMap]] Object  

说明:

  • 每一个对象都有一个原型对象[[Prototype]],一般我们不能在代码中直接访问这个内部属性,但可以通过Object.getPrototypeOf(object)来获取原型对象(在Firefox中可以通过__proto__来直接访问)。
  • 在Object.prototype.toString方法中,按照规范内建对象会返回包含[[Class]]的值“[object class]”,而内建对象的[[Class]]值就是相应的名称(比如Array对象的[[Class]]值为'Array'),因此可以通过Object.prototype.toString.call(value) == '[object Array]'来判断value是否是一个Array。
  • 给一个属性赋值时,后台调用[[Put]]来实现,获取一个属性值时,后台调用[[Get]]来获取。
  • 使用new操作符调用一个函数时,后台调用[[Construct]],而使用call方法来调用函数时,后台会调用[[Call]]
  • [[HasInstance]]方法返回给定参数是否是通过调用函数来创建的,和Object的方法isPrototypeOf(obj)类似。
  • 当一个函数被执行时,就会创建一个[[Scope]]对象,可以理解为[[Scope]]就是我们前面所说的活动对象,也就是说this、arguments、形参、函数内部定义的变量和函数都是的[[Scope]]对象的属性。

C、属性特性(用来描述属性的特性)

内部特性 配置属性 属性类型 数据类型 默认值 含义 备注
[[Configurable]] configurable 数据属性 访问器属性 Boolean true 能否通过delete删除属性从而重新定义属性 能否修改属性的特性 能否把属性修改为访问器特性 一旦把属性定义为不可配置的,就不能再变为可配置的 如果为false,不能做删除、也不能修改属性特性,但是允许修改属性值 非严格模式下会忽略相应操作,严格模式下则抛出异常
[[Enumerable]] enumerable 数据属性 访问器属性 Boolean true 能否通过for-in循环返回属性 为true时可以通过for-in来枚举,否则不能通过for-in枚举
[[Writable]] writable 数据属性 Boolean true 能否修改属性的值 为false时不能修改属性值,非严格模式下会忽略相应操作,严格模式下则抛出异常
[[Value]] value 数据属性 任意类型 undefined 属性值  
[[Get]] get 访问器属性 Undefined/Function undefined 读取属性时调用的函数 为一个函数时,会无参数调用这个函数,并将返回值作为属性值返回
[[Set]] set 访问器属性 Undefined/Function undefined 写入属性时调用的函数 为一个函数时,会将传入的值作为参数调用这个函数,赋给属性

说明:

  • 配置属性是指使用下面要讲的属性定义方法时用以定义相关特性的配置项名称。
  • 对于访问器属性,[[Get]]、[[Set]]不一定都有,没有[[Get]]的属性不能读(返回undefined,严格模式下抛出异常),没有[[Set]]的属性不能写(会忽略,严格模式下抛出异常)。
  • 注意区分对象内部属性和对象属性的特性。

D、属性定义方法(用来定义属性的方法)

最常见的定义属性的方法就是直接在对象上添加属性,比如obj.name = 'linjisong',这种情况下定义的属性所具有的内部特性都是默认的,如果想定义一个值不能被修改的属性要怎么做呢?在ES中给我们提供了几个方法用于实现类似的功能。

方法名 功能说明 参数和返回值 说明 调用示例
defineProperty() 定义一个属性 (1)目标对象 (2)属性的名字 (3)属性描述符对象 使用属性定义方法时 [[Enumerable]] [[Configurable]] [[Writable]] 默认值为false // 创建一个包含一个默认属性job的对象(job属性可以修改、删除、在for-in中枚举) var person = {job:'it'}; // 添加一个不能被修改、删除的name属性 Object.defineProperty(person, 'name', { value:'linjisong',//这里的配置属性和上面特性列表中的配置属性一致 enumerable:true }); // 定义多个属性(数据属性year和访问器属性age) Object.defineProperties(person, { year:{ value : 2012, configurable:true, writable:true }, age:{ get : function(){ return this.year-1983; } } }); var job = Object.getOwnPropertyDescriptor(person, 'job'); console.info(job.configurable);//true,直接添加属性时默认为true var name = Object.getOwnPropertyDescriptor(person, 'name'); console.info(name.configurable);//false,使用属性定义方法添加属性时默认为false console.info(person.name);//linjisong person.name = 'oulinhai';//由于不能修改,所以值不会改变,在严格模式下会抛出异常 console.info(person.name);//linjisong person.year = 2015; console.info(person.year);//2015 console.info(person.age);//32,在修改year的同时,也修改了age属性
defineProperties() 定义一组属性 (1)目标对象 (2)多个属性描述符组成的一个对象
getOwnPropertyDescriptor() 获取属性的特性 (1)目标对象 (2)属性的名字 (3)返回一个包括了属性特性的对象  

注:这些方法设置或获取的属性特殊和属性的类型有关,比如数据属性只能设置[[Confirurable]]、[[Enumerable]]、[[Writable]]、[[Value]]。

(2)防篡改对象

所谓防篡改对象,就是给对象一定级别的保护以防止在这个级别上对对象的变更,在ES5规范中,定义了依次升高的三种保护级别:

保护级别 描述 操作方法 判断方法 说明
不可扩展 不能给对象添加新属性和方法,但可以修改已有属性和方法 preventExtensions() isExtensible():不能扩展时返回false  
密封 不可扩展,并且已有成员的[[Configurable]]设置为false,不能删除属性,但可以修改属性值 seal() isSeal():被密封时返回true isSeal()为true时一定有isExtensible()为false
冻结 密封,其[[Writable]]设置为false,但如果定义了[[Set]],访问器属性仍然可写 freeze() isFrozen():被冻结时返回true isFrozen()为true时一定有isSeal()为true,isExtensible()为false

注:一旦定义成了防篡改对象,就不能撤销。

(3)对象的其它方法

名称 描述
create(prototype[,descriptors]) 创建一个具有指定原型且可选择性地包含指定属性的对象
getOwnPropertyNames(object) 返回对象的属性(方法)的名称
getPrototypeOf(object) 返回对象的原型
keys(object) 返回对象的可枚举属性(方法)的名称

这里的create(prototype[,descriptors])是一个非常有意思的方法,规范中这样描述它的行为:

[code]
①如果prototype不是Null或Object,抛出TypeError异常
②var obj = new Object()
③设置obj的内部属性[[Prototype]]为prototype
④如果descriptors存在且不为undefined,使用Object.defineProperties(obj,descriptors)来添加属性
⑤返回obj

Javascript 相关文章推荐
如何让easyui gridview 宽度自适应窗口改变及fitColumns应用
Jan 25 Javascript
JS在TextArea光标位置插入文字并实现移动光标到文字末尾
Jun 21 Javascript
2则自己编写的jQuery特效分享
Feb 26 Javascript
js实现星星打分效果的方法
Jul 05 Javascript
js改变css样式的三种方法推荐
Jun 28 Javascript
JS常见算法详解
Feb 28 Javascript
js导出Excel表格超出26位英文字符的解决方法ES6
Nov 15 Javascript
详解angular应用容器化部署
Aug 14 Javascript
深入理解react 组件类型及使用场景
Mar 07 Javascript
JS页面获取 session 值,作用域和闭包学习笔记
Oct 16 Javascript
Vue3 的响应式和以前有什么区别,Proxy 无敌?
May 20 Javascript
js编写简易的计算器
Jul 29 Javascript
JavaScript高级程序设计(第3版)学习笔记9 js函数(下)
Oct 11 #Javascript
JavaScript高级程序设计(第3版)学习笔记8 js函数(中)
Oct 11 #Javascript
JavaScript高级程序设计(第3版)学习笔记7 js函数(上)
Oct 11 #Javascript
JavaScript高级程序设计(第3版)学习笔记6 初识js对象
Oct 11 #Javascript
JavaScript高级程序设计(第3版)学习笔记5 js语句
Oct 11 #Javascript
JavaScript高级程序设计(第3版)学习笔记4 js运算符和操作符
Oct 11 #Javascript
JavaScript高级程序设计(第3版)学习笔记3 js简单数据类型
Oct 11 #Javascript
You might like
PHP模板引擎Smarty的缓存使用总结
2014/04/24 PHP
THINKPHP2.0到3.0有哪些改进之处
2015/01/04 PHP
在PHP 7下安装Swoole与Yar,Yaf的方法教程
2017/06/02 PHP
bootstrap改变按钮加载状态
2014/12/01 Javascript
JavaScript将Web页面内容导出到Word及Excel的方法
2015/02/13 Javascript
js仿QQ中对联系人向左滑动、滑出删除按钮的操作
2016/04/07 Javascript
详解JavaScript中this关键字的用法
2016/05/26 Javascript
JavaScript实现输入框与清空按钮联动效果
2016/09/09 Javascript
微信小程序中多个页面传参通信的学习与实践
2017/05/05 Javascript
详解用webpack把我们的业务模块分开打包的方法
2017/07/20 Javascript
探索Vue高阶组件的使用
2018/01/08 Javascript
Vue一个案例引发的递归组件的使用详解
2018/11/15 Javascript
微信小程序实现slideUp、slideDown滑动效果及点击空白隐藏功能示例
2018/12/11 Javascript
JS函数动态传递参数的方法分析【基于arguments对象】
2019/06/05 Javascript
vue循环数组改变点击文字的颜色
2019/10/14 Javascript
JavaScript命令模式原理与用法实例详解
2020/03/10 Javascript
vue使用微信扫一扫功能的实现代码
2020/04/11 Javascript
[01:21]辉夜杯战队访谈宣传片—CDEC
2015/12/25 DOTA
Python中使用支持向量机(SVM)算法
2017/12/26 Python
Django+JS 实现点击头像即可更改头像的方法示例
2018/12/26 Python
python实现顺时针打印矩阵
2019/03/02 Python
为何人工智能(AI)首选Python?读完这篇文章你就知道了(推荐)
2019/04/06 Python
即时搜索数百万张门票:SeatsForEveryone.com
2018/08/26 全球购物
沙特阿拉伯电子产品和家用电器购物网站:Black Box
2019/07/24 全球购物
毕业研究生的自我鉴定
2013/11/30 职场文书
2014年安全工作总结范文
2014/11/13 职场文书
高中生思想道德自我评价
2015/03/09 职场文书
2015最新婚礼主持词
2015/06/30 职场文书
资深HR教你写好简历中的自我评价
2019/05/07 职场文书
Oracle更换为MySQL遇到的问题及解决
2021/05/21 Oracle
python numpy中multiply与*及matul 的区别说明
2021/05/26 Python
特别篇动画《总之就是非常可爱 ~制服~》PV公开,2022年夏季播出
2022/04/04 日漫
OpenCV项目实践之停车场车位实时检测
2022/04/11 Python
Java后端 Dubbo retries 超时重试机制的解决方案
2022/04/14 Java/Android
Vue OpenLayer测距功能的实现
2022/04/20 Vue.js
使用Postman测试需要授权的接口问题
2022/06/21 Java/Android