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 相关文章推荐
浅谈JavaScript中变量和函数声明的提升
Aug 09 Javascript
Bootstrap基本组件学习笔记之下拉菜单(7)
Dec 07 Javascript
JS 组件系列之Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案
Jun 30 Javascript
详解JS中的this、apply、call、bind(经典面试题)
Sep 19 Javascript
vue树形结构获取键值的方法示例
Jun 21 Javascript
JS实现图片转换成base64的各种应用场景实例分析
Jun 22 Javascript
vue中使用better-scroll实现滑动效果及注意事项
Nov 15 Javascript
node.js中ws模块创建服务端和客户端,网页WebSocket客户端
Mar 06 Javascript
9个JavaScript日常开发小技巧
Oct 06 Javascript
vue使用Sass时报错问题的解决方法
Oct 14 Javascript
如何搭建一个完整的Vue3.0+ts的项目步骤
Oct 18 Javascript
react antd表格中渲染一张或多张图片的实例
Oct 28 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 页面编码声明方法详解(header或meta)
2010/03/12 PHP
PHP面向对象分析设计的61条军规小结
2010/07/17 PHP
php数据库配置文件一般做法分享
2012/07/07 PHP
PHP不用第三变量交换2个变量的值的解决方法
2013/06/02 PHP
解析linux下安装memcacheq(mcq)全过程笔记
2013/06/27 PHP
分享50个提高PHP执行效率的技巧
2015/12/26 PHP
php实现二叉树中和为某一值的路径方法
2018/10/14 PHP
js null,undefined,字符串小结
2010/08/21 Javascript
利用json获取字符出现次数的代码
2012/03/22 Javascript
jquery实现网站超链接和图片提示效果
2013/03/21 Javascript
JavaScript版的TwoQueues缓存模型
2014/12/29 Javascript
jQuery控制DIV层实现由大到小,由远及近动画变化效果
2015/10/09 Javascript
AngularJS入门心得之directive和controller通信过程
2016/01/25 Javascript
Vue.js图片预览插件使用详解
2018/08/27 Javascript
基于Vue实现的多条件筛选功能的详解(类似京东和淘宝功能)
2019/05/07 Javascript
解决Vue 给mapState中定义的属性赋值报错的问题
2020/06/22 Javascript
[03:03]2014DOTA2国际邀请赛 EG战队专访
2014/07/12 DOTA
[01:32:50]DOTA2-DPC中国联赛 正赛 DLG vs XG BO3 第一场 1月25日
2021/03/11 DOTA
将Python中的数据存储到系统本地的简单方法
2015/04/11 Python
python 网络编程常用代码段
2016/08/28 Python
详解MySQL数据类型int(M)中M的含义
2016/11/20 Python
Python字典的核心底层原理讲解
2019/01/24 Python
在Qt5和PyQt5中设置支持高分辨率屏幕自适应的方法
2019/06/18 Python
快速解决pyqt5窗体关闭后子线程不同时退出的问题
2019/06/19 Python
HTML5使用Audio标签实现歌词同步的效果
2016/03/17 HTML / CSS
HTML5 Canvas基本线条绘制的实例教程
2016/03/17 HTML / CSS
H5混合开发app如何升级的方法
2018/01/10 HTML / CSS
canvas实现图片镜像翻转的2种方式
2020/07/22 HTML / CSS
凯伦·米莲女装网上商店:Karen Millen
2017/11/07 全球购物
Wilson体育用品官网:美国著名运动器材品牌
2019/05/12 全球购物
What is view? why do we have view?
2012/06/22 面试题
实习单位评语
2014/04/26 职场文书
本科毕业生应聘自荐信范文
2014/06/26 职场文书
2015年社区工会工作总结
2015/05/26 职场文书
2016年十一促销广告语
2016/01/28 职场文书
浅谈tf.train.Saver()与tf.train.import_meta_graph的要点
2021/05/26 Python