【自我回顾】我真的学会JavaScript基础了吗(一)

236 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

从学习JavaScript这门语言到在工作中使用已一年有余,回过头来阅读JavaScript规范时,我发现有部分内容是工作中遇到了但没有认真思考其本质的的,另一部分内容则是学习的时候就遗漏的。

下面,我想结合具体的应用场景,谈谈我认为比较重要的几个点,以期待加深对这门语言的熟练度,领悟其设计哲学。

1.JavaScript 是动态类型的

JavaScript,被称为“动态类型”(dynamically typed)的编程语言,意思是虽然编程语言中有不同的数据类型,但是你定义的变量并不会在定义后,被限制为某一数据类型。

JavaScript归根到底是弱类型、动态的编程语言。

而Java是强类型、静态类型的语言:

JavaScript
let a = 1;
a = "Hello" //允许
Java
private char a;
a = "sss" //error,a只能接收char类型而非string类型的数据

而在TypeScript中,弱类型这一点得到了很好的规范和调整。

2.值的比较

普通比较运算符==运算时,当对不同类型的值(基本类型,除了undefined和null)进行比较时,JavaScript 会首先将其转化为数字类型(number)再判定大小。

在ES2020中,JavaScript一共有八种数据类型,其中引用类型1种,基本类型7种。他们分别是:

  • String
  • Number
  • BigInt
  • Null
  • Undefined
  • Boolean
  • Symbol
  • Object

严格比较运算符=== 在比较时是不会进行类型转换的。

工作中推荐使用严格比较运算符,避免产生数据类型的问题。

3.Null 和 0 的比较

这一点从初学以来就非常头疼,null、undefined、0他们都可以表示“无”的意思,但是他们的用法又是实实在在不一样的。

在类型转换中,null转换成数字时会被转换成0。

consolo.log(null > 0); // (1) false 
consolo.log(null == 0); // (2) false 
consolo.log(null >= 0); // (3) true

上面的比较结果似乎不太符合数学运算规律,因为在最后一行代码显示“null 大于等于 0”的情况下,前两行代码中一定会有一个是正确的,然而运行发现它们的结果都是 false。

相等性检查 == 和普通比较符 > < >= <= 的代码逻辑是相互独立的。进行值的比较时,null 会被转化为数字,因此它被转化为了 0。这就是为什么(3)中 null >= 0 返回值是 true,(1)中 null > 0 返回值是 false。

另一方面,undefined 和 null 在相等性检查 == 中不会进行任何的类型转换,(一般来说相等性检查是先转换为number类型再进行比较)它们有自己独立的比较规则,所以除了它们之间互等外,不会等于任何其他的值。这就解释了为什么(2)中 null == 0 会返回 false。

在非严格相等 == 下,null 和 undefined 相等且各自不等于任何其他的值。

4.空值合并运算符(ES2020)

这个在工作中暂时用的较少,都是通过undefined来作判断,这次正好回顾、学习一下。

空值合并运算符的写法为两个问号 ??

a ?? b 的结果是:

  • 如果 a 是已定义的,则结果为 a
  • 如果 a 不是已定义的,则结果为 b

也就是说,如果第一个参数不是 null/undefined,则 ?? 返回第一个参数。否则,返回第二个参数。

let firstName = null; 
let lastName = null; 
let nickName = "Jack"; // 显示第一个已定义的值: 
alert(firstName ?? lastName ?? Jack ?? "wumingshi"); // Jack

5.函数命名规范

这个话题似乎简单又抽象,但是函数命名确实是一个大学问,尤其是在面对一个页面中存在很多个功能和逻辑的时候,规范的函数命名能大大提高我们的工作效率。

函数就是行为(action)。所以它们的名字通常是动词。它应该简短且尽可能准确地描述函数的作用。这样读代码的人就能清楚地知道这个函数的功能。

一种普遍的做法是用动词前缀来开始一个函数,这个前缀模糊地描述了这个行为。团队内部必须就前缀的含义达成一致。

例如,以 "show" 开头的函数通常会显示某些内容。

函数以 XX 开始……

  • "get…" —— 返回一个值,
  • "calc…" —— 计算某些内容,
  • "create…" —— 创建某些内容,
  • "check…" —— 检查某些内容并返回 boolean 值,等。

6.一个函数 独立 一个行为

一个函数应该只包含函数名所指定的功能,而不是做更多与函数名无关的功能。

两个独立的行为通常需要两个函数,即使它们通常被一起调用(在这种情况下,我们可以创建第三个函数来调用这两个函数)。

7.函数和函数表达式

// 函数声明 
function sum(a, b) { return a + b; }
// 函数表达式 
let sum = function(a, b) { return a + b; };

一旦代码执行到赋值表达式 let sum = function… 的右侧,此时就会开始创建该函数,并且可以从现在开始使用(分配,调用等)。

函数声明则不同。

例如,一个全局函数声明对整个脚本来说都是可见的,无论它被写在这个脚本的哪个位置。

这是内部算法的原故。当 JavaScript 准备 运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数。我们可以将其视为“初始化阶段”。

在处理完所有函数声明后,代码才被执行。所以运行时能够使用这些函数。

例如下面的代码会正常工作:

*sayHi("John"); // Hello, John* 
function sayHi(name) { alert( `Hello, ${name}` ); }

函数声明 sayHi 是在 JavaScript 准备运行脚本时被创建的,在这个脚本的任何位置都可见。

如果它是一个函数表达式,它就不会工作:

*sayHi("John"); // error!* 
let sayHi = function(name) 
{ // (*) no magic any more alert( `Hello, ${name}` ); };

总结起来就是两句话:

函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用。

在函数声明被定义之前,它就可以被调用。

未完待续……

参考资料: zh.javascript.info/