2

前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。

前言BB

放开我,我又要吐槽了。看到这个题目的时候,我十分的头秃。
那么我为什么头秃呢?

  1. ECMAScript 6(ES2015) 做了大量的更新。
    那么多的更新我那说的完ECMAScript 6 入门 - 阮一峰,这里发一下学习链接,只能说大佬牛逼。
  2. 2015 年 6 月正式发布。
    现在来说都四年过去了。其实大多数人都掌握了。
  3. 其实还有一个误区不是ES5的都归ES6
    其实想想挺逗的。为什么会有这样一个误区?ES2015出来的时候浏览器厂商支持就不一样,ES2016出来之后支持还是不一样,ES2017、ES2018、ES2019 都是这样。这就出现了一个问题,发布是发布了,但是啥时候支持就不一定了
    这里放出来我前两天才看的文章,他们的更新速度是真的恐怖。

    1. 从 JavaScript、ES6、ES7 到 ES10,你学到哪儿了? - 疯狂的技术宅
    2. 盘点ES7、ES8、ES9、ES10新特性 - 浪里行舟

提案流程

从提案到正式标准,需要经历五个阶段。每个阶段的变动都需要由 TC39 委员会批准。

  1. Stage 0 - Strawman(展示阶段)
    有人提出的想法(任何人都可以向 TC39 委员会提案,要求修改语言标准)
  2. Stage 1 - Proposal(征求意见阶段)
    想法公布,进行审查与讨论
  3. Stage 2 - Draft(草案阶段)
    想法完善,初始规范
  4. Stage 3 - Candidate(候选人阶段)
    确定要做,完成规范并在浏览器上初步实现。
  5. Stage 4 - Finished(定案阶段)
    到达这里基本就可以在浏览器用了。将添加到下一个年度版本发布中。IE什么的你就不要和我提了

当前的所有提案,可以在 TC39 的官方网站查看

Babel 是什么?

Babel 是一个 JavaScript 编译器。将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。下面列出的是 Babel 能做的事情:

  • 语法转换
  • 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过@babel/polyfill模块)
  • 源码转换 (codemods)

配置文件 .babelrc

{
  // presets字段设定转码规则
  "presets": ["es2015", "react", "stage-2"],
  // 插件
  "plugins": ["transform-decorators-legacy", "transform-class-properties"]
}

执行顺序

  • plugins 在 Presets 前运行。
  • plugins 顺序是从前往后(transform-decorators-legacy、ransform-class-properties)。
  • Preset 顺序是从后往前(stage-2、react、es2015)。

官方预设

官方已经针对常用环境编写了一些 preset:

polyfill

Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API,比如 IteratorGeneratorSetMapProxyReflectSymbolPromise 等全局对象,以及一些定义在全局对象上的方法(比如Object.assignArray.includes)都不会转码。

所以我们还需要使用 babel-polyfill

ES6

后面的东西其实看不看无所谓,想要学习呢,还是看阮一峰大佬的好了。
我这里说一下我认为ES6更新了一些什么东西。

  1. 标准化(国际化、unicode、规范化、健壮性、跨平台)
  2. 功能方法(之前用奇奇怪怪的方法实现的功能,这次官方给你了)
  3. 便捷(脚本语言玩的就是骚气)

let、const、块级作用域、暂时性死区

在之前没有块级作用域的概念(try{}catch(e){} 可以模拟,性能呵呵呵呵)。这次加入了块级作用域的概念,let 变量,const 常量。

// 输出什么?
for(var i = 0; i<4;i++){};
i // 4
// 输出什么?
for(let i1 = 0; i1<4;i1++){};
i1 //Uncaught ReferenceError: i1 is not defined

变量提升与暂时性死区

大家都知道面试的时候,喜欢搞一些花里胡哨的鬼东西。
提升是说,var 会被提升到最前面执行,所以不会出现i is not defined
死区是说,let 定义的变量,不能在声明前使用。

(function(){
    console.log(1, i) //1 4 
    //4来源于上面的测试例子,不然会是下面这个鬼样子
    //Uncaught ReferenceError: i is not defined
})();
(function(){
    console.log(2, i)
    var i  = 'lilnong.top' //2 undefined
})();
(function(){
    console.log(3, i)
    let i = 'lilnong.top' // Uncaught ReferenceError: Cannot access 'i' before initialization
})();

globalThis

  • 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window
  • 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self
  • Node 里面,顶层对象是global,但其他环境都不支持。

所以提供了一个访问顶层对象的属性。

