查看原文
其他

JavaScript 竟惨遭开发者嫌弃?

程序人生 2022-04-19

大家都说 JavaScript 很怪异,可明明它又没做错什么,难道带来高效和方便也是一种错吗!让我们一起跟着作者来走进 JavaScript 的世界,来感受它的酷!


译者 | 弯月       责编 | 宋彤彤
头图 | CSDN 下载自东方 IC
出品 | CSDN(ID:CSDNnews)

我是一个单线程、非阻塞、异步并发语言。

我有一个调用栈、一个事件循环、一个回调队列和其他一些 API。

 —— JavaScript

你可以让应用程序获取一个 API。你的按钮使用全局状态。但是每当控制台中出现红色警告,你都会向 Stack Overflow 哭诉。

使用框架构建产品很方便。在实践中学习很酷。但是,由于缺乏深入了解,你肯定会碰壁。

所以我报名了网上的课程。


计算机如何理解 JavaScript


问题:你会使用 JavaScript 编写代码,但计算机不理解。

解决方案我们来简化:

  • 语法解析器变成……

高级代码 -> 数据结构(树或图)

  • 然后由编译器翻译……

数据结构 -> 低级语言(机器码)

请不要与转译相混淆,转译是一种高级编程语言到另一种的语法转换,比如 TypeScript -> JS。


执行上下文是什么?


在理解 JavaScript 的运行之前,我们首先需要理解执行上下文是什么。

执行上下文是执行一段代码的环境。输入 this,你就可以看到上下文的信息。上下文的内容取决于你是否在函数内部,但通常包含:

  • 本地代码(变量、对象、函数)

  • 全局对象(通过浏览器的 window 访问)

  • 词法环境(对其外部环境的引用)

JavaScript是怎样运行的?


执行上下文分两个阶段执行:

  1. 创建阶段:为变量和函数建立内存空间。

  2. 代码执行阶段:逐行运行代码(详细说明见下)。

在创建阶段,最初所有的变量都会被设置为 undefined,而函数则完全位于内存中。但是请注意, “undefined ” 不同于 “ReferenceError: my_var is not defined”,后者是指变量尚未分配内存空间。

事件循环和执行栈

在运行程序时,会创建全局执行上下文;接着,每当调用函数时,其执行上下文就会被放到执行栈的顶部。

请记住,JavaScript 是单线程的,这意味着它只有一个调用栈。此外,JavaScript 是同步的,这意味着每个命令都是按顺序执行的。

每个函数都会创建自己的执行上下文,而该上下文将贯穿创建和执行阶段。当栈顶部的函数运行完成后,就会被弹出。


了解作用域链


我们来看看下面这段代码:

function b() { console.log(myVar);}function a() { var myVar = 2; b();}var myVar = 1;a();

正确答案是1。为什么不是 undefined?

因为如果当前执行上下文中没有定义某个变量,则它会去外部环境寻找(在上面的代码中是全局执行上下文)。作用域链就是这个外部环境的引用链。


JavaScript类型:基本上是无类型


JavaScript是动态类型,也就是说没有关键字定义变量指向的数据类型。JavaScript 与 TypeScript 的主要区别就在于此,TypeScript 是静态类型。

什么是基本类型?

基本类型是一种表示单个值的数据类型(不是键值对或对象)。

JavaScript 中有六种基本类型:

  • undefined:"不存在"。

  • null:也是“不存在”,但它是一个确定的值。

  • boolean :true 或 false。

  • number:浮点数,也就是说数字永远是小数(JavaScript 中唯一的数字类型)。

  • string:文本。

  • symbol:仅限于 ES6 。

运算符都有哪些?

运算符是语法上不同的函数。通常运算符接受两个参数,并返回一个结果。

与普通的函数不同,运算符使用中缀表示法,即 3+4,而不是前缀表示法 +(3,4) 或后缀表示法 (3, 4)+。

  • 运算符优先级:优先调用哪个函数。

  • 运算符结合律:函数被调用的顺序(从左到右,或从右到左)。

什么是强制转换?

强制转换指的是将值从一种类型转换为另一种类型,例如:

var a = 1 + '2';

有时候,强制转换的行为会非常怪异:

console.log(3 < 2 < 1); // trueconsole.log(Number(undefined)); // Nanconsole.log(Number(null)); // 0

相等(==)会执行强制转换,而严格相等(===)不会:

console.log(Number('3' == 3)); // truthyconsole.log(Number('3' === 3)); // falsy

换句话说,我们应该尽可能使用严格相等,否则代码就会出现一些预料之外的行为。

最后,我们可以使用强制转换来检查某个变量是否已定义(但要小心零!)

if (a || a === 0) { console.log("There's a there there.");}


JSON 与对象字面量


JSON 的键需要使用引号,而对象不需要。因此,所有 JSON 都可以用作对象,反之则不然。

但由于二者非常相似,JavaScript 为 JSON 提供了许多内置功能:

  • JSON.stringify():获取一个对象,并输出字符串形式的 JSON。

  • JSON.parse():接受一个字符串,并输出一个对象。

对象字面量与构造函数

本质上,{} 与 new Object() 相同,但使用字面量创建的对象是全局的。而构造函数则允许我们创建对象的实例。

函数是对象!

JavaScript 中的函数有着举足轻重的地位,也就是说函数可以当做任何其他对象或类型进行处理(可以被创建、传递等等),这就是 JavaScript 非常适合函数式编程的原因。

虽然,函数与对象的不同指出主要表现在以下两个方面:

  • 匿名:可以不指定名称。

  • 拥有可调用的代码。

当一个函数被附着到一个对象时,函数范围内的 this 会指向该对象,而匿名函数中的 this 指向的是它的创建者。

值传递与引用传递

最后,所有基本类型都是值传递,所有对象(包括函数)都是引用传递。

基本类型的值变量 a  位于内存中的某个位置(例如 0x001)。如果我们将新的 var b 传递给该 var a,它会在内存的其他位置创建一个基本类型的值的副本(例如 0x002)。这是值调用(即将值复制到内存中的两个单独的位置)。这意味着我们之后修改 a 时 b 不会受影响 。

然而,当我们复制一个对象变量时,新变量就会指向内存中的同一个位置(也称为引用):

a = new Object(); // 0x001b = a; // 0x001

总结

可怜的 JavaScript,他们都说你很怪异。

这不公平,你不应该害怕。

有人理解你的怪异之处,而他们会为你喝彩。

其实你很高效,缺陷也不是太多。

原文链接:https://broman.blog/relearning-js

本文为 CSDN 翻译,转载请注明来源出处。


《新程序员003》正式上市,50余位技术专家共同创作,云原生和数字化的开发者们的一本技术精选图书。内容既有发展趋势及方法论结构,华为、阿里、字节跳动、网易、快手、微软、亚马逊、英特尔、西门子、施耐德等30多家知名公司云原生和数字化一手实战经验!


☞PHP 正在干掉 Python
我司空降了一名专家后,一半程序员疯了...
2021年C++项目中的十大bug:乍一看都正确的代码,实则暗藏玄机!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存