JavaScript秘密花园 - Array, Array Constructor, for in loop, typeof, instanceOf

JavaScript 秘密花园.pdf 立即下载

数组遍历与属性

虽然在 JavaScript 中数组是是对象,但是没有好的理由去使用 `for in` 循环 遍历数组。 相反,有一些好的理由不去使用 for in 遍历数组。

注意: JavaScript 中数组不是 关联数组。 JavaScript 中只有对象 来管理键值的对应关系。但是关联数组是保持顺序的,而对象不是。

由于 for in 循环会枚举原型链上的所有属性,唯一过滤这些属性的方式是使用 `hasOwnProperty` 函数, 因此会比普通的 for 循环慢上好多倍。

遍历(Iteration)

为了达到遍历数组的最佳性能,推荐使用经典的 for 循环。

var list = [1, 2, 3, 4, 5, ...... 100000000];
for(var i = 0, l = list.length; i < l; i++) {
    console
.log(list[i]);
}

上面代码有一个处理,就是通过 l = list.length 来缓存数组的长度。

虽然 length 是数组的一个属性,但是在每次循环中访问它还是有性能开销。 可能最新的 JavaScript 引擎在这点上做了优化,但是我们没法保证自己的代码是否运行在这些最近的引擎之上。

实际上,不使用缓存数组长度的方式比缓存版本要慢很多。

`length` 属性(The `length` property)

length 属性的 getter 方式会简单的返回数组的长度,而 setter 方式会截断数组。

var foo = [1, 2, 3, 4, 5, 6];
foo
.length = 3;
foo
; // [1, 2, 3]

foo
.length = 6;
foo
; // [1, 2, 3]

译者注: 在 Firebug 中查看此时 foo 的值是: [1, 2, 3, undefined, undefined, undefined] 但是这个结果并不准确,如果你在 Chrome 的控制台查看 foo 的结果,你会发现是这样的: [1, 2, 3] 因为在 JavaScript 中 undefined 是一个变量,注意是变量不是关键字,因此上面两个结果的意义是完全不相同的。

// 译者注:为了验证,我们来执行下面代码,看序号 5 是否存在于 foo 中。
5 in foo; // 不管在 Firebug 或者 Chrome 都返回 false
foo
[5] = undefined;
5 in foo; // 不管在 Firebug 或者 Chrome 都返回 true

为 length 设置一个更小的值会截断数组,但是增大 length 属性值不会对数组产生影响。

结论(In conclusion)

为了更好的性能,推荐使用普通的 for 循环并缓存数组的 length 属性。 使用 for in 遍历数组被认为是不好的代码习惯并倾向于产生错误和导致性能问题。

Array 构造函数

由于 Array 的构造函数在如何处理参数时有点模棱两可,因此总是推荐使用数组的字面语法 - [] - 来创建数组。

[1, 2, 3]; // 结果: [1, 2, 3]
new Array(1, 2, 3); // 结果: [1, 2, 3]

[3]; // 结果: [3]
new Array(3); // 结果: []
new Array('3') // 结果: ['3']

译者注:这里的模棱两可指的是数组的两种构造函数语法 var arr1 = new Array(arrayLength); var arr2 = new Array(element0, element1, ..., elementN);

// 译者注:因此下面的代码将会使人很迷惑
new Array(3, 4, 5); // 结果: [3, 4, 5]
new Array(3) // 结果: [],此数组长度为 3

由于只有一个参数传递到构造函数中(译者注:指的是 new Array(3); 这种调用方式),并且这个参数是数字,构造函数会返回一个 length 属性被设置为此参数的空数组。 需要特别注意的是,此时只有 length 属性被设置,真正的数组并没有生成。 译者注:在 Firebug 中,你会看到 [undefined, undefined, undefined],这其实是不对的。在上一节有详细的分析。

var arr = new Array(3);
arr
[1]; // undefined
1 in arr; // false, 数组还没有生成

这种优先于设置数组长度属性的做法只在少数几种情况下有用,比如需要循环字符串,可以避免 for 循环的麻烦。

new Array(count + 1).join(stringToRepeat);
// 译者注:new Array(3).join('#') 将会返回 "##"

结论(In conclusion)

应该尽量避免使用数组构造函数创建新数组。推荐使用数组的字面语法。它们更加短小和简洁,因此增加了代码的可读性。

for in 循环

和 in 操作符一样,for in 循环同样在查找对象属性时遍历原型链上的所有属性。

注意: for in 循环不会遍历那些 enumerable 设置为 false 的属性;比如数组的 length 属性。

// 修改 Object.prototype
Object.prototype.bar = 1;

var foo = {moo: 2};
for(var i in foo) {
    console
.log(i); // 输出两个属性:bar 和 moo
}

