js 深度学习 -类型 与 文法
js 深度学习 -类型 与 文法
You-Dont-Know-JS(你不知道的 js 这本书的开源版本)
You-Dont-Know-JS(你不知道的 js 这本书的开源版本)
github 国内翻译
https://github.com/JoeHetfield/You-Dont-Know-JS
掘金中文
https://juejin.cn/post/6844903478813261831
github 原帖
Number
非常大或非常小的number将默认以指数形式输出,与toExponential()方法的输出一样,比如:
1 |
|
因为number值可以用Number对象包装器封装,number值可以访问内建在Number.prototype上的方法。举个例子,toFixed(..)方法允许你指定一个值在被表示时,带有多少位小数:
1 |
|
要注意的是,它的输出实际上是一个number的string表现形式,而且如果你指定的位数多于值持有的小数位数时,会在右侧补0。
toPrecision(..)很相似,但它指定的是有多少 有效数字 用来表示这个值:
1 |
|
你不必非得使用持有这个值的变量来访问这些方法;你可以直接在number的字面上访问这些方法。但你不得不小心.操作符。因为.是一个合法数字字符,如果可能的话,它会首先被翻译为number字面的一部分,而不是被翻译为属性访问操作符。
// 不合法的语法:
1 |
|
// 这些都是合法的:
1 |
|
42.toFixed(3)是不合法的语法,因为.作为42.字面的一部分被吞掉了,因此没有.属性操作符来表示.toFixed访问。
42..toFixed(3)可以工作,因为第一个.是number的一部分,而第二个.是属性操作符。但它可能看起来很古怪,而且确实在实际的 JavaScript 代码中很少会看到这样的东西。实际上,在任何基本类型上直接访问方法是十分不常见的。但是不常见并不意味着 坏 或者 错。
number 还支持科学计数法,以及二进制,八进制,十六进制
var onethousand = 1E3; // 代表 1 * 10^3
var onemilliononehundredthousand = 1.1E6; // 代表 1.1 * 10^6
1 |
|
关于 number 一个大坑
就是 0.1 + 0.2 不等于 0.3 问题
其实并不是 javascript 独有的问题。 而是使用 IEEE 754 语言标准的通病
**可以通过 ** “机械极小值(machine epsilon)” 来判断,就是说两个相比的数,相减小于机械极小值,就是相等了。
在 ES6 中,使用这个容差值预定义了Number.EPSILON,所以你将会想要使用它,你也可以在前 ES6 中安全地填补这个定义:
1 |
|
我们可以使用这个Number.EPSILON来比较两个number的“等价性”(带有错误舍入的容差):
1 |
|
可以被表示的最大的浮点值大概是1.798e+308(它真的非常,非常,非常大!),它为你预定义为Number.MAX_VALUE。在极小的一端,Number.MIN_VALUE大概是5e-324,它不是负数但是非常接近于 0!
Error(..)
就是抛出 错误哈 可以用 new Error() 构造器写法。 也可以直接 Error()
一般 模拟 真实报错 用 throw 关键字抛出错误, return 的话就如同 console 上打印一般,没得劲
提示: 技术上讲,除了一般的Error(..)原生类型以外,还有几种特定错误的原生类型:EvalError(..),RangeError(..),ReferenceError(..),SyntaxError(..), TypeError(..),和URIError(..)。但是手动使用这些特定错误原生类型十分少见。如果你的程序确实遭受了一个真实的异常,它们是会自动地被使用的(比如引用一个未声明的变量而得到一个ReferenceError错误)。
=
Symbol(..)
在 ES6 中,新增了一个基本值类型,称为“Symbol(标志)”。Symbol 是一种特殊的“独一无二”(不是严格保证的!)的值,可以作为对象上的属性使用而几乎不必担心任何冲突。它们主要是为特殊的 ES6 结构的内建行为设计的,但你也可以定义你自己的 symbol。
Symbol( [description] )
description** **可选可选的,字符串类型。对 symbol 的描述,可用于调试但不是访问 symbol 本身。
Symbol 可以用做属性名,但是你不能从你的程序中看到或访问一个 symbol 的实际值,从开发者控制台也不行。例如,如果你在开发者控制台中对一个 Symbol 求值,将会显示Symbol(Symbol.create)之类的东西。
在 ES6 中有几种预定义的 Symbol,做为Symbol函数对象的静态属性访问,比如Symbol.create,Symbol.iterator等等。要使用它们,可以这样做:
obj[Symbol.iterator] = function(){ /../ };
要定义你自己的 Symbol,使用Symbol(..)原生类型。Symbol(..)原生类型“构造器”很独特,因为它不允许你将new与它一起使用,这么做会抛出一个错误。
1 |
|
虽然 Symbol 实际上不是私有的(在对象上使用Object.getOwnPropertySymbols(..)反射,揭示了 Symbol 其实是相当公开的),但是它们的主要用途可能是私有属性,或者类似的特殊属性。对于大多数开发者,他们也许会在属性名上加入_下划线前缀,这在经常在惯例上表示:“这是一个私有的/特殊的/内部的属性,别碰!”
注意: Symbol 不是 object,它们是简单的基本标量。它是一个抽象的符号。
不是值的值
- null是一个空值
- undefined是一个丢失的值
或者:
- undefined还没有值
- null曾经有过值但现在没有
null**是一个特殊的关键字,不是一个标识符,因此你不能将它作为一个变量对待来给它赋值(为什么你要给它赋值呢?!)。然而,**undefined**(不幸地)**是 一个标识符。可以被赋值。
NaN
Nubmer 类型 真正的意思应该为: 不合法的数字、坏掉的数字、失败的数字。
在 ES6 中,:Number.isNaN(..) 不像 window.isNaN() 那样 会把字符串, 就是除了数字外的都理解为 NaN.
实际上,通过利用NaN与它自己不相等这个特殊的事实,我们可以更简单地实现
判断是否为 NaN 最好的方法就是 自己不等于自己的数 即是 NaN
1 |
|
=
特殊等价
当使用等价性比较时,值NaN和值-0拥有特殊的行为。NaN永远不会和自己相等,所以你不得不使用 ES6 的Number.isNaN(..)(或者它的填补)。相似地,-0撒谎并假装它和普通的正零相等(即使使用===严格等价)
在 ES6 中,有一个新工具可以用于测试两个值的绝对等价性,而没有任何这些例外。它称为Object.is(..): 让 -0 能等于 -0 NaN 能等于 NaN
1 |
|
Object.is(..)可能不应当用于那些==或===已知 安全 的情况(见第四章“强制转换”),因为这些操作符可能高效得多,并且更惯用/常见。Object.is(..)很大程度上是为这些特殊的等价情况准备的。
=
值与引用
在 JavaScript 中,没有指针,并且引用的工作方式有一点儿不同。你不能拥有一个从一个 JS 变量到另一个 JS 变量的引用。这是完全不可能的。引用都是值(数据)的引用
基本数据类型就是除了 Object 外的 他们的赋值本质都是拷贝**
**而被拥有引用数据类型值的变量赋值则是 对 Object 值本身的引用,而非对赋值变量的引用。**
**就是说 你可以通过存有某对象引用的变量,来修改这个对象本身,因为不是拷贝,是引用(共享)。**
**修改后的值会共享到同样引用此对象的变量上面。**
**但是你对这个变量重新赋值时,并不代表对引用的对象赋值,只是单纯的给这个变量赋值。**
**引用的对象** **还是 原样一点没变,只是重新赋值后的变量的值 变成了其他的值,**
**其他引用这个对象的变量,值依然是那个对象,不会改变的。**
**这很重要,不要被骗了。
a 赋值给 b** 实质上是把 [1, 2, 3] 这个数组对象的引用赋值给了 b,而并非 a 对象本身**
- a 变量 可以访问 [1, 2, 3] 这个数组对象的引用,也就可以调用 push 修改这个数组对象, 同样拥有[1, 2, 3]数组对象引用的 b 变量自然的会共享到修改后的值
- 但是 对 a 变量本身重新赋值, 跟 b 变量完全没有一点关系,b 变量 还是存有 修改后的[1, 2, 3] 数组对象的引用
你可以修改 变量引用的一部分 比如 object 的键值, arr 的元素。这些都会
– 实例分析
1 |
|
正如你看到的,x.length = 0和x.push(4,5,6,7)没有创建一个新的array,但是修改了现存的共享array。
操作符
**1. || ** 和 && 操作符
表达式中 :
- || 和 && 操作符号 都是 判断第一个参数,会把第一个参数强转为 一个 Boolean 值 。
- || 是 第一个参数正确就取第一个参数, 第一个参数错误则取第二个参数
- 而 && 是 第一个参数正确就取第二个参数,第一个参数错误,就取第一个参数。 刚开始会感觉挺无厘头的,但是这种机制完全跟 if 如出一辙,很多时候都可以 用 && 取代 if 语句 。
- 需要注意 && 与传统 if 语句的不同, 就是当 第一个参数错误时,&& 会执行第一个参数本身,而非强转后的布尔值。
if 的条件中
- 就是单纯返回 true false 了
- || 表示任意一个正确就返回 true, && 表示都要正确 才返回 true
- 但是本质上 也会是表达式中那样运转 只是最后返回的参数 被 if 再一次强转为了 boolean 值
1 |
|
2. 优先级问题
==
三元表达式 ?后的 一项 也可以是一个三元表达式
&& 优先级比 || 高,而 || 优先级比 ? : 高。 if 语句中 && || 也高于 = 。所以赋值语句需要用小括号框住。
3. {}
js 文法上 {} 除了**被*做运算 (+{}、-{} 、{}.. 但不包括 = {})。
本质上都是空的代码块的意思, 不是空对象。
1 |
|
在第一行中,{}出现在+操作符的表达式中,因此被翻译为一个实际的值(一个空object),[]被强制转换为“”因此{}也会被强制转换为一个string:“[object Object]”。
但在第二行中,{}被翻译为一个独立的{}空代码块儿(它什么也不做)。块儿不需要分号来终结它们,所以这里缺少分号不是一个问题。最终,+ []是一个将[]明确强制转换 为number的表达式,而它的值是0。
4. 逻辑操作符
ECMAScript 中的所有数值都以 IEEE-754 64 位格式存储,但位操作符并不直接操作 64 位的值。而是先将 64 位的值转换成 32 位的整数,然后执行操作,最后再将结果转换为 64 位。就是只要使用操作符的 两个 数值还是字符串或是其他数据类型,都会被转为 32 位的 整数
“ | “ ( 按位或 or )
相或的两位数 只要其中一位是 1 就是 1 。两位同时为 0 才为 0
任何数 和 0 ‘|’ 都得那个数本身
但特殊数字转为 32 位 整数 都得 0
“ ^ “ ( 位异或 )
相位异或的两位数 只要其中一位是 1 就是 1 。两位同时为 1 则为 0, 两位同时为 0 也为 0
“ & “ ( 按位与 and )
相与的两位数 只要其中一位是 0 就是 0 。两位同时为 1 才为 1
任何数 和 0 ‘&’ 都得 0
“ ~ “ ( 按位取反 )
- 第 1 步:把运算数转换为 32 位的二进制整数。
- 第 2 步:逐位进行取反操作。
- 第 3 步:把二进制反码转换为十进制浮点数。
其实本质的结果就是 取一个数的相反数 然后 -1
~ 12 ———> -12 - 1 ———> -13
~ -12 ———> 12 -1 ———> 11
最佳可以搭配 indexOf() 使用。 因为 indexOf() 索引不存在的下标会返回 -1 而 ~-1 等于 0 也是就是一个 false,而且其他任何值都会返回个 true 。所有完全避免了写 比较判断。
还可以使用 ‘~~’ 双~ 把一个数的小数位给去掉。
“ !! “ ( 否定之否定 )
就是把一个 值 强转为 Boolean 类型
数值转 二进制方法
5. ‘==’ 的 坑
不要在任何情况下,使用== true或== false。永远。
因为 == 布尔 逻辑判断中 布尔值 都是 默认转 number 类型来判断比较。其他数值不会转成 Boolean 的。
但时要记住,我在此说的仅与==有关。=== true和=== false不允许强制转换,所以它们没有ToNumber强制转换,因而是安全的。
- 如果比较的任意一边可能出现**true**或者**false**值,那么就永远,永远不要使用**==**。
- 如果比较的任意一边可能出现**[]**,**“”**,或**0**这些值,那么认真地考虑不使用**==**。
考虑如下代码:
1 |
|
如果你在你的代码中一直避免使用== true或== false(也就是与boolean的宽松等价),你将永远不必担心这种真/假的思维陷阱。
6. 关系型比较
JS 更准确地将 **<font style="background-color:#F3F4F4;"><= </font>**
考虑为“不大于”
a <= b 即是 !(a>b)
>=考虑为“不小于”
a >=b 即是 !(a<b)
不幸的是,没有像等价那样的“严格的关系型比较”。换句话说,没有办法防止a < b这样的关系型比较发生 隐含的 强制转换,除非在进行比较之前就明确地确保a和b是同种类型。
使用与我们早先==与===合理性检查的讨论相同的推理方法。如果强制转换有帮助并且合理安全,比如比较42 < “43”,就使用它。另一方面,如果你需要在关系型比较上获得安全性,那么在使用<(或>)之前,就首先 明确地强制转换 这些值。
var a = [ 42 ];
var b = “043”;
a < b; // false – 字符串比较!
Number( a ) < Number( b ); // true – 数字比较!
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!