[ES6 系列] 你真的了解ES6吗(一)

前言

无论是我们日常开发还是面试跳坑, ES6 已经变得越来越重要,那么你是否对它足够熟悉呢

ES6 将会是专栏接下来的一个系列,从最基础的概念或者有趣的问题开始逐渐深入,探究 ES6 常用的特性以及实际开发中遇到的问题。有些问题可能会比较奇葩,工作中根本不会写出这样的代码,但正是这些问题可以看出你的了解程度

本文的 答案 不一定是最优解释,如果你有更好的想法或更优雅的写法,欢迎留言讨论

如果文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过

以下↓

正文

  1. 下面代码会打印什么
function bar(x = y, y = 2) {  return [x, y];}

bar();复制代码

答案

报错

y 在没赋值之前使用,隐藏的 暂时性死区

暂时性死区的本质:只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量


  1. 下面代码会打印什么
function f() { console.log(‘I am outside!‘) }

(function () {    if (false) {        function f() { console.log(‘I am inside!‘) }    }    f();}());复制代码

答案

ES5 的执行环境(比如 IE8 ),会打印 I am inside,执行方式类似下面这样

function f() { console.log(‘I am outside!‘) }

(function () {    function f() { console.log(‘I am inside!‘) }    if (false) {}    f();}())复制代码

ES6 的执行环境会报错.这是因为在 ES6 环境中,if 语句这里形成了块级作用域,在块级作用域中的函数声明类似使用 var 声明一个变量,只会将声明提升到所在作用域头部。所以,执行方式就类似下面这样

function f() { console.log(‘I am outside!‘) }

