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时,须要支持不同的分隔符.那么,非常自然的一种实现就是将分隔符作为 ...
随机推荐
- .NET Framework 3.5 无法安装以下功能 安装错误:0x800F0906(客户端加域后出现)
问题:安装错误:0x800F0906 系统安装并加域后,在安装用友软件时提示没有.net 3.5 系统为win10 但是,点击确定后,却出现了这样的错误.如下: 点击下载并安装此功能,出现了这样 ...
- 【BZOJ 1083】 [SCOI2005]繁忙的都市
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 很明显的最小生成树了. 输出最后选的那条边就好了. [代码] #include <bits/stdc++.h> usin ...
- @SpringBootApplication cannot be resolved to a type In STS
@SpringBootApplication cannot be resolved to a type In STS 学习了:https://stackoverflow.com/questions/4 ...
- "duplicate symbol for architecture i386" 解决的方法
我在写项目的过程中,碰到了这个错误,我在网上查了一下,发现这个错误的原因是,project里面有反复的类. 解决方式:找到反复的类,然后删除掉就好了. 分析一下, 如图. 能够看出, 错误类型是 du ...
- hdu4405--Aeroplane chess(概率dp第七弹:飞行棋游戏--2012年网络赛)
Aeroplane chess Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 【Oracle】Exadata虚拟机配置(一)
Exadata是Oracle软硬结合的一体机.通过自己的机子不可能全然模拟出来,这里搭建的虚拟机仅仅是一个简单的.能够供我们学习Exadata的环境. 最简单能够模拟的Exadata虚拟机须要两个节点 ...
- Linux/UNIX线程(1)
线程(1) 本文将介绍怎样使用多个控制线程在单个进程环境中运行多个任务. 一个进程中的全部线程都能够訪问该进程的组成部件(如文件描写叙述符和内存). 线程包含了表示进程内运行环境必须的信息,当中包含进 ...
- 配置ssh免密码登录的原理
- HBase框架基础(四)
* HBase框架基础(四) 上一节我们介绍了如何使用HBase搞一些MapReduce小程序,其主要作用呢是可以做一些数据清洗和分析或者导入数据的工作,这一节我们来介绍如何使用HBase与其他框架进 ...
- Oozie框架基础
* Oozie框架基础 官方文档地址:http://oozie.apache.org/docs/4.0.0/DG_QuickStart.html 除Oozie之外,类似的框架还有: ** Zeus:h ...