ES6汇总(附加面试考点,冷知识点)————关于严谨性汇总(共2900+字)

前言

文章为个人原创手写,内容参考部分书籍(《深入理解ES6》)与博客(阮一峰),个人的汇总与总结。
如有不对,希望指出。

话题 链接
es6严谨性 https://juejin.im/post/5eea3020f265da02ab172265
es6简洁性 https://juejin.im/post/5ef0116df265da02ba14e261
es6原对象方法的扩展 正在更新中
es6新概念的引入 正在更新中

ES6简介

ES6,全称ECMAScript 2015,于2015年发布,成为新一代前端标准。值得一提的是,当前的浏览器并不兼容ES6语法。我们需要借助Babel去编译。

ES6的重点

本人把ES6的改革从性质上分成四个部分,包括严谨性,简洁性,原对象方法的扩展,以及新概念的引入

本文重点___严谨性

前端严谨性从发展角度越来越强。如后期的typescript更加明显,由”弱语言“,逐步发展为常规语言。ES6的更加严谨,可以从以下几点进行分析。

块级作用域

我们都知道,变量声明(var)会有变量提升。这里的变量会提前初始化,也可以提前访问。当项目变量复杂的时候,很容易产生bug。es6就在这个时候,引入了let跟const。它解决了下边的问题:

1)局部作用域
新引入的let,const声明,再不会再产生变量提升。避免了变量提前访问的场景,间接的提高了严谨性。我们可以在程序运行时就知道了报错,而非后期的调试中。案例如下

alert("a=" + a);//此时a为underfined,因为变量a已提前声明,但还未赋值
alert("b=" + b);//此时程序已抛出异常,因为此时未找到变量b
var a = 1;
let b = 2;

2)禁止重复声明
如果一个标识符已经在代码块内部被定义,那么在此代码块内使用同一个标识符进行 let 声明就会导致抛出错误。

3)区分常量与变量
这是let与const的区别。const 声明会阻止对于变量绑定与变量自身值的修改,避免了我们日常开发中,了不小心改到常量的问题。

4)暂时性死区
用案例理解该概念。
for( var i = 0; i<10; i++ ){
setTimeOut( function(){
alert(i );
}, 1000);
}

for( let i = 0; i<10; i++ ){
    setTimeOut( function(){
        alert(i );
    }, 1000);
}

通过案例你可以发现,用var声明的,会受setTimeOut所影响,
而let的没有影响。可以说明let有暂时性死区。

冷知识

在 for-in与 for-of 循环中, let 与 const 都能在每一次迭代时创建一个新的绑定,这意味着在循
环体内创建的函数可以使用当前迭代所绑定的循环变量值
(而不是像使用 var 那样,统一使用循环结束时的变量值)。
这一点在 for 循环中使用 let 声明时也成立,不过在 for 循
环中使用 const 声明则会导致错误。

面试考点

简述var,let,const之间的区别?

参考答案:可参考上述解释几个要点。作用域,禁止声明重复,区分常量与变量,暂时性死区。

需要理解,什么是变量作用域的提升。


怎么解决for循环延迟打印?如下案例,怎么让输出正确的结果?
for( var i = 0; i<10; i++ ){
    setTimeOut( function(){
        alert(i );
    }, 1000);
}

参考答案:1.let声明 2.利用闭包 3.立即执行函数

module模块化

为什么要模块化?
在以前,js一直没有模块化的体系。这就会产生一个问题,当项目到达大型时,很大可能性出现方法重叠,以及安全性问题,成为大型项目的一个痛点与障碍。而es6模块化正式为此诞生。

冷知识

关于es6模块化的冷知识:
  1. 模块代码自动运行在严格模式下,并且没有任何办法跳出严格模式
  2. 在模块的顶级作用域创建的变量,不会被自动添加到共享的全局作用域,它们只会在模块顶级作用域的内部存在;
  3. 模块顶级作用域的 this 值为 undefined ;
  4. 模块不允许在代码中使用 HTML 风格的注释(这是 JS 来自于早期浏览器的历史遗留特
    性);
  5. 对于需要让模块外部代码访问的内容,模块必须导出它们;
  6. 允许模块从其他模块导入绑定。
  7. 模块化可以用as重命名导出