解构、默认值

  1. 数组解构赋值 let [a, b, c] = [1, 2, 3];
  2. 对象解构赋值 let { foo, bar } = { foo: 'aaa', bar: 'bbb' }
  3. 字符串解构赋值 const [a, b, c, d, e] = 'hello'
  4. 函数参数的解构赋值(这个比较常用)

    axios('https://www.lilnong.top/cors/axios-destructuring')
    .then(({data})=>console.log(data))
    // y取默认值,然后入参第一个的默认值是{}
    function move({x = 0, y = 0} = {}) {
      return [x, y];
    }
    
    move({x: 3, y: 8}); // [3, 8]
    move({x: 3}); // [3, 0]
    move({}); // [0, 0]
    move(); // [0, 0]
    // y没有默认值,第一个入参的默认值是{ x: 0, y: 0 }
    function move({x, y} = { x: 0, y: 0 }) {
      return [x, y];
    }
    
    move({x: 3, y: 8}); // [3, 8]
    move({x: 3}); // [3, undefined]
    move({}); // [undefined, undefined]
    move(); // [0, 0]

字符串的扩展、模板字符串、unicode

字符串扩展

只能说写起来更爽了。然后就是之前的写法其实不是很好。会浪费空间,效率不高。
${Math.random()}-${Date.now()}-lilnong.top

unicode 更好的支持、codePointAt、fromCodePoint、normalize

面向国际化,以及 emoji。JavaScript 内部,字符以 UTF-16 的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符。

这里有个小插曲,weex 中 Text 组件无法包含 Image 组件,实现流式排列。(富文本组件好像是可以解决)

在实现这个功能的时候,我想到可以把字变成块,然后flex 允许换行。
测试地址,里面用了两种方案来获取大于Oxffff的字符。

  1. for of
  2. codePointAt 判断大于0xFFFF,需要跳字节。charCodeAt是ES5就支持的,只能拿到小于OxFFFF

更多的API

includes、startsWith、endsWith、repeat、padStart、padEnd、trimStart、trimEnd、matchAll
随着原生提供的 API 越来越多,我们慢慢的不需要使用 Loadsh 等工具库。

正则表达式的扩展、断言、unicode

后行断言

JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先行否定断言(negative lookahead),不支持后行断言(lookbehind)和后行否定断言(negative lookbehind)。ES2018 引入后行断言,V8 引擎 4.9 版(Chrome 62)已经支持。
“先行断言”指的是,x只有在y前面才匹配,必须写成/x(?=y)/。比如,只匹配百分号之前的数字,要写成/\d+(?=%)/。“先行否定断言”指的是,x只有不在y前面才匹配,必须写成/x(?!y)/。比如,只匹配不在百分号之前的数字,要写成/\d+(?!%)/
ECMAScript 6 入门 - 后行断言 - 阮一峰

数值的扩展、API、指数运算符

更多的API Number.isFinite()、Number.isNaN()、Number.parseInt()、Number.parseFloat()、Number.isInteger()、Number.isSafeInteger()、Number.EPSILON、Number.isSafeInteger()

函数的扩展、默认值、rest参数、箭头函数、尾调用优化

尾调用优化

我们知道,函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到AB的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。
递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。

rest参数

(()=>arguments)(1,2,3) // 输出什么?Uncaught ReferenceError: arguments is not defined

在兼容函数中arguments无法使用

((...args)=>args)(1,2,3) //有输出什么?[1, 2, 3]

我们可以使用...来把入参收集起来

((a,...args)=>args)(1,2,3) //[2, 3]

甚至我们前面用变量接收,后面整体用...接收

箭头函数

  1. this 指向定义时所在的对象
  2. 不可以使用 arguments 对象

数组的扩展、展开运算符、API、空位的处理

展开

举一个例子你就知道了。去重,虽然这个方法有局限性吧。
[...new Set([12, 2, 3, 12, 31, 2, 11, 2, 1, 2, 1, 21, 1, 2, 3, 1, 23, 12, 3, 12, 31, 11, 1, 2, 2, 31, 2, 3])]

数组的API

Array.from()、Array.of()、Array.prototype.copyWithin()、Array.prototype.find()、Array.prototype.findIndex()、Array.prototype.fill()、Array.prototype.entries()、Array.prototype.keys()、Array.prototype.values()、Array.prototype.includes()、Array.prototype.flat()、Array.prototype.flatMap()、

nodeList = document.querySelectorAll('div');
// ES5的写法
[].slice.call(nodeList);
// ES6的写法
Array.from(nodeList);

对象的扩展、缩写、变量名表达式、展开运算符、API

变量名表达式

当我看到下面的写法的时候,内心是卧槽的。

GET_USER_INFO = 'getBaseUserInfo'
obj = {
    [GET_USER_INFO](){// 第一次看到是vuex里面分开定义获取数据
        console.log(arguments)
    },
    'abc.sdf'(){// vue watch监听改变的时候
        console.log(arguments)
    }
}

image.png

API

Object.is()、Object.assign()、Object.getOwnPropertyDescriptors()、Object.setPrototypeOf()、Object.getPrototypeOf()、Object.keys()、Object.values()、Object.entries()、Object.fromEntries()

新的类型、新的全局对象

Symbol、Set、Map、Proxy、Reflect、Promise、Iterator、Generator、async、Class、Module
简直了。太多了

微信公众号:前端linong

clipboard.png

参考文献

  1. 前端培训目录、前端培训规划、前端培训计划

linong
29.2k 声望9.5k 粉丝

Read-Search-Ask