1、var 、let 和 const
var 、let 、const常见区别如下:
1. 变量挂载在 window
var 声明的变量会挂载在 window 上,而 let 和 const 声明的变量不会
var a = 100;
console.log(a, window.a); // 100 100
let b = 10;
console.log(b, window.b); // 10 undefined
const c = 1;
console.log(c, window.c); // 1 undefined
2. 变量提升
var 声明变量存在变量提升,let 和 const 不存在变量提升
console.log(a); // undefined ===> a已声明还没赋值,默认得到undefined值
var a = 100;
console.log(b); // 报错:b is not defined ===> 找不到b这个变量
let b = 10;
console.log(c); // 报错:c is not defined ===> 找不到c这个变量
const c = 10;
3、块作用域
let 和 const 声明形成块作用域
if(1) {
var a = 100;
let b = 10;
const c = 1;
}
console.log(a); // 100
console.log(b) // 报错:b is not defined ===> 找不到b这个变量
console.log(c) // 报错:c is not defined ===> 找不到c这个变量
4、重复声明同一个变量
同一作用域下 let 和 const 不能声明同名变量,而 var 可以
var a = 100;
console.log(a); // 100
var a = 10;
console.log(a); // 10
let a = 100;
let a = 10;
// 控制台报错:Identifier 'a' has already been declared ===> 标识符a已经被声明了。
5、暂存死区
var a = 100;
if(1){
a = 10;
//在当前块作用域中存在 a 使用 let/const 声明的情况下,给 a 赋值 10 时,
只会在当前作用域找变量a,
// 而这时,还未到声明时候,所以控制台 Error:a is not defined
let a = 1;
}
6、const
- 一旦声明必须赋值,不能使用 null 占位。
- 声明后不能再修改
- 如果声明的是复合类型数据,可以修改其属性或 Object.preventExtensions(阻止扩展)
const a = 100;
const list = [];
list[0] = 10;
console.log(list); // [10]
const obj = {a:100};
obj.name = 'apple';
obj.a = 10000;
console.log(obj); // {a:10000,name:'apple'}
如果声明的是复合型数据,不让其修改,可以使用 冻结对象 Object.freeze(obj) , 禁止为对象修改已存在的属性和方法。所有字段均只读。被冻结的对象也是不可扩展和密封的。
const info = { name: 'xxl' };
Object.freeze(info);
info.phone = '12345678';
console.log(info); // { name: 'xxl' } phone 属性没加成功
2、箭头函数
1. 箭头函数和普通函数的区别
-
箭头函数没有 this,函数内部的 this 来自于父级最近的非箭头函数,并且不能改变 this 的指向。
const obj = { name: 'John', regularFunction: function() { console.log(this.name); }, arrowFunction: () => { console.log(this.name); } }; obj.regularFunction(); // 输出: John objarrowFunction(); // 输出: undefined,因为箭头函数的 this 指向全局对象(在浏览器中是 window) // 尝试改变箭头函数的 this 指向 const newObj = { name: 'Jane' }; const arrow = obj.arrowFunction.bind(newObj); arrow(); // 仍然输出: undefined,说明不能改变箭头函数的 this 指向 -
箭头函数没有 super
super关键字用于访问和调用一个对象的父对象上的函数。由于箭头函数没有自己的this和原型链, 所以它没有super。 -
箭头函数没有 arguments
// `arguments` 对象是一个类数组对象,它包含了函数调用时传递的所有参数。 // 箭头函数没有自己的 `arguments` 对象,它会继承外层函数的 `arguments` 对象。 function regular() { const arrow = () => { console.log(arguments[0]); }; arrow(); } regular(1, 2, 3); // 输出: 1 -
箭头函数没有 new.target 绑定。
new.target是一个元属性,在构造函数中使用时,它指向被调用的构造函数。由于箭头函数不能使用new来调用,所以它没有new.target绑定。 -
箭头函数不能使用 new
箭头函数不能使用
new关键字来创建对象实例,因为它没有自己的this和prototype。const Arrow = () => {}; try { const instance = new Arrow(); // 抛出 TypeError } catch (error) { console.error(error.message); // 输出: Arrow is not a constructor } -
箭头函数没有原型
每个函数都有一个
prototype属性,用于实现原型继承。箭头函数没有prototype属性。const arrow = () => {}; console.log(arrow.prototype); // 输出: undefined -
箭头函数不支持重复的命名参数。
在严格模式下,普通函数和箭头函数都不允许有重复的命名参数。
// 严格模式 'use strict'; // 普通函数 function regular(a, a) { console.log(a); } // 会抛出 SyntaxError: Duplicate parameter name not allowed in this context // 箭头函数 const arrow = (a, a) => { console.log(a); }; // 会抛出 SyntaxError: Duplicate parameter name not allowed in this context
2. 箭头函数作用域
传统 function 函数的 this 指向在函数调用的时候决定,a 调用指向 a,b 调用指向 b
箭头函数不是在调用的时候决定this,而是在箭头函数 申明 的时候,就指定了this,指向上层 父作用域 的this,如果父作用域没有this,则依次往上
window下 申明,window下调用func
let c = {a:123}
window.a = 321
// func 在 window 下申明,this 指向父作用域 this,window
let func = () => { console.log(this.a) }
c.b = function(){
func()
}
c.b() //321
再次强调 箭头函数的 this 在箭头函数申明时就已经绑定到内部,不会被外部影响改变, call 和 apply 方法对箭头函数无效
window.a = 312
let func = () => {
console.log(this.a)
}
let c = {
a:123,
func
}
func() // 312
c.func() // 312
func.apply(c) //312
func.call(c) //312
3、函数参数默认值
在ES6之前,如果我们写函数需要定义初始值的时候,需要这么写:
function config (data) {
var data = data || 'data is empty'
}
这样看起来也没有问题,但是如果参数的布尔值为 false 时就会出问题, 例如我们这样调用 config:
config(0) 或 config('') 那么结果就永远是后面的值
如果我们用函数参数默认值就没有这个问题,写法如下:
const config = (data = 'data is empty') => {}
3、模板字符串 ${name}
在ES6之前,如果我们要拼接字符串,则需要像这样:
var name = 'kris'
var age = 24
var info = 'My name is ' + this.name + ', I am ' + this.age
但是在ES6之后,我们只需要写成以下形式:(用反引号包含内容、用 ${} 引用数据)
const name = 'kris'
const age = 24
const info = `My name is ${name}, I am ${age}`
4、扩展操作符 ...
a. 二维数组转一维数组
var middle = [3, 4];
var arr = [1, 2, ...middle, 5, 6];
console.log(arr); // [1, 2, 3, 4, 5, 6]
b. 复制数组
arr 数组中的元素扩展成为单独元素被分配到 arr2 中。现在可以随意改变 arr2 数组,且都不会对源数组 arr 产生影响
这是因为,arr 数组值被扩展后添加到 arr2 数组中,我们设置 arr2 等于 arr 的值,而不是其本身。我们可以关注没有扩展运算符时发生事情,就能理解了。
var arr = [ 'a', 'b', 'c'];
var arr2 = [...arr];
console.log(arr2); // [ 'a', 'b', 'c']
arr2.push('8')
console.log(arr) // [ 'a', 'b', 'c']
console.log(arr2) // [ 'a', 'b', 'c', '8']
c. 拼接数组
使用扩展运算符可以代替 concat() 来拼接数组。
# concat() 来拼接数组
var arr = [‘a’, ‘b’, ‘c’];
var arr2 = [‘d’, ‘e’, ‘f’];
arr1 = arr.concat(arr2);
console.log(arr); // [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
# 使用扩展运算符
var arr = [‘a’, ‘b’, ‘c’];
var arr2 = [‘d’, ‘e’, ‘f’];
arr = [...arr, ...arr2];
console.log(arr); // [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
d. Math
也可以使用 math 函数连同扩展运算符。如这个例子中,将使用 Math.max()
Math.max()将返回一组数最大值。
Math.max(); // -Infinity
Math.max(1, 2, 3); // 3
Math.max(100, 3, 4); // 100
扩展运算符做同样事情
var arr = [2, 4, 8, 6, 0];
var max = Math.max(...arr);
console.log(max); // 8
e. 字符串转数组
使用扩展运算符将字符串转换为数组。
var str = “hello”;
var chars = […str];
console.log(chars); // [‘h’, ‘e’,’ l’,’ l’, ‘o’]
5、对象属性简写
但是在ES6里我们就方便很多:
let cat = 'Miaow'
let dog = 'Woof'
let bird = 'Peet peet'
let someObject = {
cat,
dog,
bird
}
console.log(someObject) //{ cat: "Miaow",dog: "Woof", bird: "Peet peet"}
6、Symbol
symbol 是一种基本数据类型,Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。
它的静态属性会暴露几个内建的成员对象;
它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:“new Symbol()”。
每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。
例子如下:
const symbol1 = Symbol();
const symbol2 = Symbol(42);
const symbol3 = Symbol('foo');
console.log(typeof symbol1); // "symbol"
console.log(symbol3.toString()); // "Symbol(foo)"
console.log(Symbol('foo') === Symbol('foo')); // false
8、Set
a. 理解Set
- Set 本身是一个构造函数,用来生成 Set 数据结构。
- 它类似于数组,但里面的成员是唯一的,不重复的。
- 向 Set 加入值时,不会发生类型转换,它类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为 NaN 等于自身,而精确相等运算符认为 NaN 不等于自身。
- Set 可以接收一个数组做为参数,用来初始化
b. set 数组去重
const arr = new Set([1, 1, '2', 2, 3, 4, 5])
console.log(arr) // [ 1, '2', 2, 3, 4, 5]
c. set 字符串去重
let str = 'sssuuunnn'
let res = [...new Set(str)].join('')
console.log(res) // sun
d. set 实例的属性
属性
size: size 属性表示 set 集合中有多少个元素
new Set([1, 2]).size // 2
e. set 实例的方法
方法
# add(value):添加某个值,返回Set结构本身
const arr = new Set()
arr.add(1).add(2).add('zs')
console.log(arr)
# delete(value):删除某个值,返回一个布尔值表示是否删除成功
const arr = new Set([1, 2, 3, 'zs'])
var a = arr.delete('zs')
console.log(a)
console.log(arr)
# has(value):返回一个布尔值,表示参数是否为Set的成员
const arr = new Set([1, 2, 3, 'zs'])
var a = arr.has('zs')
console.log(a)
#clear():清除所有成员,没有返回值
const arr = new Set([1, 2, 3, 'zs'])
var a = arr.clear('zs')
console.log(arr)
f. set 的遍历方法 for ... of ...
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
for…of…
let setArr = new Set([1, 6, 6, 'sun', {name: 'sun'}])
for(let item of setArr.keys()) {
console.log(item);
// 1 6 sun {name: 'sun'}
}
for(let item of setArr.values()) {
console.log(item);
// 1 6 sun {name: 'sun'}
}
for(let item of setArr.entries()) {
console.log(item);
// [1, 1] [6, 6] [sun, sun] [{name: 'sun'}, {name: 'sun'}]
}
for(let item of setArr) {
console.log(item);
// 1 6 sun {name: 'sun'}
}
g. set 实例循环遍历总结
set 生成的 数据结构 不能用 for 循环遍历
let arr = ['好好', '恩恩', '哦哦', '吃饭饭', '睡觉觉', '亲亲']
let arr1 = new Set(arr)
console.log(arr1.size);
for (var i = 0; i < arr1.size; i++) {
console.log(arr1[i].value)
}
报错:
# index.html:29 Uncaught TypeError: Cannot read property 'value' of undefined
set 生成的数据结构能用 forEach 循环遍历
let arr = ['好好', '恩恩', '哦哦', '吃饭饭', '睡觉觉', '亲亲']
let arr1 = new Set(arr)
arr1.forEach(item => console.log(item))
// 好好, 恩恩, 哦哦, 吃饭饭, 睡觉觉, 亲亲
set 生成的数据结构能用 for of 循环遍历
let arr = ['好好', '恩恩', '哦哦', '吃饭饭', '睡觉觉', '亲亲']
let arr1 = new Set(arr)
for (let i of arr1.keys()) {
console.log(i) // 好好, 恩恩, 哦哦, 吃饭饭, 睡觉觉, 亲亲
}
7、模块化(Module)
在ES6之前,JS并没有模块化的概念,有的也只是社区定制的类似CommonJS和AMD之类的规则。例如基于CommonJS的NodeJS:
// circle.js
// 输出
const { PI } = Math
exports.area = (r) => PI * r ** 2
exports.circumference = (r) => 2 * PI * r
// index.js
// 输入
const circle = require('./circle.js')
console.log(`半径为 4 的圆的面积是 ${circle.area(4)}`)
在ES6之后我们则可以写成以下形式:
/ circle.js
// 输出
const { PI } = Math
export const area = (r) => PI * r ** 2
export const circumference = (r) => 2 * PI * r
// index.js
// 输入
import {area} = './circle.js'
console.log(`半径为 4 的圆的面积是: ${area(4)}`)
14、Proxy/Reflect
Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 Proxy 的方法相同。Reflect不是一个函数对象,因此它是不可构造的。
Proxy跟Reflect是非常完美的配合,例子如下:
const observe = (data, callback) => {
return new Proxy(data, {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, value, proxy) {
callback(key, value);
target[key] = value;
return Reflect.set(target, key, value, proxy)
}
})
}
const FooBar = { open: false };
const FooBarObserver = observe(FooBar, (property, value) => {
property === 'open' && value
? console.log('FooBar is open!!!')
: console.log('keep waiting');
});
console.log(FooBarObserver.open) // false
FooBarObserver.open = true // FooBar is open!!!
当然也不是什么都可以被代理的,如果对象带有configurable: false 跟writable: false 属性,则代理失效。
16、Math对象的扩展
•二进制表示法 : 0b或0B开头表示二进制(0bXX或0BXX)
•二进制表示法 : 0b或0B开头表示二进制(0bXX或0BXX)
•八进制表示法 : 0o或0O开头表示二进制(0oXX或0OXX)
•Number.EPSILON : 数值最小精度
•Number.MIN_SAFE_INTEGER : 最小安全数值(-2^53)
•Number.MAX_SAFE_INTEGER : 最大安全数值(2^53)
•Number.parseInt() : 返回转换值的整数部分
•Number.parseFloat() : 返回转换值的浮点数部分
•Number.isFinite() : 是否为有限数值
•Number.isNaN() : 是否为NaN
•Number.isInteger() : 是否为整数
•Number.isSafeInteger() : 是否在数值安全范围内
•Math.trunc() : 返回数值整数部分
•Math.sign() : 返回数值类型(正数1、负数-1、零0)
•Math.cbrt() : 返回数值立方根
•Math.clz32() : 返回数值的32位无符号整数形式
•Math.imul() : 返回两个数值相乘
•Math.fround() : 返回数值的32位单精度浮点数形式
•Math.hypot() : 返回所有数值平方和的平方根
•Math.expm1() : 返回e^n - 1
•Math.log1p() : 返回1 + n的自然对数(Math.log(1 + n))
•Math.log10() : 返回以10为底的n的对数
•Math.log2() : 返回以2为底的n的对数
•Math.sinh() : 返回n的双曲正弦
•Math.cosh() : 返回n的双曲余弦
•Math.tanh() : 返回n的双曲正切
•Math.asinh() : 返回n的反双曲正弦
•Math.acosh() : 返回n的反双曲余弦
•Math.atanh() : 返回n的反双曲正切
17、for …of
for…of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
例子如下:
const array1 = ['a', 'b', 'c'];
for (const element of array1) {
console.log(element)
}
// "a"
// "b"
// "c"
18、Promise
19. es6 map 与 原生对象区别
区别 object 和 Map 存储的都是键值对组合。但是:
object 的键的类型是 字符串;
map 的键的类型是 可以是任意类型;
另外注意,object 获取键值使用Object.keys(返回数组) ;
Map 获取键值使用 map变量.keys() (返回迭代器) 。
示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>js es6 map 与 原生对象区别</title>
</head>
<body>
<script type="text/javascript">
let a = {
o: 1
};
// string
console.log(typeof Object.keys(a)[0]);
let map = new Map();
map.set(a, 'content');
// 输出是object 也可以是任何类型
console.log(map.keys().next());
</script>
</body>
</html>
6、解构赋值 [ ]
JS 的解构赋值是 ES6 新增的一种赋值方法,一般分为对象解构与数组解构两种形式;
a. 对象解构赋值
对象解构赋值 : 对象按照属性解构赋值,对象的属性没有次序,变量必须与属性同名,才能取到正确的值
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
details: {
nickName: "光脚丫思考",
address: "中国北京",
signature: "勿以善小而不为,勿以恶小而为之"
}
}
const { userName, blog, details: { signature } } = user;
console.info(userName); // 光脚丫思考
console.info(blog); // https://blog.csdn.net/gjysk
console.info(signature); // 勿以善小而不为,勿以恶小而为之
更深入的对象嵌套, 深层次的嵌套的对象也是可以通过解构赋值来获取属性值的,再深层次的也是可以正常获取的
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
details: {
nickName: "光脚丫思考",
address: {
domicileAddress: "户籍地",
abodePlace: "居住地"
},
signature: "勿以善小而不为,勿以恶小而为之"
}
}
const { userName, blog, details: { signature, address: { domicileAddress, abodePlace } } } = user;
console.info(userName); // 光脚丫思考
console.info(blog); // https://blog.csdn.net/gjysk
console.info(signature); // 勿以善小而不为,勿以恶小而为之
console.info(domicileAddress); // 户籍地
console.info(abodePlace); // 居住地
b. 设置默认值
在某种特殊或意外的情况下,比如后端写接口的大侠忘记返回这个状态的值了,除了让后端的大侠正确的补充上这个状态值以外,我们还可以给它设置一个默认值,比如默认值离线状态 offline。代码如下:
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
status: undefined
}
const { userName, blog, status = "offline" } = user;
console.info(userName); // 光脚丫思考
console.info(blog); // https://blog.csdn.net/gjysk
console.info(status); // offline
另外一种情况就是直接就没有这个属性,缺少这个属性,设置默认值的办法同样好使,示例代码如下:
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
}
const { userName, blog, status = "offline" } = user;
console.info(userName); // 光脚丫思考
console.info(blog); // https://blog.csdn.net/gjysk
console.info(status); // offline
无论是返回的属性值为undefined,还是直接把这个属性值干没了,解构赋值设置的默认值都很好使
在使用默认值的时候,应该注意区分 undefined 和 null,只有 undefined 的时候才会使用设置的默认值,null 是不会使用默认值的。可以看到address使用的是设置的默认值,而signature的值则继续保留为null了。如下代码所示:
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
address: undefined,
signature: null,
}
const { userName, blog, address = "中国北京", signature = "默认签名信息" } = user;
console.info(`userName=${userName}`); // userName=光脚丫思考
console.info(`blog=${blog}`); // blog=https://blog.csdn.net/gjysk
console.info(`address=${address}`); // address=中国北京
console.info(`signature=${signature}`); // signature=null
c. 使用别名
另外一个使用解构赋值必须得面临的一个问题:变量命名冲突的问题,该如何解决呢?
前面的那些示例代码中,解构赋值中的变量名和对象中的属性名是完全一致的,如果已经定义了同名的变量该怎么办呢?岂不是会发生命名冲突的情况。此时,使用别名就能很好的解决这个问题了。示例代码如下:
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
}
const { userName: name, blog: url } = user;
console.info(name);
console.info(url);
d. 定义新变量
解构赋值还可以基于对象的属性值创建新的变量,还是先来看一个示例:
const user = {
userName: "光脚丫思考",
blog: "https",
}
const { userName, blog, message = `我是${userName},我的博客地址是:${blog}` } = user;
console.info(userName); // 光脚丫思考
console.info(blog); // https
console.info(message); // 我是光脚丫思考,我的博客地址是:https
请留意上面的代码,解构赋值中的 message 变量并非 user 对象的某个属性名称,而是由变量 userName 和 blog 拼接到一起的字符串变量。
需要特别强调一点的是,新定义的变量 message 中使用到的 userName 和 blog 并非user 中的属性名,而是解构赋值中定义的 userName 和 blog,这 2 个变量接收了 user 对象中同名的属性值。
因此,如果我们把解构赋值中的 userName 和 blog 移除掉的话,代码就废掉了。
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
}
const { message = `我是${userName},我的博客地址是:${blog}` } = user;
console.info(message); // Uncaught ReferenceError: userName is not defined
如果使用别名的方式就能更加说明这一点了。下面的代码中,新定义的变量 message 中拼接的变量名称就是别名,而并非 user 对象中的属性名,表明它所使用的是解构赋值中定义的变量名,而并非对象中的属性名。
const user = {
userName: "光脚丫思考",
blog: "https:/",
}
const { userName: name, blog: url, message = `我是${name},我的博客地址是:${url}` } = user;
console.info(name); // 光脚丫思考
console.info(url); // https:/
console.info(message); // 我是光脚丫思考,我的博客地址是:https:/
e. 动态名称属性
在实际的开发过程中,我们通常会通过接口API来获取数据,而这些数据不仅仅内容是动态的,甚至对象的属性键名也是动态的,再或者我们一开始连属性的名称都可能不知道。这样的属性值要如何获取呢?如果不使用解构赋值,可以通过下标[]的方式来获取属性值,那解构赋值又是如何做到的呢?请看示例。
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
};
function getValue(data, key) {
const { [key]: value } = data;
return value;
}
let userName = getValue(user, "userName");
let blog = getValue(user, "blog");
console.info(userName);
console.info(blog);
可以看到,解构赋值代码也是通过下标[]的方式来获取对象的属性值的,下标中 key 的内容就是属性的名称。
f. 函数中的解构赋值
aa. 解构赋值传参
使用对象解构赋值将属性值作为参数传递给函数。
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
};
function display({userName, blog}) {
let message = `大家好,我是${userName},我的博客地址是:${blog}`;
console.info(message);
}
display(user);
bb. 解构赋值返回结果
如果函数返回一个对象,可以将属性值直接解构为变量,如下代码所示:
function getUSer() {
const user = {
userName: "光脚丫思考",
blog: "https://blog.csdn.net/gjysk",
};
return user;
}
const { userName, blog } = getUSer();
let message = `大家好,我是${userName},我的博客地址是:${blog}`;
console.info(message);
g. 循环中的解构赋值
接下来我们再看看在循环中如何使用解构赋值。示例代码如下:
代码中,我们在 for 循环的内部使用了解构赋值语法,成功的从每个 user 对象中获取到了 userName 和 blog 的数据。
let users = [
{
userName: "光脚丫思考1",
blog: "https://blog.csdn.net/gjysk",
},
{
userName: "光脚丫思考2",
blog: "https://blog.csdn.net/gjysk",
},
{
userName: "光脚丫思考3",
blog: "https://blog.csdn.net/gjysk",
},
];
for (user of users) {
const { userName, blog } = user;
let message = `大家好,我是${userName},我的博客地址是:${blog}`;
console.info(message);
}
也算是最基本的玩法了,下面的方式则更加的简洁一些。
在 for 循环的 {} 中不包含解构赋值的代码,而是直接放到了 () 中,输出的结果和前面的代码是一样的。
for ({ userName, blog } of users) {
let message = `大家好,我是${userName},我的博客地址是:${blog}`;
console.info(message);
}
h. 数组结构赋值
数组按照顺序解构赋值, 先来看一个简单的数组解构赋值的代码,如下:
let [a, b] = [1, 2];
console.info(a); // 1
console.info(b); // 2
就像上面的示例一样,数组解构赋值的过程中,只要把每个解构的部分一一对应起来,就可以层层解构赋值。比如下面的代码:
请留意[b]这个语句,它对应的是实际数组中的[2,3],因此这个语法解析的便是[2,3]中的元素,因此获得的应该是2这个数值,如下图所示:可以看到这次的变量b输出的就是[2,3]这个数组了。
let [a, [b], d] = [1, [2, 3], 4];
console.info(a); // 1
console.info(b); // 2
console.info(d); // 4
我们把上述的代码稍微做点改变,输出的结果就会大不一样。代码如下:
let [a, b, d] = [1, [2, 3], 4];
console.info(a); // 1
console.info(b); // [2, 3]
console.info(d); // 4
I. 字符串解构
// 当作数组结构
var [q,w] = '12'; // q 1; w 2
// 当作对象结构
var { length}= '12';// length 2
j. 解构规则
ES6的解构赋值遵循一个规则:要左右两边的模式相同,就可以进行合法赋值。如下面的示例代码:
let [a, b, c] = [1, 2, 3];
let [d, [[e], f]] = [1, [[2], 3]];
如果解构不成功,变量值等于undefined,比如下面的代码:
let [a, b] = [1];
console.info(a); // 1
console.info(b); // undefined