DS.Lab筆記
来源:互联网 发布:数据分析的对比分析法 编辑:程序博客网 时间:2024/05/21 00:46
属性的种类
作者在一句话里总结说有三种。但是在这句话后面的一个段落里只罗列了两个:一个是命名属性,在JS代码中可以访问,还有一种是内部属性,JS代码中不能访问到。第三种是他在第一段落中提到的,在ES3中的传统的属性,在这个版本的标准里,属性的值与其命名是直接关联的,其内部的实现并没有被详细解释,虽然有些实现在属性值背后添加了访问器的概念,setter和getter方法。但是在ES5里这种情况被明确描述了,命名属性明确地有访问器,作者称之为named accessor property。。
属性的特性(attribute)
[[Value]]
[[Writable]]对应ES3里的{ReadOnly}。
[[Enumerable]]对应ES3里的{DontEnum}。
[[Configurable]]对应ES3里的{DontDelete}。
命名数据属性
这类属性有四个特性,它们的默认值是:
var defaultDataPropertyAttributes = { [[Value]]: undefined, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false};
所以,也就是说你创建一个新属性的时候,你要是不提供这几个特性的值,那么这个属性就成了一个不可以修改,不能够枚举不能够再修改特性值的属性了,那也就等于一个常量:
// define a global constant Object.defineProperty(this, "MAX_SIZE", { value: 100});console.log(MAX_SIZE); // 100 MAX_SIZE = 200; // error in strict mode, [[Writable]] = false,delete MAX_SIZE; // error in strict mode, [[Configurable]] = false console.log(MAX_SIZE); // still 100
在《Effective JavaScript》里,有几个知识点都是跟可枚举特性有关的,问题在于在原型链上任何一个代理点新创建的属性都会被for...in循环遍历。所以在ES5里,这个问题可以通过enumerable解决:
Object.defineProperty(Array.prototype, "sum", { value: function arraySum() { // sum implementation }, enumerable: false }); // now with using the same example this "sum"// is no longer enumerable for (var k in a) { console.log(k); // 0, 1, 2}
这样一来,在ES3里面的一个单纯的赋值操作
// simple assignment (if we create a new property)foo.bar = 10;
在ES5里就成了
// the same asObject.defineProperty(foo, "bar", { value: 10, writable: true, enumerable: true, configurable: true});
注意:
- defineProperty()不仅用来创建属性,也负责修改;
- defineProperty()返回被修改的对象本身;
- Object.keys()返回一个对象上的所有可枚举属性;
- Object.getOwnPropertyNames()返回一个对象上的所有属性,包括可枚举和不可枚举的。
命名访问器属性
学术化的定义是:命名访问器属性将两个访问器与一个属性名关联起来,分别是设定器和取值器,两者用来间接地修改和读取该属性的值。
其实感觉很接近C#里的property。
这类属性多了两个特性:[[Get]]和[[Set]]。
以前ES3系列的文章里有讲到过,ES3里每个对象都有些内部属性,其中[[Get]]和[[Put]]是负责读写属性值的。在ES5里,它们不是一回事,而实际上却又有紧密的关系,对象上的内部属性[[Get]]会呼叫访问器属性的[[Get]]特性,[[Put]]会呼叫[[Set]]。
10和20这段讲的意思在下面的示例代码里能更清楚地显现出来,如果在getter做一些手脚,那么将读不到这个属性自己的值。
这类属性的特性的默认值是:
var defaultAccessorPropertyAttributes = { [[Get]]: undefined, [[Set]]: undefined, [[Enumerable]]: false, [[Configurable]]: false};
如果没有定义set,属性就成为只读。
用defineProperty()来定义属性的语法是:
var foo = {}; Object.defineProperty(foo, "bar", { get: function getBar() { return 20; }, set: function setBar(value) { // setting implementation } }); foo.bar = 10; // calls foo.bar.[[Set]](10) // independently always 20console.log(foo.bar); // calls foo.bar.[[Get]]()
或者用声明式也可以:
var foo = { get bar () { return 20; }, set bar (value) { console.log(value); } }; foo.bar = 100;console.log(foo.bar); // 20
第一个坑:修改一个[[Configurable]]为false的对象
好,下面作者指出一个貌似是bug的东西,倒不能算bug,但或许是个坑。在前面讲过,一旦一个属性的[[Configurable]]是false,以后就不能再修改它的任何特性了,只能修改它的值而已,所以再次给getter赋值会导致一个异常,这个很合情合理:
// configurable false by defaultvar foo = Object.defineProperty({}, "bar", { get: function () { return "bar"; }}); // trying to reconfigure the "bar"// property => exception is throwntry { Object.defineProperty(foo, "bar", { get: function () { return "baz" } });} catch (e) { if (e instanceof TypeError) { console.log(foo.bar); // still "bar" }}
但是,如果修改时的新值与当前值相同,这个异常不会被抛出。
function getBar() { return "bar";} var foo = Object.defineProperty({}, "bar", { get: getBar}); // no exception even if configurable is false,// but practically such "re"-configuration is uselessObject.defineProperty(foo, "bar", { get: getBar});
第二个坑:[[Configurable]]为false的前提下,[[Writable]]可以由true到false,但不可由false到true
看下下面的代码就明白了:
var foo = Object.defineProperty({}, "bar", { value: "bar", writable: true, configurable: false}); Object.defineProperty(foo, "bar", { value: "baz"}); console.log(foo.bar); // "baz" // change writableObject.defineProperty(foo, "bar", { value: "qux", writable: false // changed from true to false, OK}); console.log(foo.bar); // "qux" // try to change writable again - back to trueObject.defineProperty(foo, "bar", { value: "qux", writable: true // ERROR});
第三个坑:[[Configurable]]为true的前提下,数据属性和访问器属性之间可以相互转换
如果[[Configurable]]为false当然就不可能了,作者得出结论说可见[[Writable]]有多么不重要。
// writable false by defaultvar foo = Object.defineProperty({}, "bar", { value: "bar", configurable: true}); Object.defineProperty(foo, "bar", { get: function () { return "baz"; }}); console.log(foo.bar); // OK, "baz"
第四个坑:
- DS.Lab筆記
- DS.Lab筆記
- DS.Lab筆記
- DS.Lab筆記
- DS.Lab筆記
- DS.Lab筆記
- DS.Lab筆記
- DS.Lab筆記
- DS.Lab筆記
- Set(DS)(15C++ for lab)
- Lab
- LAB
- ds
- ds
- ds
- ds
- ds
- DS
- freemarker的使用心得
- iText7报错com.itextpdf.kernel.font.PdfType0Font.getCidFontType2(PdfType0Font.java:720)解决
- 一个非常简单的spring-boot web项目(一)
- 二叉树的递归遍历与非递归遍历
- 在Mac上直接使用Python2.7版本
- DS.Lab筆記
- spice性能优化
- copy文章方法
- SJA1000控制器详解
- hack this site-level 1 the idiot test
- 很全面的freemarker教程
- 整数排序
- 常用linux命令scp,grep,free
- 【Spring学习笔记】基于profile的高级装配