(function () {    var f;    if (false) {        function f() { console.log(‘I am inside!‘) }    }    f(); // 由于 f 是 undefined,所以就导致了错误}())复制代码

  1. 以下代码为什么会报错
let { prop: x } = undefined;let { prop: y } = null;复制代码

答案

解构赋值的规则是:只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefinednull 无法转为对象,所以对它们进行解构赋值,都会报错


  1. 如何交换下面的两个变量(至少写出三种)
let a = ‘abc‘let b = ‘xyz‘复制代码

答案

  • 解构赋值
[a, b] = [b, a]复制代码
  • 变成一个对象
a = {a: b, b: a}b = a.ba = a.a复制代码
  • 变成一个数组
a = [a, b]b = a[0]a = a[1]复制代码
  • 比较骚的方式
a = [b, b = a][0]复制代码

……


  1. 下面两种写法有什么不同
// 写法一function m1({x = 0, y = 0} = {}) {  return [x, y];}

// 写法二function m2({x, y} = { x: 0, y: 0 }) {  return [x, y];}复制代码

答案

上面的两种写法都对函数的参数设定了默认值

区别是 写法一函数参数的默认值是空对象,但是设置了对象解构赋值的默认值;写法二函数参数的默认值是一个具体的对象,但是没有设置对象解构赋值的默认值

测试方式:

// 函数没有参数的情况m1() // [0, 0]m2() // [0, 0]

// x 和 y 都有值的情况m1({x: 3, y: 8}) // [3, 8]m2({x: 3, y: 8}) // [3, 8]

// x 有值,y 无值的情况m1({x: 3}) // [3, 0]m2({x: 3}) // [3, undefined]

// x 和 y 都无值的情况m1({}) // [0, 0];m2({}) // [undefined, undefined]

m1({z: 3}) // [0, 0]m2({ z: 3 }) // [undefined, undefined]复制代码

  1. 下面的代码输出什么
(function (a, b, c = 5) { }.length

(function (a, ...b) { }).length) 复制代码

答案

2 1

函数参数的默认值以及 reset 参数 不计算在函数的 length 当中


  1. 下面的代码输出什么
var x = 1;function foo(x, y = function() { x = 2; }) {  var x = 3;  y();  console.log(x);}

foo() console.log(x)复制代码

答案

3 1

  • 函数参数和函数内部是两个不同的作用域
  • 函数执行的时候,先执行函数参数,然后再执行函数体

正是由于它们是不同的作用域,而且在函数体中使用 var 重新声明了变量,所以后面的打印结果就是 3;如果没有使用 var 声明,而是直接这样 x = 3 ,那么最终的打印结果就是 2

x 的打印结果是 1,作用域问题


  1. 下面的代码输出什么
const cat = {    lives: 9,    jumps: () => {        console.log(this)    }}cat.jumps() 复制代码

答案

this 指向全局

  • 箭头函数没有 this
  • 对象不能构成单独的作用域

所以上面代码中的 this 是指向全局的


  1. isNaN()Number.isNaN 有什么区别

答案

都可以用来检查一个值是否为 NaN

区别是 Number.isNaN() 不会对值进行转换,如果值不是 Number 类型,就直接返回 false

isNaN(123)  // falseNumber.isNaN(123) // false

isNaN(NaN) // trueNumber.isNaN(NaN) // true

isNaN(‘abc‘) // trueNumber.isNaN(‘abc‘) // false复制代码

  1. Array.from 与 拓展运算符有什么区别

答案

两者都可以将某些数据结构转换为数组

扩展运算符 背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换

它的主要使用场景包括函数调用、复制、合并数组以及结合解构赋值生成新的数组等

Array.from 方法还支持类似数组的对象(任何有 length 属性的对象,都可以通过 Array.from 方法转为数组,而此时扩展运算符就无法转换)

它的使用场景主要是将两类对象转换为真正的数组:类似数组的对象和可遍历(iterable)的对象(包括 ES6 新增的数据结构 SetMap

另外,Array.from 还接收第二个参数,类似于 map 操作

let obj = {length: 3}

Array.from(obj) // [undefined, undefined, undefined][...obj] // 报错:object is not iterable复制代码
let arr = [1, 2, 3]

add(...arr) // 相当于 add(1, 2, 3)Array.from(arr, v=> v * 2) // [2, 4, 6]复制代码

  1. super 关键字的了解

答案

super 有两种使用方式

作为对象时:在普通方法中,指向父类的原型对象。表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错

const proto = {  foo: ‘hello‘};

const obj = {  foo: ‘world‘,  find() {    return super.foo;  }};

Object.setPrototypeOf(obj, proto); // 指定原型对象obj.find() // "hello"复制代码

作为函数调用时:代表父类的构造函数,只能用在子类的构造函数之中,用在其他地方就会报错

class 继承时,我们需要手动指定子类的 constructor ,这时候 super 就派上了用场

class A {}

class B extends A {  constructor() {    super();  }}复制代码

ES6 规定,子类的构造函数必须执行一次 super 函数

super 代表了父类 A 的构造函数,返回的是子类 B 的实例,即 super 内部的 this 指的是 B 的实例,因此 super() 在这里相当于 A.prototype.constructor.call(this)


  1. Object.assign() 的了解

答案

Object.assign 方法用于对象的合并,将源对象(scource)的所有可枚举属性,复制到目标对象(target)

Object.assign(target, source1, source2)复制代码

特点:

  • 浅拷贝
  • 拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性
  • 只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制
const source = {  get foo() { return 1 }};const target = {};

Object.assign(target, source) // { foo: 1 }复制代码
  • 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性
let obj = {a: 1, b: 2}let obj1 = {a: 10}

Object.assign(obj, obj1) // {a: 10, b: 2}复制代码
  • 如果只有一个参数,Object.assign 会直接返回该参数
  • 如果该参数不是对象,则会先转成对象,然后返回
  • undefinednull 无法转成对象,所以如果它们作为参数,就会报错.但是如果 undefinednull 不在首参数,就不会报错
Object.assign(undefined) // 报错Object.assign(null) // 报错

Object.assign({}, undefined) // {}Object.assign({}, null) // {}复制代码

更多用法,可参考阮大大的作品 ECMAScript 6 入门

参考

ECMAScript 6 入门

MDN

后记

作者:游荡de蝌蚪
链接:https://juejin.im/post/5de8c565f265da33de3a678c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原文地址:https://www.cnblogs.com/yizijianxin/p/12000265.html

时间: 2024-10-27 04:54:11

[ES6 系列] 你真的了解ES6吗(一)的相关文章

【ES6系列】一、ES6简介

说明 本系列是笔记,参考以下两个网站,本系列的其他笔记中将不再说明 [1] http://es6.ruanyifeng.com/ [2] https://developer.mozilla.org/zh-CN/ 如果想学习javascript或es6,推荐到以上两个网站学习 诞生 2015年6月17日,ECMAScript的第六个版本正式发布,该版本正式名称为ECMAScript 2015,但通常被称为ECMAScript 6或者ES6. 对ES6的支持 浏览器对ES6的支持情况 Node.js

[js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解

接着上文[js高手之路] es6系列教程 - 迭代器与生成器详解继续. 在es6中引入了一个新的循环结构for ....of, 主要是用来循环可迭代的对象,那么什么是可迭代的对象呢? 可迭代的对象一般都有Symbol.iterator属性,你可以在控制台中用console.dir打印数组,Map,Set,在他们的原型对象(prototype)上面就能找到.这个属性与迭代器密切相关,通过该函数可以返回一个迭代器,下文,我会举一个例子.一般来说所有的集合对象(数组,Set,Map 以及字符串)都是可

ES6 系列之异步处理实战

前言 我们以查找指定目录下的最大文件为例,感受从 回调函数 -> Promise -> Generator -> Async 异步处理方式的改变. API 介绍 为了实现这个功能,我们需要用到几个 Nodejs 的 API,所以我们来简单介绍一下. fs.readdir readdir 方法用于读取目录,返回一个包含文件和目录的数组. fs.stat stat 方法的参数是一个文件或目录,它产生一个对象,该对象包含了该文件或目录的具体信息.此外,该对象还有一个 isFile() 方法可以

[ES6系列-04]再也不乱“哇”了:用 let 与 const 替代 var

[原创]码路工人 Coder-Power 大家好,这里是码路工人有力量,我是码路工人,你们是力量. github-pages 博客园cnblogs 今天的内容是,关于 JavaScript 中定义变量的变化(其实不确切,函数,常量表示被冷落). 首先,回顾下 var 定义存在的问题 1. 哇..var 好乱.. 1.1 可以重复定义 /* eg.0 * multi-definition of var-variable */ //----------------------------------

[ES6系列-07]Generator Function: 生成器函数

[原创]码路工人 Coder-Power 大家好,这里是码路工人有力量,我是码路工人,你们是力量. github-pages 博客园cnblogs Generator function 生成器函数是ES6中新增的语法糖,本质上讲,就是以封装成一个遍历器的形式,让编码的你获得程序的执行控制权,通俗地说就是,流程控制上,踹一脚,走一步,不要太暴力~ 0.前言 要说到生成器函数,就不得不提到javascript的异步编程方式演进史. (不能跑题不能跑题不能跑题) 1.普通的回调函数方式(callbac

深入解析 ES6 系列(一)

简介 欢迎来到深度探索 ES6!在这个新的周系列里,我们将探索 ECMAScript 6.这是一种 JavaScript 语言即将到来的新版本.ES6 包含了很多新的语言功能,且这些语言功能使得 JS 更加强大更富有表现力.在接下来的几周时间里,我们将会一个一个地了解这些新功能.但是在我们了解细节的东西之前,我们值得花一点时间来讨论一下什么是 ES6 以及你期望能得到什么. ECMAScript 的范围是什么? JavaScript 编程语言是由 ECMAScript 名下的 ECMA 进行标准

深入解读ES6系列(二)

ES6函数 哈喽小伙伴们,爱说'废'话的Z又回来了,欢迎来到Super IT曾的博客时间,上一节说了es6的历史,变量,以及闭包,这一节我们继续我们知识的海洋,一起奋斗不秃头!不足的欢迎提问留言. 今天一打开CSDN有被惊喜到哈哈被选热门超开心!看来要加更才行,当然注重基础是必须的!那我们继续~ 箭头函数 总结起来箭头函数也就那么回事儿,说白了就两点: 如果只有一个参数,()可以省. 如果只有一个return,{} 可以省. 好了,箭头函数说完了,我们说下一个...??,开个玩笑,哈哈,上实例:

[js高手之路] es6系列教程 - new.target属性与es5改造es6的类语法

es5的构造函数前面如果不用new调用,this指向window,对象的属性就得不到值了,所以以前我们都要在构造函数中通过判断this是否使用了new关键字来确保普通的函数调用方式都能让对象复制到属性 1 function Person( uName ){ 2 if ( this instanceof Person ) { 3 this.userName = uName; 4 }else { 5 return new Person( uName ); 6 } 7 } 8 Person.proto

ES6系列四 函数的扩展

一丶ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面. function log(x, y = 'World') { console.log(x, y); } log('Hello') // Hello World log('Hello', 'China') // Hello China log('Hello', '') // Hello 二丶与解构赋值结合 function fetch(url, { body = '', method = 'GET', headers = {} }