浅习一波JavaScript高级程序设计(第4版)p3

2022-09-19 10:46:12 浏览数 (1)


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 数据类型:

  1. "undefined"表示值未定义;
  2. "boolean"表示值为布尔值;
  3. "string"表示值为字符串;
  4. "number"表示值为数值;
  5. "object"表示值为对象(而不是函数)或 null;
  6. "function"表示值为函数;
  7. "symbol"表示值为符号。

变量值可以用 typeof 来检查,结果就是以上 7 种的任一一种;

老前端知道 typeof 来检查类型是远不够的,它不能检查出 array、正则、内置对象等,会将它们都返回为 Object

这个时候,就需要用到:

Object.prototype.toString.call()

代码语言:javascript复制
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 有的属性,基本的类型也有,这些属性是:

  1. constructor:用于创建当前对象的函数。在前面的例子中,这个属性的值就是 Object() 函数。
  2. hasOwnProperty(propertyName):用于判断当前对象实例(不是原型)上是否存在给定的属 性。要检查的属性名必须是字符串(如 o.hasOwnProperty("name"))或符号。
  3. isPrototypeOf(object):用于判断当前对象是否为另一个对象的原型。(第 8 章将详细介绍 原型。)
  4. propertyIsEnumerable(propertyName):用于判断给定的属性是否可以使用(本章稍后讨 论的)for-in 语句枚举。与 hasOwnProperty()一样,属性名必须是字符串。
  5. toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
  6. toString():返回对象的字符串表示。
  7. 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,以上便是本篇分享。 觉得不错点个赞吧

0 人点赞