面试考点

模块化引入,跟常规js引入方法有什么不同?

参考答案:

常规js引入,script标签src为"text/javascript"。
而如果你想直接引入模块化js,则src="module"。
可能看到这里,你会反驳,react跟vue打包编译后,
他们模块化后的代码引入的script标签,
为什么没有用到src="module",
那是因为人家已经经过webpack编译后,
已经把你的模块化代码,打包成一个全局js文件中。

Web 浏览器中的模块加载顺序是怎么样的?

参考答案:

1)当使用模块加载的时候,浏览器立即开始下载模块文件,但并不会执行它,
直到整个网页文档全部解析完为止。
(默认是defer,可以了解一下defer跟async的区别)
2)模块执行的代码,是由上往下的,如果中间包含内联模块,则会优先执行内链模块

在es6模块化之前,你还知道那些前端模块化?他们之间有什么区别?

参考答案:

在es6模块化之前,社区还出现了一些模块化的方法,
例如commonJS 和 AMD 。此外还有CMD。
下边我们简述一下他们的概念与区别。

1)AMD, commonJS, 与es6,都属于预加载类型。而后期引入的CDM是懒加载。
    何为预加载, 也就是说,在程序调用,所有的模块都加载完成。
    而懒加载,是用到什么的时候,才去加载什么。
2)AMD跟cmd专注于前端的规范。而commonjs跟es6 moudle可用于前后端。
3)AMD的代表做为requirejs,cmd的代表作为seajs。commonjs 与 es6,则无需引入,
    只需要引入编译器(如babel)即可。 seajs为淘宝引入的规范,我们都知道淘宝相对很大,
    不采用懒加载,首屏的时间将会很长,不过现在已经停止维护。
4)es6 跟 commonJS做了如下改变:
 1.ES6只能新增值,无法重新赋值就会报错
 2.CommonJS 输出是值的拷贝,即原来模块中的值改变不会影响已经加载的该值,
    ES6静态分析,动态引用,输出的是值的引用,值改变,引用也改变
    ,即原来模块中的值改变则该加载的值也改变。
 3.CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
 4.CommonJS 加载的是整个模块,即将所有的接口全部加载进来,
   ES6 可以单独加载其中的某个接口(方法)。
 5.CommonJS this 指向当前模块,ES6 this指向undefined

Symbol

Symbol个人也觉得是提高我们项目严谨性的方法之一。
它用于创建不可枚举的属性,并且这些属性在不引用符号的情况下是无法访问的。
只有在访问属性的时候用[]方法才能正确访问,这算不算大大提高了我们程序的严谨性呢?

首先我们理解一下声明是Symbol。Symbol是JS新引入的基本类型。我们都知道在ES5之前,JS 已有的基本类型(字符串、数值、布尔类型、 null 与 undefined )之外, ES6 引入
了一种新的基本类型。

思考一下,为什么要引入这个Symbol呢?

符号起初被设计用于创建对象私有成员,而这也
是 JS 开发者期待已久的特性。
在符号诞生之前,将字符串作为属性名称导致属性可以被轻易
访问,无论命名规则如何。
而“私有名称”意味着开发者可以创建非字符串类型的属性名称,由
此可以防止使用常规手段来探查这些名称。

看到这里,我们结合官方文档。列举一下Symbol常规作用。

应用场景

1.作为内置属性名称

可观察如下案例:

let name = Symbol();
let student = {};
person[name] = "weizhan";
console.log(person[name]); // "weizhan"

此代码创建了一个符号类型的 name 变量,并将它作为 student 对象的一个属性,而每
次访问该属性都要使用这个符号值。
为符号变量适当命名是个好主意,这样你就可以很容易地说明它的含义。

