内容要点:

一.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属性的特性》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. sublime vue 语法高亮插件安装

    默认情况下,Vue.js 的单文件组件(*.vue)在 sublime 编辑器中是不被识别的.若要想高亮显示,需要安装插件 Vue Syntax Hightlight.安装步骤如下:   第一,在 s ...

  2. 关于Container With Most Water的求解

    Container With Most Water 哎,最近心情烦躁,想在leetcode找找感觉,就看到了这题. 然而,看了题目半天,硬是没看懂,于是乎就百度了下,怕看到解题方法,就略看了下摘要,以 ...

  3. 在GNU/Linux下使用Lilypond排版简谱

    尽管GNU/Linux并非无所不能,但确实能在很多时候提供免费.开放的解决方案.这两天我想做一个简谱,在网上搜索乐谱排版软件,发现了基于GPL协议的Lilypond软件.只不过Lilypond是用来做 ...

  4. BitMap - leetcode [位运算]

    136. Single Number 因为A XOR A = 0,且XOR运算是可交换的,于是,对于实例{2,1,4,5,2,4,1}就会有这样的结果: (2^1^4^5^2^4^1) => ( ...

  5. c# 读取ACCESS 数据库

    using System; using System.Collections.Generic; using System.Data.OleDb; using System.IO; using Syst ...

  6. COCOS2D-JS入门-web端项目部署

    下载cocos2d-js文件,建议上官网下载(外国官网或者中国官网都可以) 外国官网:http://cocos2d-x.org/download(选择最新版即可,我下载时为3.9版本,大概300多M) ...

  7. MQTT协议之 Apache Apollo服务

    一.说明 MQTT是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分.该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网) ...

  8. 【安装】python3.4版安装与2.x共存问题

    首先,到官网去下载python3.x版,这里推荐3.4以上的版本,自带pip库,以后不用自己另外下载 3.4.4版: https://www.python.org/downloads/release/ ...

  9. shrio登录验证

    shiro的认证过程也就是判断用户名和密码的过程,在认证过程中,用户需要提交实体信息(用户名)(Principals)和凭据信息(密码)(Credentials)来判断用户是否合法,最常见的" ...

  10. 问题: 在使用thinkphp自带分页类时,在设置尾页显示的最后一页时,用setConfig(“last”,”尾页”)来设置样式,发现无效。

    分析: 在分页类(/ThinkPHP/Library/Think/Page.class.PHP)里面有一个共有属性: public $lastSuffix = true; // 最后一页是否显示总页数 ...