Effective JavaScript Item 40 避免继承标准类型
本系列作为Effective JavaScript的读书笔记。
ECMAScript标准库不大。可是提供了一些重要的类型如Array,Function和Date。在一些场合下。你或许会考虑继承当中的某个类型来实现特定的功能。可是这样的做法并不被鼓舞。
比方为了操作一个文件夹。能够让文件夹类型继承Array类型例如以下:
function Dir(path, entries) {
this.path = path;
for (var i = 0, n = entries.length; i < n; i++) {
this[i] = entries[i];
}
}
Dir.prototype = Object.create(Array.prototype);
// extends Array
var dir = new Dir("/tmp/mysite", ["index.html", "script.js", "style.css"]);
dir.length; // 0
可是能够发现。dir.length的值是0,而不是期待中的3。
发生这样的现象的原因在于:仅仅有当对象是真正的Array类型时,length属性才会起作用。
在ECMAScript标准中。定义了一个不可见的内部属性被称为
[[class]]。该属性的值仅仅是一个字符串,所以不要被误导觉得JavaScript也实现了自己的类型系统。所以,对于Array类型,这个属性的值就是“Array”。对于Function类型。这个属性的值就是“Function”。下表是ECMAScript定义的全部[[class]]
值:
那么当对象的类型确实是Array时,length属性的特别之处就在于:length的值会和该对象中被索引的属性个数保持一致。比方对于一个数组对象arr。arr[0]和arr[1]就表示该对象有两个被索引的属性。那么length的值就是2。当加入了arr[2]的时候。length的值会被自己主动同步成3。
相同地,当设置length值为2时。arr[2]会被自己主动设置成undefined。
可是当继承Array类型并创建实例时,该实例的
[[class]] 属性并非Array。而是Object。因此length属性不能正确的工作。
在JavaScript中,也提供了用于查询
[[class]] 属性的方法,即使用Object.prototype.toString方法:
var dir = new Dir("/", []);
Object.prototype.toString.call(dir); // "[object Object]"
Object.prototype.toString.call([]); // "[object Array]"
因此,更好的实现方法是使用组合而不是继承:
function Dir(path, entries) {
this.path = path;
this.entries = entries; // array property
}
Dir.prototype.forEach = function(f, thisArg) {
if (typeof thisArg === "undefined") {
thisArg = this;
}
this.entries.forEach(f, thisArg);
};
以上代码将不再使用继承。而是将一部分功能代理给内部的entries属性来实现。该属性的值是一个Array类型对象。
ECMAScript标准库中,大部分的构造函数都会依赖内部属性值如 [[class]]
来实现正确的行为。对于继承这些标准类型的子类型。无法保证它们的行为是正确的。
因此。不要继承ECMAScript标准库中的类型如:
Array。
Boolean,
Date,
Function。
Number,RegExp,String
总结
- 继承标准类型可能会导致子类的行为不对,由于标准类型会依赖于内部属性诸如 [[class]]
- 优先使用组合的方式来实现功能。而不是使用继承。
Effective JavaScript Item 40 避免继承标准类型的更多相关文章
- Effective JavaScript Item 46 优先使用数组而不是Object类型来表示有顺序的集合
本系列作为Effective JavaScript的读书笔记. ECMAScript标准并没有规定对JavaScript的Object类型中的属性的存储顺序. 可是在使用for..in循环对Objec ...
- Effective JavaScript Item 39 绝不要重用父类型中的属性名
本系列作为Effective JavaScript的读书笔记. 假设须要向Item 38中的Actor对象加入一个ID信息: function Actor(scene, x, y) { this.sc ...
- Effective JavaScript Item 51 在类数组对象上重用数组方法
Array.prototype对象上的标准方法被设计为也能够在其他对象上重用 - 即使不是继承自Array的对象. 因此,在JavaScript中存折一些类数组对象(Array-like Object ...
- Effective JavaScript Item 30 理解prototype, getPrototypeOf和__proto__的不同
本系列作为Effective JavaScript的读书笔记. prototype,getPropertyOf和__proto__是三个用来訪问prototype的方法.它们的命名方式非常类似因此非常 ...
- Effective JavaScript Item 38 调用父类的构造函数在子类的构造函数
作为这一系列Effective JavaScript的读书笔记. 在一个游戏或者图形模拟的应用中.都会有场景(Scene)这一概念.在一个场景中会包括一个对象集合,这些对象被称为角色(Actor). ...
- Effective JavaScript Item 21 使用apply方法调用函数以传入可变參数列表
本系列作为Effective JavaScript的读书笔记. 以下是一个拥有可变參数列表的方法的典型样例: average(1, 2, 3); // 2 average(1); // 1 avera ...
- Effective JavaScript Item 31 优先使用Object.getPrototypeOf,而不是__proto__
本系列作为Effective JavaScript的读书笔记. 在ES5中引入了Object.getPrototypeOf作为获取对象原型对象的标准API.可是在非常多运行环境中.也提供了一个特殊的_ ...
- Effective JavaScript Item 49 对于数组遍历,优先使用for循环,而不是for..in循环
本系列作为Effective JavaScript的读书笔记. 对于以下这段代码,能看出最后的平均数是多少吗? var scores = [98, 74, 85, 77, 93, 100, 89]; ...
- Effective JavaScript Item 37 认识this的隐式指向
本系列作为Effective JavaScript的读书笔记. CSV数据通常都会被某种分隔符进行分隔.所以在实现CSV Reader时,须要支持不同的分隔符.那么,非常自然的一种实现就是将分隔符作为 ...
随机推荐
- axios使用方法
npm install axios 创建文件夹api/index.js import axios from 'axios'; let http = axios.create({ baseURL: '' ...
- 紫书 习题 11-12 UVa 1665 (并查集维护联通分量)
这道题要逆向思维 反过来从大到小枚举, 就是在矩阵中一点一点加进去数字,这样比较 好操作, 如果正着做就要一点一点删除数字, 不好做. 我们需要在这个过程中维护联通块的个数, 这里用到了并查集. 首先 ...
- 洛谷 P2183 巧克力
P2183 巧克力 题目描述 佳佳邀请了M个同学到家里玩.为了招待客人,她需要将巧克力分给她的好朋友们.她有N(1<=N<=5000)块巧克力,但是大小各不一样,第i块巧克力大小为为1*X ...
- [Javascript] Improve Composition with the Compose Combinator
To make our composition more readable and easier to name we are going to ceate a compose function we ...
- XCL-Chart柱形图的期望线/分界线
周日在柱形图上加了两个小功能,当中之中的一个是加上了期望线/分界线,功能非常小,但我个人非常喜欢这个功能(好像之前也没看到别的图表库原生支持这个. ) 主要是加上这些小小的横线后,能非常明显的区分出数 ...
- 移动端页面弹出对话框效果Demo
核心思路:设置一个隐藏的(display:none;).背景偏暗的div及其子div作为对话框.当点击某处时,将此div设置为显示. 核心代码例如以下(部分js代码用于动态调整div内容的行高.这部分 ...
- IIS预编译提升载入速度
当我们把站点部署在IIS7或IIS6S的时候,每当IIS或是ApplicationPool重新启动后,第一次请求站点反应总是非常慢.原因大家都知道(不知道能够參考这个动画说明ASP.NET网页第一个R ...
- H5学习_番外篇_PHP数据库操作
1. 文件操作 1.1 打开关闭文件 fopen() resource fopen ( string filename, string mode [, bool use_include_path [, ...
- 深入理解Android之Java虚拟机Dalvik
一.背景 这个选题非常大,但并非一開始就有这么高大上的追求. 最初之时,仅仅是源于对Xposed的好奇.Xposed差点儿是定制ROM的神器软件技术架构或者说方法了. 它究竟是怎么实现呢?我本意就是想 ...
- Vue小技巧,如何导入普通JS文件
最近在开发一个展示3D模型的WEB程序,在工程中使用了VUE和ThreeJS库.Three.js本身是支持CommonJS的,但我们还用到了OBJLoader模块,此模块不支持CommonJS,改成C ...