Deep-js-fundations
Type
js类型的描述
语言特性: 动态语言, 在运行时确定类型, 所以与静态语言不同的是,在初始化的时候并不需要我们指定变量的类型.
分类:
- 基本类型
- undefined
- string
- number
- boolean
- symbol
- null
- 引用类型
- object
- function
- array
- 草案阶段的类型
- bigInt
bigInt: 可以表示无限大的数, 例如:
1 | var n = 42n; |
typeof
使用typeof可以判断的类型有
- undefined
- number
- string
- boolean
- object
- symbol
- function
这里要注意一个特殊的例子:
1 | typeof null === 'Object' |
请写一个增强的判断js类型的函数.要求可判断引用类型(arr, funciton, Data)
1 | const isType = (value) => { |
undefined vs undeclared
这是两个不相等的关系.undeclared:在我可以触及的作用域从未创建过。undefined: 我肯定这是一个变量, 只是现在还没有值.
而在ES6语法中,我们在let定义一个变量之前去使用它,那么就会报错,这是临时死区的概念: 在定义这个变量之前的scoped都是临时死区, 无法访问。
1 | typeof a; // referentceError. |
NaN 与 isNaN
NaN 并不是指“Not A Number”, 虽然它的翻译确实如此.
NaN指的是一个无效的number, Invalid number.
我认为就是经过运算后无法转换成数字类型的都是NaN.
1 | let myAge = Number(42) // 42 |
negative Zero
让我们看一下-0的特性
1 | let a= -0 |
- -0 等于0
- -0 不大于0
- -0 不小于0
- 只能用Obect.is进行判断
应用:
1 | Math.sign(-3) // -1 |
Object.is polyfill
1 | // TODO: define polyfill for `Object.is(..)` |
fundational Object
use New Keyword
- object
- array
- function
- data
- regexp
- error
don’t use new Keyword
- string
- number
- boolean
1 | var sum = new Function('a', 'b', 'return a + b'); |
抽象运算符(Abstract Operation:ToPrimitive)
如果我们要使用到基础类型, 那么我们就会通过一个算法去转换它, 成为我们需要的类型
number
- valueOf()
- toString()
->to number
原则: 把所有值转换为number后返回
- Object: 调用valueOf方法
- String: 调用toPrimitive
- 调用顺序是: valueOf()->toString()
- 但是要注意, 所有的valueOf都是返回this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// 最普遍的例子
“” -> 0
“0” -> 0
“-0” -> -0
“009” -> 9
“3.1415926” -> 3.1415926
“0.” -> 0
“.0” -> 0
“.” -> NaN
“0xaf” -> 176
// 特殊字符
false-> 0
true-> 1
null-> 0
undefind-> 0
// 特殊例子
[''] -> 0
[0''] -> 0
['-0'] -> -0
[null] -> 0
['undefind'] -> 0
[1, 2, 3] -> NaN
[[[]]]-> 0
// 如果你重写了valueOf()方法,那么会应用到强制转换上
{
valueOf() {
return 3;
}
}
num = {valueOf() {return 3}}
num + 1 // 4
String
- toString()
- valueOf()
->TO String:
原则: 把所有的值强制转化为String后返回
- Object: 调用toString方法
- String: 调用toPrimitive
- 调用顺序是: toString()->valueOf()
看个例子:
1 | []->"" |
->toBoolean
- false
- “”
- 0/-0
- null
- NaN
- false
- undefined
- true: !false
coercion rules
大概有以下规则
- ‘+’: 如果为加号, 只要有一边是字符串, 则会把两边作为字符串处理
- ‘-‘: 只会把运算符两边作为数字来处理
- 布尔值:
- !!
- 0: false/ !0: true
- Boolean(value)
常见的触发场景:
- 使用模板字符串
- 字符串拼接(使用+号)
- 对对象的某个属性进行数学运算的时候, 会触发
1
2
3
4
5
6const addAStudent = number => number + 1;
addAStudent(student.count) // 171
// solution1
addAStudent(+student.count)
// solution2
addAStudent(Number(student.count))隐式转换
访问字符串的长度值,就是一种隐式转换:
string是基本类, 而这个基本类并不是一个对象,那么js会判定你想要把string当做一个对象访问,以便获取到String的长度值。
“someText”.length
在所有语言, 我们都要处理类型转换。而在js中,我们遵循的基本原则就是aka(讲道理,我理解就是上面说的三种转换)
边界转换事件
- ‘’ -> number
- boolean -> number
- 3>2>1 || 1>2>3
边界转换发生在字符串和数字转换之间
强制转换的应用
每个语言都要处理类型转换, 而每个语言都存在边际转换的情况,我们要做的是掌握这些边际问题,然后应用起来。
但是我们可以通过一些编码风格防止这些边界情况,例如使用typescript.以及,在你的代码中使用全等===。
营造学习文化
通过code review的方式, 让团队形成这样一种文化, 有助于帮助成员更好的了解他手中的工具, 当成员收到了代码审查,应该认真的去看,如果你发现了一些愚蠢的事,那么你应该让他过来,认真的说出这件事,让他避开那个边界情况做这样的事,是让大家成为更好的开发者。
你写的代码就像你在跟代码阅读者沟通, 他们应该可以理解。不然你在做的东西就是shit.浪费时间。
code communication
- 好的代码本身就是注释
- 但是注释本身也是必要的,特别是在一些复杂的业务逻辑上,在入口函数就说明它的入参结构, 功能, 代码组织方式,会减少很多维护者阅读代码的时间
隐式转换
- 隐式转换在一些写静态语言的人看来,是一种魔法,他们无法理解,为什么要做这样的事,所以认为这是js语言的弱点。
- 隐式转换是一种抽象概念。不是所有抽象都是好的,但是有些抽象是必要的。
- 提升代码清晰度的一个方法是,抽象不必要的细节,让阅读者关注我们需要他关注的地方。最常见的例子是: 比较运算符
- 我希望你是拥有分析能力的工程师,而不是写代码的猴子
理解特性
原则1: 有用的判断依据是, 你需要读者专注的点是重要的
原则2: 危险的是, 你写的东西如果有让人看不懂的地方,那么这就是危险的
原则3: 让读者能看得懂你的代码,并理解它
== 与 ===
两者区别:
=== 会检测类型与值, == 只会检测value, 那么意味着会触发强制转换
== 算法
- 优先转换成数字进行比较
- 若为非数字的原语(string, boolean, object, array), 那么会优先转换为原语
边际问题:
1 | [] == false; |
你应该避免进行以下的比较
- 使用 == 比较 “”/0/“ ”
- 使用 == 比较非原语(boolean/string/number)
- 如果要使用到 == true or == false,那么我更建议你去使用 === 做比较
优先使用 ==的情况
遵循两个原则
- 明确类型,比不知道类型好
- 静态类型(Typescript)不是唯一的方式让你去明确你的类型的方法
如果了解 == 双方的类型
- 场景1: == 不适用与不知道类型的比较场景, 当你不确定比较元素的类型的时候,不要使用==
- 场景2: == 适用于你知道两者的类型,并且期望它进行转换的场景(当你确定类型一样的情况下 == 与 === 是一样的情况)
- 场景3: 两者元素类型不一样的时候,使用 === 这样的逻辑注定错误
总结: 如果类型确定,那么优先使用 == 将是你最好的选择
如果不了解 === 双方的类型
- 建议: 如果你不能确认比较双方的类型是什么,那么你不够了解你的代码,建议重构, 基准是你能明白类型是什么
- 类型不能确定会让你代码的阅读者困惑, 所以当你需要给代码阅读者明显的信号,让他注意这个地方的时候,请使用 ===
- 如果类型处于不确定的状态下, 使用 === 真的是一个保护措施
总结: 如果你代码中,不能确定类型,那么使用 === 保护你的代码时必要措施
当然,如果你代码里都是 === 那么,你要表达的东西是,我不相信(不知道)每一个比较两边的类型
我们写的代码应该是类型确定和明显会让代码质量更高,如果类型确定,那么优先使用== ,如果类型不确定,那么优先使用 === 保护你的代码