它的好处就是可以避免同参数名的覆盖。从这点,提高了程序的严谨性你是否赞同?因为每一个Symbol都独立存在,及时程序重名了,它也不会覆盖。我们可以通过变量获取它曾经覆过的值。

Symbol 作为对象的属性名,可以保证属性不重名。
用Symbol只能用个[]去访问,没有其他方式可以进行访问。

2.使用Symbol来替代常量

我们可以利用Symbol来创建一些常量。比如订单状态等。

const ORDER_RETRUN = Symbol();//订单退货状态
const ORDER_SUCCESS = Symbol();订单成功状态
const ORDER_PAY = Symbol();//订单支付状态

这一点更体现出程序的简洁性(下文)。如果没有Symbol。
我们只能这样去声明。

const ORDER_RETRUN = "RETRUN";//订单退货状态
const ORDER_SUCCESS = "SUCCESS";订单成功状态
const ORDER_PAY = "PAY";//订单支付状态

我们如果需要保证每个状态都为独立存在,则要保证“RETRUN”,“SUCCESS”,“PAY”不一致。假设出现手误
const ORDER_SUCCESS = “SUCCESS”;
const ORDER_PAY = “SUCCESS”;
两者值都为SUCCESS时,两个状态ORDER_SUCCESS跟ORDER_PAY则相等。跟我们原来的单一状态设计相违背。而用Symbol()可直接获取独一无二的值。

看到这里,是否觉得Symbol提高了严谨性。

冷知识点:

关于Symbol的一些额外api,笔者个人是不建议深入的。本文只是列举,有兴趣可自行查询。

Symbol.hasInstance :供 instanceof 运算符使用的一个方法,用于判断对象继承关
系。
Symbol.isConcatSpreadable :一个布尔类型值,在集合对象作为参数传递给
Array.prototype.concat() 方法时,指示是否要将该集合的元素扁平化。
Symbol.iterator :返回迭代器(参阅第七章)的一个方法。
Symbol.match :供 String.prototype.match() 函数使用的一个方法,用于比较字符串。
Symbol.replace :供 String.prototype.replace() 函数使用的一个方法,用于替换子字
符串。
Symbol.search :供 String.prototype.search() 函数使用的一个方法,用于定位子字符
第六章 符号与符号属性
108
串。
Symbol.species :用于产生派生对象(参阅第八章)的构造器。
Symbol.split :供 String.prototype.split() 函数使用的一个方法,用于分割字符串。
Symbol.toPrimitive :返回对象所对应的基本类型值的一个方法。
Symbol.toStringTag :供 String.prototype.toString() 函数使用的一个方法,用于创建
对象的描述信息。
Symbol.unscopables :一个对象,该对象的属性指示了哪些属性名不允许被包含在
with 语句中。

面试考点

怎么访问到Symbol的值?

Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。
但是不会出现在 for...in 、 for...of 的循环中
,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 返回。
如果要读取到一个对象的 Symbol 属性,
可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。

Array

假设需要创建一个数组,传统的new Array(2);第一个参数,可能为数组长度,也可能是第一个参数值。
设计上没有问题,但是程序中容易出现疏忽造成bug。

如果是克隆多一个数组呢?

而新引入数组方法,array.of跟array.form正是解决该问题。array详细部分,会在第三篇文章具体列出。

es6严谨性 : https://juejin.im/post/5eea3020f265da02ab172265

es6简洁性 : https://juejin.im/post/5ef0116df265da02ba14e261

es6原对象方法的扩展: https://juejin.im/post/5ef0116df265da02ba14e261

es6新概念的引入: 正在更新中

友情提示

该文章已结束,下一篇文章,关于es6简洁性汇总,主要知识点包括:
字符串模版,箭头函数,class的引入,解构函数的引入,js原型扩展等。

https://juejin.im/post/5ef0116df265da02ba14e261

你可能感兴趣的:(javascript,前端)