[ES6 系列] 你真的了解ES6吗(一)
前言
无论是我们日常开发还是面试跳坑, ES6
已经变得越来越重要,那么你是否对它足够熟悉呢
ES6
将会是专栏接下来的一个系列,从最基础的概念或者有趣的问题开始逐渐深入,探究 ES6
常用的特性以及实际开发中遇到的问题。有些问题可能会比较奇葩,工作中根本不会写出这样的代码,但正是这些问题可以看出你的了解程度
本文的 答案
不一定是最优解释,如果你有更好的想法或更优雅的写法,欢迎留言讨论
如果文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过
以下↓
正文
- 下面代码会打印什么
function bar(x = y, y = 2) {
return [x, y];
}
bar();
复制代码
答案
报错
y
在没赋值之前使用,隐藏的 暂时性死区
暂时性死区的本质:只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
- 下面代码会打印什么
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,所以就导致了错误
}())
复制代码
- 以下代码为什么会报错
let { prop: x } = undefined;
let { prop: y } = null;
复制代码
答案
解构赋值的规则是:只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefined
和 null
无法转为对象,所以对它们进行解构赋值,都会报错
- 如何交换下面的两个变量(至少写出三种)
let a = 'abc'
let b = 'xyz'
复制代码
答案
- 解构赋值
[a, b] = [b, a]
复制代码
- 变成一个对象
a = {a: b, b: a}
b = a.b
a = a.a
复制代码
- 变成一个数组
a = [a, b]
b = a[0]
a = a[1]
复制代码
- 比较骚的方式
a = [b, b = a][0]
复制代码
……
- 下面两种写法有什么不同
// 写法一
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]
复制代码
- 下面的代码输出什么
(function (a, b, c = 5) { }.length
(function (a, ...b) { }).length)
复制代码
答案
2 1
函数参数的默认值以及 reset
参数 不计算在函数的 length
当中
- 下面的代码输出什么
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
,作用域问题
- 下面的代码输出什么
const cat = {
lives: 9,
jumps: () => {
console.log(this)
}
}
cat.jumps()
复制代码
答案
this
指向全局
- 箭头函数没有
this
- 对象不能构成单独的作用域
所以上面代码中的 this
是指向全局的
isNaN()
与Number.isNaN
有什么区别
答案
都可以用来检查一个值是否为 NaN
区别是 Number.isNaN()
不会对值进行转换,如果值不是 Number
类型,就直接返回 false
isNaN(123) // false
Number.isNaN(123) // false
isNaN(NaN) // true
Number.isNaN(NaN) // true
isNaN('abc') // true
Number.isNaN('abc') // false
复制代码
Array.from
与 拓展运算符…
有什么区别
答案
两者都可以将某些数据结构转换为数组
扩展运算符 背后调用的是遍历器接口(Symbol.iterator
),如果一个对象没有部署这个接口,就无法转换
它的主要使用场景包括函数调用、复制、合并数组以及结合解构赋值生成新的数组等
Array.from
方法还支持类似数组的对象(任何有 length
属性的对象,都可以通过 Array.from
方法转为数组,而此时扩展运算符就无法转换)
它的使用场景主要是将两类对象转换为真正的数组:类似数组的对象和可遍历(
iterable
)的对象(包括ES6
新增的数据结构Set
和Map
)
另外,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]
复制代码
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)
- 对
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
会直接返回该参数 - 如果该参数不是对象,则会先转成对象,然后返回
undefined
和null
无法转成对象,所以如果它们作为参数,就会报错.但是如果undefined
和null
不在首参数,就不会报错
Object.assign(undefined) // 报错
Object.assign(null) // 报错
Object.assign({}, undefined) // {}
Object.assign({}, null) // {}
复制代码
更多用法,可参考阮大大的作品 ECMAScript 6 入门
参考
后记
作者:游荡de蝌蚪
链接:https://juejin.im/post/5de8c565f265da33de3a678c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
[ES6 系列] 你真的了解ES6吗(一)的更多相关文章
- [js高手之路] es6系列教程 - 对象功能扩展详解
第一:字面量对象的方法,支持缩写形式 //es6之前,这么写 var User = { name : 'ghostwu', showName : function(){ return this.nam ...
- [js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解
接着上文[js高手之路] es6系列教程 - 迭代器与生成器详解继续. 在es6中引入了一个新的循环结构for ....of, 主要是用来循环可迭代的对象,那么什么是可迭代的对象呢? 可迭代的对象一般 ...
- ES6 系列之 Babel 是如何编译 Class 的(下)
前言 ES5 寄生组合式继承 function Parent (name) { this.name = name; } Parent.prototype.getName = function () { ...
- webpack4 系列教程(二): 编译 ES6
今天介绍webpack怎么编译ES6的各种函数和语法.敲黑板:这是webpack4版本哦, 有一些不同于webpack3的地方. >>> 本节课源码 >>> 所有课 ...
- 大白话,讲编程之《ES6系列连载》汇总
如果你经历过2,3年前的前端开发,你一定感受过兼容IE6,7的痛苦,一定用过网页三剑客的dreamweaver编写html,面试的时候面试官一定会问你:会用PS切图吗? 刚开始的时候你发现,web前端 ...
- es6系列-变量声明
es6系列所有文章都是阅读阮一峰老师的<ES6标准入门>(第2版)所做的读书笔记.方便日后查阅相关基础知识. git地址: https://github.com/rainnaZR/es6- ...
- ES6 系列之异步处理实战
前言 我们以查找指定目录下的最大文件为例,感受从 回调函数 -> Promise -> Generator -> Async 异步处理方式的改变. API 介绍 为了实现这个功能,我 ...
- [ES6系列-01]Class:面向对象的“新仇旧恨”
[原创]CoderPower 大家好,这里是码路工人有力量,我是码路工人,你们是力量. 这是公众号(码路工人有力量)开通后的第二篇,写得还是有待改进吧.这次准备写一个关于ES6基础的短文系列,努力尽快 ...
- ES6系列之项目中常用的新特性
ES6系列之项目中常用的新特性 ES6常用特性 平时项目开发中灵活运用ES6+语法可以让开发者减少很多开发时间,提高工作效率.ES6版本提供了很多新的特性,接下来我列举项目中常用的ES6+的特性: l ...
随机推荐
- FFmpeg常用命令学习笔记(三)分解/复用命令
分解/复用命令 比如文件格式的转换.将封装格式文件中的音频与视频文件分别抽取出来等. 多媒体格式的转换(将MP4文件转成flv格式) ffmpeg -i yan.mp4 -vcodec copy -a ...
- echarts自定义折线图横坐标时间间隔踩坑总结
折线图需求:横坐标为时间,要求按一定间隔展示,鼠标移至折线上间隔时间内的数据也可展示 其实很简单的一个配置就可搞定,但在不熟悉echarts配置的情况下,就很懵逼 xAxis: { boundaryG ...
- Filter和interceptor比较
作为一个备忘,有时间补充 https://www.cnblogs.com/learnhow/p/5694876.html 先说一个题外话,Filter是过滤器,interceptor是拦截器.前者基于 ...
- Linux防CC攻击脚本
多数CC攻击在web服务器日志中都有相同攻击的特征,我们可以根据这些特征过滤出攻击的ip,利用iptables来阻止 #!/bin/bash #by LinuxEye #BLOG: http://bl ...
- jsp前台输入框不输入值,后台怎么取出整型?
当前台输入框限定整型,后台取值就会出现很多问题. eg: Integer.parseInt(request.getParameter("uno"));当前台的文本框不输入值,直接点 ...
- 题解 [CF525D] Arthur and Walls
题面 解析 首先考虑将一个\('*'\)变成\('.'\)后会形成什么, 显然至少是一个\(2\times 2\)的矩形. 因为\(1\times 1\)和\(1\times 2\)的改了没用啊, 而 ...
- 题解 [51nod1274] 最长递增路径
题面 解析 这题一眼DP啊. 然而想了半天毫无思路. 后来看题解后发现可以按边权的大小顺序DP. 将边权从小到大排序,对于权值相同的边分为一组. 设\(f[i][0]\)表示经过当前权值的边后到达\( ...
- ...cURL error 60: SSL certificate problem: unable to get local issuer certificate...
问题描述: 在做PHP爬虫的时候, 安装了 guzzle 和 dom-crawler 之后, 调用的时候出现问题, 如下 报错内容: Fatal error: Uncaught GuzzleHttp ...
- neo4j 一些常用的CQL
创建节点.关系 创建节点(小明):create (n:people{name:’小明’,age:’18’,sex:’男’}) return n; 创建节点(小红): create (n:people{ ...
- PHP 根据两个坐标计算距离 圆形围栏的计算
可以应用于圆形电子围栏入 出围栏计算 圆形电子围栏的计算方式是: 根据圆心坐标和当前检查的坐标进行距离计算,如果距离长度超出围栏的半径,则判定为出围栏,反之是在围栏之内 <?php /** * ...