theme: smartblue
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
JavaScript 高级程序设计第 4 版(后简称高程4),相较于第 3 版,增加了 ES6 至 ES10 的全新内容,删除了旧版过时的内容,并在原有基础上充实了更加翔实的内容。
中文译版于 2020 年发售,妥妥的“新鲜出炉”,你要是问本瓜:当今学 JavaScript 哪家强,我只能说:红宝书第 4 版最在行。
于是乎,借着更文契机,本瓜将开启一个小系列,带你重看一遍高级程序设计4(先前只是跳着跳着看),将抽取精华,用最简单的话解释核心点、尽量把握全局、快速过一遍的同时,记录与工友们分享~~
正文
第三章:语法是任何语言的核心所在!
第一句:
ECMAScript 的语法很大程度上借鉴了 C 语言和其他类 C 语言,如 Java 和 Perl。
这句计算机语言之间的历史沿革关系很重要,做“全干“程序员,一定要知晓它们,触类旁通。
有兴趣的同学一定要去看看 编程语言历史,维基词条:https://zh.wikipedia.org/wiki/程式語言歷史;
本瓜找到一张很棒的高级语言发展史的图:实线表示 直接继承 关系,虚线表示 参考借鉴 关系
接着,行文就讲到:JS 的注释、严格模式(我在实际工作中用得很少)、语句、关键保留字,这些都比较基础,不做赘述。
然后,讲到变量,变量提升,var 的变量提升我相信大家都很清楚,另外:还有一个函数的提升,不知道你清楚吗?一起提一下:
代码语言:javascript复制fn()
const fn = function(){
console.log(1)
}
// 这样写,会报错:fn is not defined
fn()
function fn(){
console.log(1)
}
// 这样写,则不会报错,因为函数提升
本瓜更倾向使用“没有提升的变量声明或函数声明”,由上自下,代码结构清晰,不然,写这种隐式的提升,会造成很多困扰!!
比如看这种代码,根本没有食欲,还容易出错:
代码语言:javascript复制function hoistFunction() {
foo();
var foo = function() {
console.log(1);
};
foo();
function foo() {
console.log(2);
}
foo();
}
hoistFunction();
// 2
// 1
// 1
但就老老实实写成这样,不要提升,不就清晰多了吗?
代码语言:javascript复制let foo = undefined
function hoistFunction() {
foo = function foo() {
console.log(2);
}
foo();
foo = function() {
console.log(1);
};
foo(); // 1
foo(); // 1
}
hoistFunction();
// 2
// 1
// 1
然后,var、let、const 区别就不作展开了。
- 有个小 trick,问:通过 const 声明了,真的就不能再被修改了吗??
再问:为什么要在 ES6 推出 let 和 const ?? 本瓜认为有一个回答的方向:使用 let 或 const 是声明式的代码风格!!什么意思?即我们推崇:变量声明了就不要修改了!那有人问:用 let 声明,也会被修改啊;当然,但是至少 let 的修改只影响局部的快,能减少影响的范围,这就是一种进步;实际也是如此,我们推荐使用 const > let > var。
至于,为什么推荐变量声明了,就不要再修改了,这其实是函数式编程的思想,可以了解下 immutable.js 以及 λ 变量计算等,这里先不作展开;
然后,行文来到 JavaScript 数据类型:
- "undefined"表示值未定义;
- "boolean"表示值为布尔值;
- "string"表示值为字符串;
- "number"表示值为数值;
- "object"表示值为对象(而不是函数)或 null;
- "function"表示值为函数;
- "symbol"表示值为符号。
变量值可以用 typeof 来检查,结果就是以上 7 种的任一一种;
老前端知道 typeof 来检查类型是远不够的,它不能检查出 array、正则、内置对象等,会将它们都返回为 Object
这个时候,就需要用到:
Object.prototype.toString.call()
typeof([]) // 'object'
typeof(/g/) // 'object'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(/g/) // '[object RegExp]'
具体各类型下的细节,就不一一展开啦:
抛个经典的面试考点:为什么0.1 0.2不等于0.3?
因为:JS Number 是二进制浮点数,0.1 和 0.2 转换成二进制后会无限循环,
代码语言:javascript复制0.1 -> 0.0001100110011001...(无限循环)
0.2 -> 0.0011001100110011...(无限循环)
二者相加时,会根据 IEEE 754 尾数位数限制,将后面多余的位截掉,导致了精度缺失,使得不等于 0.3;
还有 Object 对象要拿出来说说:在 ECMAScript 中 Object 是所有对象的基类
怎么理解?
任何基础的类型都可以通原型链找到 Object
代码语言:javascript复制String.prototype.__proto__===Object.prototype // true
Number.prototype.__proto__===Object.prototype // true
Function.prototype.__proto__===Object.prototype // true
Array.prototype.__proto__===Object.prototype // true
......
所以说:万事万物皆由对象构造的,一点没错,万物皆对象!!
所以,Object 有的属性,基本的类型也有,这些属性是:
- constructor:用于创建当前对象的函数。在前面的例子中,这个属性的值就是 Object() 函数。
- hasOwnProperty(propertyName):用于判断当前对象实例(不是原型)上是否存在给定的属 性。要检查的属性名必须是字符串(如 o.hasOwnProperty("name"))或符号。
- isPrototypeOf(object):用于判断当前对象是否为另一个对象的原型。(第 8 章将详细介绍 原型。)
- propertyIsEnumerable(propertyName):用于判断给定的属性是否可以使用(本章稍后讨 论的)for-in 语句枚举。与 hasOwnProperty()一样,属性名必须是字符串。
- toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
- toString():返回对象的字符串表示。
- valueOf():返回对象对应的字符串、数值或布尔值表示。通常与 toString()的返回值相同。
OK,写到这里,关于类型就暂时不继续展开了;
然后,书行文来到了:操作符,一元操作符、位操作符等等,一共有 11 个,讲的比较详细。
重点嘛,个人认为有: x 和 x 问题、位操作、解构赋值这些;
然后,行文来到:语句, if、for、while、switch,和 C 基本一致啦
最后讲到:函数, 这是我们感兴趣的。函数对任何语言来说都是核心组件,因为它们可以封装语句,然后在任何地方、任何时间执行。
ECMAScript 使用 function 关键字声明函数。神奇的是,ECMAScript 中的函数不需要指定是否返回值,也就是没有强制 return 也可以;
本瓜认为,没有强制 return , 会给我们代码的可读性造成困扰。
比如:
代码语言:javascript复制let sum1,sum2,sum3
function sum(){
sum1 = xx
sum2 = sum1 xx
sum3 = sum2 * 2 xxx
sum1 = xxx
}
函数内部对函数外部的变量做了多次修改。实际代码中,没有通过函数 return 修改外部变量的情况,比这个要复杂很多很多。一定会给变量的改动的溯源造成困扰。
如果我们强制用return,只用 return 修改外部变量,那它是这样的:
代码语言:javascript复制function sum(){
let tmp1,tmp2,tmp3
tmp1= xx
tmp2= sum1 xx
tmp3= sum2 * 2 xxx
tmp1= xxx
return [tmp1,tmp2,tmp3]
}
let [sum1,sum2,sum3] = sum()
我们可以清晰地去查询,这个函数对于外部数据到底做了什么,看 return 就可以了。
小结
第三章,关于基础语法!!就这么多了,相对于前两章,内容已经多了很多,后面也会更加精细,复杂,但是基本把要点都标粗了,然后附加了自己的一点体会。
OK,以上便是本篇分享。 觉得不错点个赞吧