《JS权威指南学习总结--6.7属性的特性》
内容要点:
一.ES5中查询和设置属性的API
1.可以通过这些API给原型对象添加方法,并将它们设置成不可枚举的,这让它们看起来更像内置方法。
2.可以通过这些API给对象定义不能修改或删除的属性,借此 "锁定" 这个对象。
3.数据属性的4个特性: 值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable)。
4.存取器属性不具有值特性和可写性,它们的可写性是由setter方法存在与否决定的。因此存取器属性的4个特性是:读取(get)、写入(set)、可枚举性(numberable)和可配置性(configurable)。
其中writable、enumerable和configurable都是布尔值,当然,get属性和set属性是函数值。
二.Object.getOwnPropertyDescriptor()
1.通过调用Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述符:
例如:
//返回{ value : 1,writable : true,enumerable:true,configurable:true }
Object.getOwnPropertyDescriptor({x:1},"x");
//查询上文中定义的random对象的octet属性
//返回{get:/*func*/,set:undefined,enumerable:true,configurable:true}
Object.getOwmPropertyDescriptor(random,"octet");
//对于继承属性和不存在的属性,返回undefined
Object.getOwnPropertyDescriptor({},"x"); //undefined,没有这个属性
Object.getOwnPropertyDescriptor({},"toString"); //undefined,继承属性
Object.getOwnPropertyDescriptor()只能得到自有属性的描述符。要想获得继承属性的特性,需要遍历原型链
三.Object.definePeoperty()
传入要修改的对象,要创建或修改的属性的名称以及属性描述符对象。
var o = {}; //创建一个空对象
//添加一个不可枚举的数据属性x,并赋值为1
Object.defineProperty(o,"x",{value:1,writable:true,enumerable:false,configurable:true});
//属性是存在的,但不可枚举
o.x; //=>1
Object.keys(o) //=>[]
//现在对属性x做修改,让它变为只读
Object.defineProperty(o,"x",{writable:false});
//试图更改这个属性的值
o.x = 2; //操作失败但不报错,而在严格模式中抛出类型错误异常
o.x=1;
//属性依然是可配置的,因此可以通过这种方式对它进行修改
Object.defineProperty(o,"x",{value:2});
o.x //=>2
//现在将x从数据属性修改为存取器属性
Object.defineProperty(o,"x",{get:function(){return 0;}});
o.x //=>0
传入Object.defineProperty()的属性描述符对象不必包含所有4个特性。对于新创建的属性来说,默认的特性值是false或undefined。对于修改的已有属性来说,默认的特性值没有做任何修改。注意:这个方法要么修改已有属性要么新建自有属性,但不能修改继承属性。
四.Object.defineProperties()
同时修改或创建多个属性。第一个参数是要修改的对象,第二个参数是一个映射表,它包含要新建或修改的属性的名称,以及它们的属性描述符
例如:
var p = Object.defineProperties({},{
x:{value:1,writable:true,enumerable:true,configurable:true},
y:{value:1,writable:true,enumerable:true,configurable:true},
r:{
get:function(){ return Math.sqrt(this.x*this.x+this.y*this.y) },
enumerable:true,
configurable:true
}
});
这段代码从一个空对象开始,然后给它添加了两个数据属性和一个只读存储器属性,最终Object.defineProperties()返回修改后的对象
五.
对于那些不允许创建或修改的属性来说,如果用Object.defineProperty()和Object.defineProperties()返回修改后的对象(新建或修改)就会抛出类型错误异常,
比如,给一个不可扩展的对象新增属性就会抛出类型错误异常。造成这些方法抛出类型错误异常的其他原因则和特性本身相关。
可写性控制着特性的修改,可配置性控制着对其他特性的(包括属性是否可以删除)的修改。然而规则远不止这么简单:
例如,如果属性是可配置的话,则可以修改不可写属性的值。同样,如果属性是不可配置的,仍然可以将可写属性修改为不可写属性。
下面是完整的规则,任何对Object.defineProperty()或Object.defineProperties()违反规则的使用都会抛出类型错误异常
1.如果对象是不可扩展的,则可以编辑已有的自有属性,但不能给它添加新属性
2.如果属性是不可配置的,则不能修改它的可配置性和可枚举性。
3.如果存取器属性是不可配置的,则不能修改其getter和setter方法,也不能将它转换为数据属性
4.如果数据属性是不可配置的,则不能将它转换为存取器属性
5.如果数据属性是不可配置的,则不能将它的可写性从false修改为true,但可以从true修改为false。
6.如果数据属性是不可配置的且不可写的,则不能修改它的值。然而可配置但不可写属性的值是可以修改的(实际上是先将它标记为可写的,然后修改它的值,最后转换为不可写的)
六.
上节中实现了extend()函数,这个函数把一个对象的属性复制到另一个对象中。这个函数只是简单地复制属性名和值,没有复制属性的特性,而且也没有复制存取器属性的getter和setter方法,只是将它们简单地转换为静态的数据属性。
下例给出了改进的extend(),它使用Object.getOwnPropertyDescriptor()和Object.defineProperty()对属性的所有特性进行复制。新的extend()作为不可枚举属性添加到Object.prototype中,因此它是Object上定义的新方法,而不是独立的函数。
/*给Object.prototype添加一个不可枚举的extend()方法
*这个方法继承自调用它的对象,将作为参数传入的对象的属性一一复制
*除了值之外,也复制属性的所有特性,除非在目标对象中存在同名的属性
*参数对象的所有自有对象(包括不可枚举的属性)也会一一复制
*/
Object.defineProperty(Object.prototype,
"extend",
{
writable: true,
enumerable:false, //将其定义为不可枚举的
configurable:true,
value:function(o){ //值就是这个函数
//得到所有的自有属性,包括不可枚举属性
var names = Object.getOwnPropertyNames(o);
//遍历它们
for(var i = 0; i <names.length; i++){
//如果属性已经存在,则跳过
if(names[i] in this) continue;
//获得o中的属性的描述符
var desc = Object.getOwnPropertyDescriptor(o,names[i]);
//用它给this创建一个属性
Object.defineProperty(this,names[i],desc);
}
}
});
《JS权威指南学习总结--6.7属性的特性》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- sublime vue 语法高亮插件安装
默认情况下,Vue.js 的单文件组件(*.vue)在 sublime 编辑器中是不被识别的.若要想高亮显示,需要安装插件 Vue Syntax Hightlight.安装步骤如下: 第一,在 s ...
- 关于Container With Most Water的求解
Container With Most Water 哎,最近心情烦躁,想在leetcode找找感觉,就看到了这题. 然而,看了题目半天,硬是没看懂,于是乎就百度了下,怕看到解题方法,就略看了下摘要,以 ...
- 在GNU/Linux下使用Lilypond排版简谱
尽管GNU/Linux并非无所不能,但确实能在很多时候提供免费.开放的解决方案.这两天我想做一个简谱,在网上搜索乐谱排版软件,发现了基于GPL协议的Lilypond软件.只不过Lilypond是用来做 ...
- BitMap - leetcode [位运算]
136. Single Number 因为A XOR A = 0,且XOR运算是可交换的,于是,对于实例{2,1,4,5,2,4,1}就会有这样的结果: (2^1^4^5^2^4^1) => ( ...
- c# 读取ACCESS 数据库
using System; using System.Collections.Generic; using System.Data.OleDb; using System.IO; using Syst ...
- COCOS2D-JS入门-web端项目部署
下载cocos2d-js文件,建议上官网下载(外国官网或者中国官网都可以) 外国官网:http://cocos2d-x.org/download(选择最新版即可,我下载时为3.9版本,大概300多M) ...
- MQTT协议之 Apache Apollo服务
一.说明 MQTT是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分.该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网) ...
- 【安装】python3.4版安装与2.x共存问题
首先,到官网去下载python3.x版,这里推荐3.4以上的版本,自带pip库,以后不用自己另外下载 3.4.4版: https://www.python.org/downloads/release/ ...
- shrio登录验证
shiro的认证过程也就是判断用户名和密码的过程,在认证过程中,用户需要提交实体信息(用户名)(Principals)和凭据信息(密码)(Credentials)来判断用户是否合法,最常见的" ...
- 问题: 在使用thinkphp自带分页类时,在设置尾页显示的最后一页时,用setConfig(“last”,”尾页”)来设置样式,发现无效。
分析: 在分页类(/ThinkPHP/Library/Think/Page.class.PHP)里面有一个共有属性: public $lastSuffix = true; // 最后一页是否显示总页数 ...