you dont know JavaScript 2-1
2018-08-02 16:32:33 0 举报
AI智能生成
《你不知道的JavaScript(中卷)》第一部分——思维导图
作者其他创作
大纲/内容
《你不知道的JavaScript(中卷)》第一部分
类型
内置类型
分类
null、undefined、boolean、number、string、object、symbol(es6新增)
typeof
typeof返回一个字符串:object、undefined、boolean、number、string、object(只有函数是function)、symbol
typeof null === 'object'
原因:不同的对象在底层都表示为二进制,在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型,null 的二进制表示是全 0,自然前三位也是 0,所以执行 typeof 时会返回“object”
正确检测方法:(!a && typeof a === \"object\"); // true
值和类型
JavaScript 中的变量是没有类型的,只有值才有。变量可以随时持有任何类型的值。
区分
undefined
变量已经声明但还没有赋值
undeclared
变量没有声明
typeof对undefined和undeclared变量都返回 \"undefined\"
typeof Undeclared安全防范机制
typeof DEBUG !== \"undefined\"
值
数组
对数组声明后即可向其中加入值,不需要预先设定大小
使用 delete 运算符可以将单元从数组中删除,但是单元删除后,数组的 length 属性并不会发生变化
创建“稀疏”数组(含有空白或空缺单元的数组),“空白单元”的值为undefined
数组通过数字进行索引,也可以包含字符串键值和属性 (但这些并不计算在数组长度内)
如果字符串键值能够被强制类型转换为十进制数字的话,它就会被当作数字索引来处理
将类数组转换为真正的数组
var arr = Array.prototype.slice.call( arguments );
var arr = Array.from( arguments );
字符串
字符串是类数组,有 length 属性、 indexOf(..)、 concat(..) 方法
字符串不可变
字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串
字符串可以“借用”数组的非变更方法来处理字符串,如join、map等,但是不能用可变更成员函数reverse
字符串反转
方法:将字符串转换为数组,待处理完后再将结果转换回字符串
var c = a .split( \"\" ) .reverse() .join( \"\" );
此方法对于包含复杂字符(Unicode,如星号、多字节字符等)的 字符串并不适用
数字
格式
JavaScript中的数字使用的是“双精度”格式(即 64 位二进制),默认为十进制
其他格式:0x(十六进制)、 0o(八进制)、0b(二进制)
语法
toExponential()
指数格式
tofixed(..)
指定小数部分的显示位数,多余位数用0补齐
toPrecision(..)
指定有效数位的显示位数
. 运算符
会被优先识别为数字常量的一部分,然后才是对象属性访问运算符
较小的数值
0.1 + 0.2 === 0.3; // false
二进制浮点数中的 0.1 和 0.2 并不是十分精确,它们相加的结果并非刚好等于 0.3,而是一个比较接近的数字 0.30000000000000004
“机器精度” —— Number.EPSILON,这个值通常是 2^-52
比较两个数字是否相等
Math.abs( n1 - n2 ) < Number.EPSILON;
整数的安全范围
最大整数
Number.MAX_SAFE_INTEGER,即 2^53 - 1
最小整数
Number. MIN_SAFE_INTEGER,即 -(2^53 - 1)
整数检测
Number.isInteger(..)
特殊数值
null
指空值,或者曾经赋过值,但是现在没有值
指没有值,或者从未赋值
在非严格模式下,可以为全局标识符 undefined 赋值 (不要这样用)
undefined = 2;
在非严格和严格两种模式下,我们可以声明一个名为 undefined 的局部变量(不要这样用)
var undefined = 2;
void 运算符
表达式void ___ 返回结果为undefined。void并不改变表达式的结果,只是让表达式不返回值
NaN
执行数学运算没有成功,这是失败后返回的结果,是“无效数值”
NaN是一个特殊值,它和自身不相等,是唯一一个不等于自身的值
NaN !== NaN
检测NaN
isNaN(..)
判断一个值是否是 NaN
缺陷:参数不是数字,或者NaN,都被认为是NaN
Number.isNaN(..)
无穷数
Infinity
Infinity/ Infinity 是一个未定义操作,结果为 NaN
有穷正数 / Infinity = 0
有穷负数除以 Infinity ?
-Infinity
零值
-0
对负零进行字符串化会返回 \"0\"
JSON.stringify(-0) //\"0\"
String( -0 ); //\"0\"
从字符串转换为数字,结果是-0
JSON.parse(\"-0\") // -0
Number(\"-0\") //-0
为什么需要负零
有些应用程序中的数据需要以级数形式来表示(比如动画帧的移动速度),数字的符号位 (sign)用来代表其他信息(比如移动的方向)。此时如果一个值为 0 的变量失去了它的符号位,它的方向信息就会丢失。所以保留 0 值的符号位可以防止这类情况发生
由于0 === -0,如何区分 0 和 -0
function isNegZero(n) { n = Number( n ); return (n === 0) && (1 / n === -Infinity); }
Object.is(..)
判断两个值是否绝对相等,与===行为基本一致,但是可以弥补它的缺陷
值和引用
简单值(字符串和数字等)通过值复制的方式来赋值/传递
复合值(对象等)通过引用复制的方式来赋值 / 传递
原生函数
String()、 Number() 、 Boolean() 、 Array() 、 Object() 、 Function() 、 RegExp() 、 Date() 、 Error() 、 Symbol()
使用
通过new来实例化
var s = new String( \"abc\" );
typeof 返回值为 \"object\"
原因:new String(\"abc\") 创建的是字符串 \"abc\" 的封装对象,而非基本类型值 “abc\"
这些对象都包含一个内部属性 [[Class]],这个属性一般通过 Object.prototype.toString(..) 来查看
封装对象包装
由于基本类型值没有 .length 和 .toString() 这样的属性和方法,需要通过封装对象才能访问,此时 JavaScript 会自动为基本类型值包装一个封装对象
注意: var a = new Boolean( false ); //这个对象是真值,返回true
拆封
要得到封装对象中的基本类型值,可以使用 valueOf() 函数
原生函数作为构造函数
Array(..)
Array构造函数的new关键字可带可不带
Array 构造函数只带一个数字参数的时候,该参数会被作为数组的预设长度(length)
永远不要创建和使用空单元数组
Object(..)/Function(..)/RegExp(..)
除非万不得已,否则尽量不要使用构造函数形式,推荐使用常量形式来创建
Date(..)
创建日期对象必须使用 new Date(),Date(..) 可以带参数,用来指定日期和时间,而不带参数的话则使用当前的日期和时间
调用 Date() 时不带 new 关键字,则会得到当前日期的字符串值
时间戳可以通过 (new Date()).getTime() 获得
Error(..)
Error构造函数的new关键字可带可不带
创建错误对象主要是为了获得当前运行栈的上下文(大部分JavaScript引擎通过只读属性 .stack 来访问)。栈上下文信息包括函数调用栈信息和产生错误的代码行号, 以便于调试(debug)
Symbol(..)
符号(Symbol)是具有唯一性的特殊值(并非绝对),用它来命名对象属性不容易导致重名
构造函数不能带 new 关键字
var mysym = Symbol( \"my own symbol\" );
主要用于私有或特殊属性,用它来替代有下划线(_)前缀的属性
原生原型
文档约定: 将 String.prototype.XYZ 简 写 为 String#XYZ,其他类似
例如:String#indexOf(..),String#charAt(..),String#trim()等
强制类型转换
定义
将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况; 隐式的情况称为强制类型转换
类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时
隐式强制类型转换:隐藏的副作用
var b = 42 + \"\";
显式强制类型转换:明显的副作用
var c = String( 42 );
抽象值操作
ToString
负责处理非字符串到字符串的强制类型转换
字符串化规则
基本类型值
null 转换为 \"null\",undefined 转换为 \"undefined\",true 转换为 \"true\"
普通对象
toString()(Object.prototype.toString()) 返回内部属性 [[Class]] 的值
数组的默认 toString() 方法经过了重新定义,将所有单元字符串化以后再用 \
JSON.stringify(..)
在将 JSON 对象序列化为字符串时也用到了 ToString
和 toString() 的效果基本相同,只不过序列化的结果总是字符串
undefined、function 和 symbol
在对象中会自动将其忽略,在数组中则会返回 null(以保证单元位置不变)
参数
第一个是需要序列化的值
第二个是可选参数,可以是数组或者函数,用来指定对象序列化过程中哪些属性应该被处理,哪些应该被排除,和 toJSON() 很像
第三个是可选参数,用来指定输出的缩进格式。为正整数时是指定每一级缩进的字符数,它还可以是字符串来指定每一级的缩进格式
toJSON()
返回一个能够被字符串化的安全的 JSON 值
如果传递给 JSON.stringify(..) 的对象中定义了 toJSON() 方法,那么该方法会在字符串化前调用,以便将对象转换为安全的 JSON 值
ToNumber
转化规则
true -> 1,false -> 0,undefined -> NaN,null -> 0。处理失败时返回 NaN
对象(包括数组)
首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字
内部:为了将值转换为相应的基本类型值,抽象操作 ToPrimitive会首先检查该值是否有 valueOf() 方法,使用该值进行强制类型转换。如果没有就使用 toString()的返回值(如果存在)来进行强制类型转换。如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误
ToBoolean
假值
假值列表:undefined、null、false、+0、-0、NaN、“”
真值
假值列表以外的都是真值
假值对象
var a = new Boolean( false );
var b = new Number( 0 );
var c = new String( \"\" );
document.all:一个类数组对象,包含了页面上的所有元素。现在是一个假值对象
显式强制类型转换
字符串和数字
日期显式转换为数字
获得当前的时间戳
var timestamp = +new Date();
var timestamp = Date.now();
获得指定时间的时间戳
var timestamp = new Date().getTime();
~ 运算符
首先将值强制类型转换为 32 位数字,然后执行字位操作“非”(对每一个字位进行反转)
~x 大致等同于 -(x+1)
只有x为-1时返回假值0,其他都是返回真值
可以和indexOf()使用,更简洁
~a.indexOf( \"lo\" )
~~
第一个 ~ 执行 ToInt32 并反转字位,然后第二个 ~ 再进行一次字位反转,即将所有字位反转回原值,最后得到的仍然是 ToInt32 的结果
~~ 来取整,负数向上取整,正数向下取整。适用于 32 位数字
x | 0 也可以取整,规则同上
显式解析数字字符串
解析
允许字符串中含有非数字字符,解析按从左到右的顺序,如果遇到非数字字符就停止
parseInt(..)、 parseFloat(..)
参数是字符串值,传递其他类型的值无效
在es5之前,如果没有第二个参数来指定转换的基数,它会根据字符串的第一个字符来自行决定基数。x或X为十六进制,0为八进制
解析非字符串
1/0的计算结果是Infinity,然后parseInt(..)将结果强制转换为字符串“Infinity”再来解析
实际上是parseInt(\"Infinity\
转换
不允许出现非数字字符,否则会失败并返回 NaN
Number(..)
显式转换为布尔值
Boolean(..),不常用
!!
第一个 ! 显式地将值强制类型转换为布尔值,第二个 ! 再将结果反转回原值
隐式强制类型转换
+
+ 的其中一个操作数是字符串, 则执行字符串拼接,否则执行数字加法
[] + {} // \"[object Object]\"
{} + [] // 0
+和-都会先将值转换为字符串(valueOf()或者toString()),再转为数字进行计算
操作数选择器
a || b
a为真,就返回a的值(不执行b);a为假,就返回b的值
a && b
a为真,就返回b的值;a为假,就返回a的值(不执行b)
Symbol的强制类型转换
ES6 允许从符号到字符串的显式强制类型转换,然而隐式强制类型转换会产生错误
符号不能够被强制类型转换为数字(显式和隐式都会产生错误),但可以被强制类型转换为布尔值(显式和隐式结果都是 true)
== 和 ===
== 允许在相等比较中进行强制类型转换,而 === 不允许
注意:NaN 不等于 NaN,+0 等于 -0
==
字符串和数字之间的相等比较
字符串被强制类型转换为数字,再进行相等比较
其他类型和布尔类型之间的相等比较
布尔值会强制类型转换为数字,再进行相等比较
null 和 undefined 之间的相等比较
null == undefined
(对象/函数/数组)和(字符串/数字)之间的相等比较
对象首先调用ToPromitive抽象操作进行字符串化,再转为数字
“假阳”(true)
遵守原则
如果两边的值中有true或者false,千万不要使用==
如果两边的值中有[]、\"\"或者0,尽量不要使用==
a < b
比较规则
比较双方首先调用 ToPrimitive,如果结果出现非字符串,就根据 ToNumber 规则将双方强制类型转换为数字来进行比较
如果比较双方都是字符串,则按字母顺序来进行比较
标签
continue foo
执行 foo 循环的下一轮循环
break foo
跳出标签 foo 所在的循环 / 代码块,继续执行后面的代码
代码块
[] + {};
{}在+运算符之后,会被当成一个值(空对象)处理,强制类型转换为\"[object Object]\",[]转换为\"\"
\"[object Object]\"
{} + [];
{} 被当作一个独立的空代码块(不执行任何操作),+[]显示强制类型转换为0
0
运算符优先级
优先级从高到低排列 &&, ||, ? :
关联
左关联
&&, ||
右关联
=, ? :
自动分号插入ASI
ASI 实际上是一个“纠错”机制。这里的错误是指解析器错误
错误
SyntaxError —— 语法错误
ReferenceError
提前使用变量会报错,因为暂时性死区TDZ的存在
TDZ 指的是由于代码中的变量还没有初始化而不能被引用的情况
PRODUCED BY DL.
0 条评论
下一页