由于不可能改变 for in 自身的行为,因此有必要过滤出那些不希望出现在循环体中的属性, 这可以通过 Object.prototype 原型上的 `hasOwnProperty` 函数来完成。

注意: 由于 for in 总是要遍历整个原型链,因此如果一个对象的继承层次太深的话会影响性能。

使用 `hasOwnProperty` 过滤(Using `hasOwnProperty` for filtering)

// foo 变量是上例中的
for(var i in foo) {
   
if (foo.hasOwnProperty(i)) {
        console
.log(i);
   
}
}

这个版本的代码是唯一正确的写法。由于我们使用了 hasOwnProperty,所以这次只输出 moo。 如果不使用 hasOwnProperty,则这段代码在原生对象原型(比如 Object.prototype)被扩展时可能会出错。

一个广泛使用的类库 Prototype 就扩展了原生的 JavaScript 对象。 因此,但这个类库被包含在页面中时,不使用 hasOwnProperty 过滤的 for in 循环难免会出问题。

最佳实践(Best practices)

推荐总是使用 hasOwnProperty。不要对代码运行的环境做任何假设,不要假设原生对象是否已经被扩展了。

typeof 操作符

typeof 操作符(和 `instanceof` 一起)或许是 JavaScript 中最大的设计缺陷, 因为几乎不可能从它们那里得到想要的结果。

尽管 instanceof 还有一些极少数的应用场景,typeof 只有一个实际的应用(译者注:这个实际应用是用来检测一个对象是否已经定义或者是否已经赋值), 而这个应用却不是用来检查对象的类型。

注意: 由于 typeof 也可以像函数的语法被调用,比如 typeof(obj),但这并是一个函数调用。 那两个小括号只是用来计算一个表达式的值,这个返回值会作为typeof 操作符的一个操作数。 实际上不存在名为 typeof 的函数。

JavaScript 类型表格(The JavaScript type table)

Value               Class      Type
-------------------------------------
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
new Date()          Date       object
new Error()         Error      object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object (function in Nitro/V8)
new RegExp("meow")  RegExp     object (function in Nitro/V8)
{}                  Object     object
new Object()        Object     object

上面表格中,Type 一列表示 typeof 操作符的运算结果。可以看到,这个值在大多数情况下都返回 "object"。

Class 一列表示对象的内部属性 [[Class]] 的值。

JavaScript 标准文档中定义: [[Class]] 的值只可能是下面字符串中的一个: Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number,Object, RegExp, String.

为了获取对象的 [[Class]],我们需要使用定义在 Object.prototype 上的方法 toString。

对象的类定义(The Class of an object)

JavaScript 标准文档只给出了一种获取 [[Class]] 值的方法,那就是使用 Object.prototype.toString。

function is(type, obj) {
   
var clas = Object.prototype.toString.call(obj).slice(8, -1);
   
return obj !== undefined && obj !== null && clas === type;
}

is('String', 'test'); // true
is('String', new String('test')); // true

上面例子中,Object.prototype.toString 方法被调用,this 被设置为了需要获取 [[Class]] 值的对象。

译者注:Object.prototype.toString 返回一种标准格式字符串,所以上例可以通过 slice 截取指定位置的字符串,如下所示:

Object.prototype.toString.call([])      // "[object Array]"
Object.prototype.toString.call({})      // "[object Object]"
Object.prototype.toString.call(2)       // "[object Number]"

ES5 提示: 在 ECMAScript 5 中,为了方便,对 null 和 undefined 调用 Object.prototype.toString 方法, 其返回值由 Object 变成了 Null 和 Undefined。

译者注:这种变化可以从 IE8 和 Firefox 4 中看出区别,如下所示:

// IE8
Object.prototype.toString.call(null)    // "[object Object]"
Object.prototype.toString.call(undefined)       // "[object Object]"

// Firefox 4
Object.prototype.toString.call(null)    // "[object Null]"
Object.prototype.toString.call(undefined)       // "[object Undefined]"

测试为定义变量(Testing for undefined variables)

typeof foo !== 'undefined'

上面代码会检测 foo 是否已经定义;如果没有定义而直接使用会导致 ReferenceError 的异常。 这是 typeof 唯一有用的地方。

结论(In conclusion)

为了检测一个对象的类型,强烈推荐使用 Object.prototype.toString 方法; 因为这是唯一一个可依赖的方式。正如上面表格所示,typeof 的一些返回值在标准文档中并未定义, 因此不同的引擎实现可能不同。

除非为了检测一个变量是否已经定义,我们应尽量避免使用 typeof 操作符。

instanceof 操作符

instanceof 操作符用来比较两个操作数的构造函数。只有在比较自定义的对象时才有意义。 如果用来比较内置类型,将会和 typeof 操作符 一样用处不大。

比较自定义对象(Comparing custom objects)

