type
status
date
slug
summary
tags
category
icon
password

第1章 类型

本规范中的运算法则所操纵的值均有相应的类型。
ECMAScript语言类型包括Undefined、Null、Boolean、String、Number和Object。
function(函数)也是JavaScript的一个内置类型。然而查阅规范就会知道,它实际上是object的一个“子类型”。具体来说,函数是“可调用对象”,它有一个内部属性[[Call]],该属性使其可以被调用。
函数对象的length属性是其声明的参数的个数:
数组也是对象。确切地说,它也是object的一个“子类型”
JavaScript中的变量是没有类型的,只有值才有。变量可以随时持有任何类型的值。
语言引擎不要求变量总是持有与其初始值同类型的值
在对变量执行typeof操作时,得到的结果并不是该变量的类型,而是该变量持有的值的类型,因为JavaScript中的变量没有类型。
已在作用域中声明但还没有赋值的变量,是undefined的。相反,还没有在作用域中声明过的变量,是undeclared的。
问题是如何在程序中检查全局变量DEBUG才不会出现ReferenceError错误。这时typeof的安全防范机制就成了我们的好帮手

第2章 值

使用delete运算符可以将单元从数组中删除,但是请注意,单元删除后,数组的length属性并不会发生变化。
在创建“稀疏”数组(sparse array,即含有空白或空缺单元的数组)时要特别注意:
上面的代码可以正常运行,但其中的“空白单元”(empty slot)可能会导致出人意料的结果。a[1]的值为undefined,但这与将其显式赋值为undefined(a[1] = undefined)还是有所区别。
数组通过数字进行索引,但有趣的是它们也是对象,所以也可以包含字符串键值和属性(但这些并不计算在数组长度内):
如果字符串键值能够被强制类型转换为十进制数字的话,它就会被当作数字索引来处理。
有时需要将类数组(一组通过数字索引的值)转换为真正的数组,这一般通过数组工具函数(如indexOf(..)、concat(..)、forEach(..)等)来实现。
JavaScript中的数字类型是基于IEEE 754标准来实现的,该标准通常也被称为“浮点数”。JavaScript使用的是“双精度”格式(即64位二进制)。
从ES6开始,该值定义在Number.EPSILON中,我们可以直接拿来用,
a | 0可以将变量a中的数值转换为32位有符号整数,因为数位运算符|只适用于32位整数(它只关心32位以内的值,其他的数位将被忽略)。因此与0进行OR操作本质上没有意义。
JavaScript中的引用和其他语言中的引用/指针不同,它们不能指向别的变量/引用,只能指向值。

第3章 原生函数

通过构造函数(如new String("abc"))创建出来的是封装了基本类型值(如"abc")的封装对象。
new String("abc")创建的是字符串"abc"的封装对象,而非基本类型值"abc"
所有typeof返回值为"object"的对象(如数组)都包含一个内部属性[[Class]](我们可以把它看作一个内部的分类,而非传统的面向对象意义上的类)。这个属性无法直接访问,一般通过Object.prototype.toString(..)来查看。
基本类型值没有.length和.toString()这样的属性和方法,需要通过封装对象才能访问,此时JavaScript会自动为基本类型值包装(box或者wrap)一个封装对象
我们为false创建了一个封装对象,然而该对象是真值(“truthy”,即总是返回true,参见第4章),所以这里使用封装对象得到的结果和使用false截然相反。
关键字。不带时,它会被自动补上。因此Array(1,2,3)和new Array(1,2,3)的效果是一样的。
从ES5规范开始就允许在列表(数组值、属性列表等)末尾多加一个逗号(在实际处理中会被忽略不计)。所以如果你在代码或者调试控制台中输入[ , , , ],实际得到的是[ , , ](包含三个空单元的数组)。
我们可以通过下述方式来创建包含undefined单元(而非“空单元”)的数组: var a = Array.apply( null, { length: 3 } ); a; // [ undefined, undefined, undefined ]
apply(..)是一个工具函数,适用于所有函数对象,它会以一种特殊的方式来调用传递给它的函数。
除非万不得已,否则尽量不要使用Object(..)/Function(..)/RegExp(..):
强烈建议使用常量形式(如/^a*b+/g)来定义正则表达式,这样不仅语法简单,执行效率也更高,因为JavaScript引擎在代码执行前会对它们进行预编译和缓存。
符号是具有唯一性的特殊值(并非绝对),用它来命名对象属性不容易导致重名。
符号可以用作属性名,但无论是在代码还是开发控制台中都无法查看和访问它的值,只会显示为诸如Symbol(Symbol.create)这样的值。
我们可以使用Symbol(..)原生构造函数来自定义符号。但它比较特殊,不能带new关键字,否则会出错
符号并非对象,而是一种简单标量基本类型。
原生构造函数有自己的.prototype对象,如Array.prototype、String.prototype等。
以上方法并不改变原字符串的值,而是返回一个新字符串。
所有的函数都可以调用Function.prototype中的apply(..)、call(..)和bind(..)。
Function.prototype是一个函数,RegExp.prototype是一个正则表达式,而Array. prototype是一个数组。
Function.prototype是一个空函数,RegExp.prototype是一个“空”的正则表达式(无任何匹配),而Array.prototype是一个空数组。对未赋值的变量来说,它们是很好的默认值。例如:
这种方法的一个好处是.prototype已被创建并且仅创建一次。相反,如果将[]、function(){}和/(? :)/作为默认值,则每次调用isThisCool(..)时它们都会被创建一次(具体创建与否取决于JavaScript引擎,稍后它们可能会被垃圾回收),这样无疑会造成内存和CPU资源的浪费。
对于简单标量基本类型值,比如"abc",如果要访问它的length属性或String.prototype方法,JavaScript引擎会自动对该值进行封装(即用相应类型的封装对象来包装它)来实现对这些属性和方法的访问。

