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 相关文章推荐
xml和web特殊字符
Apr 28 Javascript
jquery prop的使用介绍及与attr的区别
Dec 19 Javascript
如何在指定的地方插入html内容和文本内容
Dec 23 Javascript
采用call方式实现js继承
May 20 Javascript
jQuery制作可自定义大小的拼图游戏
Mar 30 Javascript
使用jsonp实现跨域获取数据实例讲解
Dec 25 Javascript
Bootstrap学习笔记之进度条、媒体对象实例详解
Mar 09 Javascript
微信小程序搜索组件wxSearch实例详解
Jun 08 Javascript
AngularJS使用ui-route实现多层嵌套路由的示例
Jan 10 Javascript
Vuex实现计数器以及列表展示效果
Mar 10 Javascript
详解在Vue中使用TypeScript的一些思考(实践)
Jul 06 Javascript
vue实现省市区联动 element-china-area-data插件
Apr 22 Vue.js
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
全国FM电台频率大全 - 6 辽宁省
2020/03/11 无线电
PHP中cookies使用指南
2007/03/16 PHP
php源码分析之DZX1.5加密解密函数authcode用法
2015/06/17 PHP
PHP 返回13位时间戳的实现代码
2016/05/13 PHP
js控制frameSet示例
2013/09/10 Javascript
jQuery 属性选择器element[herf*='value']使用示例
2013/10/20 Javascript
提交按钮的name='submit'引起的js失效问题及原因
2015/02/25 Javascript
深入解析JavaScript中的数字对象与字符串对象
2015/10/21 Javascript
如何解决easyui自定义标签 datagrid edit combobox 手动输入保存不上
2015/12/26 Javascript
js实现图片无缝滚动特效
2020/03/19 Javascript
json定义及jquery操作json的方法
2016/10/03 Javascript
js前端解决跨域问题的8种方案(最新最全)
2016/11/18 Javascript
详解vue-cli + webpack 多页面实例配置优化方法
2017/07/13 Javascript
使用nvm管理不同版本的node与npm的方法
2017/10/31 Javascript
轻量级JS Cookie插件js-cookie的使用方法
2018/03/22 Javascript
element-ui upload组件多文件上传的示例代码
2018/10/17 Javascript
Vue表单输入绑定的示例代码
2018/11/01 Javascript
解决微信小程序调用moveToLocation失效问题【超简单】
2019/04/12 Javascript
[00:18]天涯墨客三技能展示
2018/08/25 DOTA
讲解Python的Scrapy爬虫框架使用代理进行采集的方法
2016/02/18 Python
TensorFlow实现AutoEncoder自编码器
2018/03/09 Python
一篇文章搞懂Python的类与对象名称空间
2018/12/10 Python
Python中psutil的介绍与用法
2019/05/02 Python
如何在django中运行scrapy框架
2020/04/22 Python
使用Python FastAPI构建Web服务的实现
2020/06/08 Python
利用keras使用神经网络预测销量操作
2020/07/07 Python
Python3交互式shell ipython3安装及使用详解
2020/07/11 Python
HTML5是什么 HTML5是什么意思 HTML5简介
2012/10/26 HTML / CSS
精致的手工皮鞋:Shoe Embassy
2019/11/08 全球购物
十岁生日家长答谢词
2014/01/17 职场文书
环保倡议书100字
2014/05/15 职场文书
幼儿园保育员责任书
2014/07/22 职场文书
再读《皇帝的新衣》的读后感悟!
2019/08/07 职场文书
口袋妖怪冰系十大最强精灵,几何雪花排第七,第六类似北极熊
2022/03/18 日漫
MySQL磁盘碎片整理实例演示
2022/04/03 MySQL
Java 使用类型为Object的变量指向任意类型的对象
2022/04/13 Java/Android