function Foo() {}
function Bar() {}
Bar.prototype = new Foo();

new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true

// 如果仅仅设置 Bar.prototype 为函数 Foo 本省,而不是 Foo 构造函数的一个实例
Bar.prototype = Foo;
new Bar() instanceof Foo; // false

`instanceof` 比较内置类型(Using `instanceof` with native types)

new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true

'foo' instanceof String; // false
'foo' instanceof Object; // false

有一点需要注意,instanceof 用来比较属于不同 JavaScript 上下文的对象(比如,浏览器中不同的文档结构)时将会出错, 因为它们的构造函数不会是同一个对象。

结论(In conclusion)

instanceof 操作符应该仅仅用来比较来自同一个 JavaScript 上下文的自定义对象。 正如 `typeof` 操作符一样,任何其它的用法都应该是避免的。

JavaScript 秘密花园 JavaScript 秘密花园是一个不断更新,主要关心 JavaScript 一些古怪用法的文档。 对于如何避免常见的错误,难以发现的问题,以及性能问题和不好的实践给出建议, 初学者可以籍此深入了解 JavaScript 的语言特性,0分下载 立即下载

相关推荐

Python | 集合(set)运算之intersection()

简介 在做力扣题的时候,有一个思路是要求解两个字符串的交集。 一般来说,求解交集的思路是遍历两个字符串,判断有无相等,有相等则添加到交集中,直到循环结束。 但是这样做,会增加很多的不必要的遍历:比如说,当一个字符串中有多个相同的元素时,该元素会被遍历多次。 因此,在求解时,我们可以先将字符串转换为set集合类型。集合中存储的元素没有顺序,且互异(即元素不可重复)。 算例 求字符串m“abcdaaa” 与 字符串n“bcddses”是否存在交集 首先将字符串转换为set类型: m = set(m) n

lovetaozibaby的博客 1万+

JavaScript - Array, Array Constructor, for in loop, typeof, instanceOf

JavaScript Garden - 原文 数组遍历与属性 虽然在 JavaScript 中数组是是对象,但是没有好的理由去使用`for in` 循环遍历数组。 相反,有一些好的理由不去使用for in遍历数组。 注意:JavaScript 中数组不是关联数组。 JavaScript 中只有对象来管理键值的对应关系。但是关联数组是保持顺序的,而对象不是。...

iteye_6378的博客 181

Python虚拟环境实战:如何在不同conda环境中共享CUDA的libcupti.so.12文件

本文深入探讨了在Python虚拟环境中解决`ImportError: libcupti.so.12`报错的工程化方案。通过分析动态链接库的搜索机制,提供了环境变量法、软链接法和系统级配置法三种解决方案,帮助开发者在不同conda环境中高效共享CUDA动态链接库,确保深度学习项目的顺利运行。

weixin_29094775的博客 240

《JavaScript 秘密花园》—一些奇奇怪怪的知识

读《JavaScript 秘密花园》,根据自己知识缺漏摘抄部分内容,以及实际代码执行结果

qq_40029828的博客 1327

H3C无线控制器AC与第三方认证系统集成实现企业级Portal短信认证方案

本文详细阐述了如何将H3C无线控制器(AC)与第三方认证系统集成,构建企业级Portal短信认证方案。该方案通过手机号作为临时凭证,实现了访客网络的实名追溯、权限控制与专业体验。文章深入解析了方案原理、H3C AC的关键配置步骤、第三方系统对接要点及短信网关选型避坑指南,为企业提升网络安全管理与访客服务质量提供了完整、可行的实战指导。

a3b4c5的博客 195

AI绘画与医疗可视化:用AI生成医学插图的实践

医疗可视化是医学教育、临床沟通和学术研究的核心工具。传统医学插图依赖手工绘制或专业3D建模,存在制作周期长、成本高、更新迭代慢等问题。随着深度学习技术的发展,AI绘画工具(如Stable Diffusion、DALL-E)展现出强大的图像生成能力,但医疗领域对插图的解剖准确性、标注规范性和语义完整性有极高要求,通用AI模型难以直接应用。本文聚焦AI技术与医疗领域的交叉创新,系统阐述如何通过数据预处理、模型定制化训练和后处理校验,构建符合医疗标准的插图生成系统。

大模型应用工坊 1788

IntelliJ IDEA 代码检查规范QAPlug

静态检查规范 Avoid Array Loops 数组之间的拷贝使用System.arrayCopy更加高效 byte[] ReceiveBytes = new byte[length1+ length2]; for (int i = 0; i     ReceiveBytes[i] =ReceiveBytes_temp1[i]; } Big Integer Ins

我的成长之路 4万+

【人工智能】Spring AI项目在定义 `response_format` 的 Invalid schema for response_format ‘custom_schema‘

确保。

奶爸的编程之路,也就一周冷个三天 562