第4章 强制类型转换

隐式的情况称为强制类型转换(coercion)
JavaScript中的强制类型转换总是返回标量基本类型值(参见第2章),如字符串、数字和布尔值,不会返回对象和函数。
对普通对象来说,除非自行定义,否则toString()(Object.prototype.toString())返回内部属性[[Class]]的值(参见第3章),如"[object Object]"。
将对象强制类型转换为string是通过ToPrimitive抽象操作来完成的
工具函数JSON.stringify(..)在将JSON对象序列化为字符串时也用到了ToString。
对大多数简单值来说,JSON字符串化和toString()的效果基本相同,只不过序列化的结果总是字符串:
JSON.stringify(..)在对象中遇到undefined、function和symbol时会自动将其忽略,在数组中则会返回null(以保证单元位置不变)。
如果要对含有非法JSON值的对象做字符串化,或者对象中的某些值无法被序列化时,就需要定义toJSON()方法来返回一个安全的JSON值。

第1章 异步:现在与将来

因为它会锁定浏览器UI(按钮、菜单、滚动条等),并阻塞所有的用户交互
任何时候,只要把一段代码包装成一个函数,并指定它在响应某个事件(定时器、鼠标点击、Ajax响应等)时执行,你就是在代码中创建了一个将来执行的块,也由此在这个程序中引入了异步机制。
最好的选择是在JavaScript调试器中使用断点,而不要依赖控制台输出。次优的方案是把对象序列化到一个字符串中,以强制执行一次“快照”,比如通过JSON.stringify(..)。
JavaScript引擎本身并没有时间的概念,只是一个按需执行JavaScript任意代码片段的环境。“事件”(JavaScript代码执行)调度总是由包含它的环境进行。
然后浏览器就会设置侦听来自网络的响应,拿到要给你的数据之后,就会把回调函数插入到事件循环,以此实现对这个回调的调度执行。
setTimeout(..)并没有把你的回调函数挂在事件循环队列中。它所做的是设定一个定时器。当定时器到时后,环境会把你的回调函数放在事件循环中,这样,在未来某个时刻的tick会摘下并执行这个回调。
但现在ES6精确指定了事件循环的工作细节,这意味着在技术上将其纳入了JavaScript引擎的势力范围,而不是只由宿主环境来管理。这个改变的一个主要原因是ES6中Promise的引入,因为这项技术要求对事件循环队列的调度运行能够直接进行精细控制
它们在临时步骤中使用了共享的内存地址X和Y
JavaScript从不跨线程共享数据
这种不确定性是在函数(事件)顺序级别上,而不是多线程情况下的语句顺序级别(或者说,表达式运算顺序级别)。换句话说,这一确定性要高于多线程情况。
在JavaScript的特性中,这种函数顺序的不确定性就是通常所说的竞态条件(race condition)
可以把并发看作“进程”级(或者任务级)的并行,与运算级的并行(不同处理器上的线程)相对。
交互
通过简单的协调,就避免了竞态条件引起的不确定性。
你不知道的JavaScript(上卷)FLIP原理与实现文章来源说