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 相关文章推荐
js 操作select相关方法函数
Dec 06 Javascript
由JavaScript中call()方法引发的对面向对象继承机制call的思考
Sep 12 Javascript
js 实现浏览历史记录示例
Apr 20 Javascript
javascript框架设计读书笔记之种子模块
Dec 02 Javascript
学习javascript面向对象 javascript实现继承的方式
Jan 04 Javascript
使用JavaScript实现弹出层效果的简单实例
May 31 Javascript
JS实现改变HTML上文字颜色和内容的方法
Dec 30 Javascript
10个最优秀的Node.js MVC框架
Aug 24 Javascript
js实现文件上传功能 后台使用MultipartFile
Sep 08 Javascript
详解webpack2异步加载套路
Sep 14 Javascript
基于layui内置模块(element常用元素的操作)
Sep 20 Javascript
vue实现element表格里表头信息提示功能(推荐)
Nov 20 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 字符串正则替换函数preg_replace使用说明
2011/07/15 PHP
PHP输出XML到页面的3种方法详解
2013/06/06 PHP
浅谈Laravel模板实体转义带来的坑
2019/10/22 PHP
将HTML自动转为JS代码
2006/06/26 Javascript
用js实现层随着内容大小动态渐变改变 推荐
2009/12/19 Javascript
js 页面刷新location.reload和location.replace的区别小结
2009/12/24 Javascript
11个用于提高排版水平的基于jquery的文字效果插件
2012/09/14 Javascript
Extjs中RowExpander控件的默认展开问题示例探讨
2014/01/24 Javascript
ExtJs纵坐标值重复问题的解决方法
2014/02/27 Javascript
node.js中的fs.fstatSync方法使用说明
2014/12/15 Javascript
jQuery中hasClass()方法用法实例
2015/01/06 Javascript
总结JavaScript设计模式编程中的享元模式使用
2016/05/21 Javascript
Avalonjs 实现简单购物车功能(实例代码)
2017/02/07 Javascript
Vue 父子组件数据传递的四种方式( inheritAttrs + $attrs + $listeners)
2018/05/04 Javascript
微信小程序 高德地图路线规划实现过程详解
2019/08/05 Javascript
node.js 如何监视文件变化
2020/09/01 Javascript
[05:05]第三天的dota2
2013/07/29 DOTA
[07:31]DOTA2卡尔工作室 英雄介绍主宰篇
2013/06/25 DOTA
python 随机数使用方法,推导以及字符串,双色球小程序实例
2017/09/12 Python
Python 3实战爬虫之爬取京东图书的图片详解
2017/10/09 Python
详谈套接字中SO_REUSEPORT和SO_REUSEADDR的区别
2018/04/28 Python
python如何使用Redis构建分布式锁
2020/01/16 Python
python 函数嵌套及多函数共同运行知识点讲解
2020/03/03 Python
Python+Opencv身份证号码区域提取及识别实现
2020/08/25 Python
详解基于python的图像Gabor变换及特征提取
2020/10/26 Python
CSS3教程(1):什么是CSS3
2009/04/02 HTML / CSS
html5 http的轮询和Websocket原理
2018/10/19 HTML / CSS
Swisse官方海外旗舰店:澳大利亚销量领先,自然健康品牌
2017/12/15 全球购物
如何拷贝一整个Java对象,包括它的状态
2013/12/27 面试题
教师绩效考核方案
2014/01/21 职场文书
2014年服务行业工作总结
2014/11/18 职场文书
营业用房租赁协议书
2014/11/26 职场文书
继承公证书格式
2015/01/26 职场文书
儿童诗两首教学反思
2016/02/23 职场文书
微信小程序scroll-view不能左右滑动问题的解决方法
2021/07/09 Javascript
详解nginx安装过程并代理下载服务器文件
2022/02/12 Servers