javascript秘密花园

大家请参考http://www.jb51.net/onlineread/JavaScript-Garden-CN/,真的很好

wudiazu的博客 1097

模组 RG500Q入网问题分析

- [ ] 不同于公网,在5G专网环境中, 通常使用很多非标准的网络配置,如PLMN/APN等。因此,5G模组在专网环境下通常要做一些专门的配置才能正常入网,本文分析一例在专网环境, 5G终端无法入网问题的定位过程。 - [ ] 具体涉及到以下模组操作: 恢复出厂、SA only、锁BAND、配置MBN等

十年通信老兵的技术修炼之路——从3G到5G,从地面基站到卫星通信。 935

[Dify] -进阶13- 使用“知识库 + 工作流”打造智能推荐系统

本文介绍了在Dify平台上构建智能推荐系统的方法,重点阐述了知识库与工作流技术的结合应用。通过知识库管理RAG流程,实现文档上传、向量嵌入和检索优化;利用工作流设计节点化推荐逻辑,支持并行处理与条件分支。以电话销售话术推荐为例,展示了从数据收集到实时生成的完整流程。该方法具有准确性高、扩展性强、维护简便等优势,可广泛应用于各类推荐场景,实现从数据存储到智能推荐的闭环解决方案。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 1068

属性“xxxx”在类型“ArrayConstructor”上不存在。是否需要更改目标库? 请尝试将 “lib” 编译器选项更改为“es2015”或更高版本。

属性“form”在类型“ArrayConstructor”上不存在。是否需要更改目标库?请尝试将 “lib” 编译器选项更改为“es2015”或更高版本。打开jsconfig.json文件,如果引入了typescript语法就打开tsconfig.json。

qq_58626489的博客 1058

【微信小程序】微信小程序 manifest.json 配置 ES6 转 ES5 开关:3步让你的代码兼容性更强

ES6(ECMAScript 6)是 JavaScript 的最新标准,引入了许多新的语法和特性,如箭头函数、模板字符串、解构赋值等。然而,不是所有的环境都支持 ES6,特别是旧版本的浏览器和一些特定的运行环境。为了确保代码的兼容性,我们需要将 ES6 代码转换为 ES5 代码。通过本文的详细讲解,相信你已经学会了如何在文件中配置微信小程序的 ES6 转 ES5 开关。这个小小的配置步骤能够显著提高代码的兼容性和稳定性。如果你有任何问题或需要进一步的帮助,欢迎随时留言交流。

java专栏 1362

[翻译]JavaScript秘密花园 - Array, Array Constructor, for in loop, typeof, instanceOf

JavaScript Garden - 原文 JavaScript Garden - 中文翻译 数组遍历与属性 虽然在 JavaScript 中数组是是对象,但是没有好的理由去使用 `for in` 循环 遍历数组。 相反,有一些好的理由不去使用 for in 遍历数组。 注意: JavaScript 中数组不是 关联数组。 JavaScript 中只有对象 来管理键

三生石上 1146

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

JavaScript 的秘密花园

1、对象: JS中所有的变量都是对象,

咸鱼的星空 1326

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

《Javascript秘密花园》学习笔记(终)

实践了许多代码后,回头再看《Javascript秘密花园》,又有一些收获,与诸君分享 数组 typeof运算符 Value Class Type ------------------------------------- "foo" String string new String("f...

weixin_34252686的博客 329

”JavaScript 秘密花园“ 学习笔记 :

JavaScript秘密花园学习笔记

罗曼蒂克在消亡 379

《JavaScript 秘密花园》

恰巧今天是传统民间重要的节日之一——七夕节:被大家挂在嘴上最多的一句话便是:有对象了吗?这不……这样的话,那咱就先给new出一个对象吧:var boyfriend = new Object();然后再往其中增加属性,比如:他的名字叫Jay;1.对象:①增加属性boyfriend['name']='Jay'; ②访问属性(两种方式:点操作符或者中括号操作符)boyfriend.name;//"Jay...

weixin_34174105的博客 299

JavaScript - scope, namespace, constructor, equality and comparisons

JavaScript Garden - 原文 作用域与命名空间 尽管 JavaScript 支持一对花括号创建的代码段,但是并不支持块级作用域; 而仅仅支持函数作用域。 function test() { // 一个作用域for(var i = 0; i &lt; 10; i++) { // 不是一个作用域// count} console.log(i); // 10} ...

iteye_6378的博客 234
上一篇: JavaScript秘密花园 - scope, namespace, constructor, equality and comparisons
下一篇: JavaScript秘密花园 - Type Casting,undefined,eval,setTimeout,Auto Semicolon Insertion
迷渡
迷渡 领域专家: 前端开发技术领域 领域专家: 前端开发技术领域
博客等级 码龄19年 2405粉丝 124原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值