{
// 用变量做对象的键
let a = 'c'
let obj = {
[a]: 'b'
}
console.log(obj)// {c: "b"}
}
{
let obj = {a: 1, b: 2}
console.log(Object.keys(obj))// ["a", "b"]
console.log(Object.values(obj))// [1, 2]
console.log(Object.entries(obj))// [["a", 1], ["b", 2]]
for(let [a, b] of Object.entries(obj)) {
console.log(a, b)// a 1 b 2
}
}
{
// 使用元素填充空数组
console.log(new Array(5).fill(0))// [0, 0, 0, 0, 0]
}
{
function foo(a, b, c) {
let argu = Array.from(arguments)// 将伪数组转换成数组(另外:[].slice.call(arguments)和[...arguments]也可以转换)
argu.forEach((val, key) => {
console.log(val)// 4 5 6
})
}
foo(4, 5, 6)
}
{
let arr = [4, 5, 6]
arr = arr.map((val, key) => {// 映射的使用
return val * 2
})
console.log(arr)// [8, 10, 12]
}
{
let arr = [4, 5, 6],
findVal = arr.find((val) => {// 寻找val大于4的值
return val > 4
}),
findIndex = arr.findIndex((val) => {// 寻找val大于4的值的下标
return val > 4
})
console.log(findVal, findIndex)// 5 1
}
{
// 在数组中寻找是否存在此值
let arr = [4, 5, 6]
console.log(arr.includes(5))// true
}
{
let a = 1,
d = 4
function fun(a, b = a, c = d) {// 注意作用域的范围
console.log(a, b, c)// 2 2 4
}
fun(2)
}
{
// 0b开头用来表示一个二进制数
console.log(0b101)// 5
// 0o开头用来表示一个八进制数
console.log(0o101)// 65
}
{
// 判断一个数、字符串是负数、零、正数还是非数字
console.log(Math.sign(-5))// -1
console.log(Math.sign(0))// 0
console.log(Math.sign(5))// 1
console.log(Math.sign('-5'))// -1
console.log(Math.sign('hvb'))// NaN
}
{
// 求3次立方根
console.log(Math.cbrt(8))// 2
}
{
let str = 'logo.png',
a = str.includes('go'),// str是否包含'go'字符串
b = str.startsWith('lo'),// str是否以'lo'字符串开头
c = str.endsWith('.png')// str是否以'.png'字符串结尾
console.log(a, b, c)// true true true
}
{
let str = 'abc',
str2 = str.repeat(2)// 重复str字符串2次
console.log(str2)// abcabc
}
{
let str = '1',
a = str.padStart(2, '0')// 当str的长度不足2时,在前面自动补'0'
b = str.padEnd(2, '0')// 当str的长度不足2时,在后面自动补'0'
console.log(a, b)// 01 10
}
{
let month = `${(``+(new Date().getMonth()+1)).padStart(2, `0`)}月`// 获取当前月份,不足2位数时,自动补0
console.log(month)
}
{
// 数组解构
let a, b, rest
[a, b, c=3, ...rest] = [1, 2, 4, 5, 6]
console.log(a, b, c, rest)// 1 2 4 [5, 6]
}
{
// 对象解构
let a, b
({a, b: c} = {a: 1, b: 2})
console.log(a, b, c)// 1 undefined 2
}
{
let data = {
name: 'hvb',
course: [
{ title: 'chinese', score: 90 },
{ title: 'english', score: 80 }
]
}
for (let i = 0; i < data.course.length; i++) {
let { [i]: { title, score } } = data.course// 通过i来定位当前要解构的是数组的哪一项
console.log(title, score)// chinese 90 english 80
}
}
{
// 实现2个值的互换
let a = 1,
b = 2;
[a, b] = [b, a]
console.log(a, b)// 2 1
}
{
// 通过解构函数的参数方便赋值
function foo({a, b=2}) {
console.log(a, b)// 1 2
}
foo({a: 1})
}
// 检查参数是否必填
function check() {
throw new Error('该参数必填')
}
function foo(a=check(), b=2) {
console.log(a + b)
}
foo(1)// 3
foo()// 抛出错误
块级作用域易犯错误
// 使用var声明变量
var funArr = []
for(var i=0; i<2; i++) {// var声明变量使i变量提升且由于循环,最终会变成2
funArr.push(function() {// 这里添加到数组中的匿名函数在执行的时候,拿到的i是变量提升的那个值
console.log(i)
})
}
funArr[0]()// 2
funArr[1]()// 2
// 使用let声明变量
let funArr2 = []
for(let j=0; j<2; j++) {// let声明变量,会在每次循环中都创建一个块作用域,这个块作用域中的i每次都能确定
funArr2.push(function() {// 这里添加到数组中的匿名函数在执行的时候,拿到的i是当前块作用域中的i
console.log(j)
})
}
funArr2[0]()// 0
funArr2[1]()// 1
es6中可以直接使用{}创建一个块级作用域
{
let a = 1
console.log(a)// 1
{
let a = 2
console.log(a)// 2
}
}
{
let a = Symbol()
let b = Symbol()
let c = Symbol.for('e')// 用'e'来标记这个独一无二的值
let d = Symbol.for('e')
console.log(a==b, c==d)// false true
}
{
// 用Symbol做的键不会重复
let a = Symbol.for('abc')
let obj = {
[a]: 1,
abc: 2
}
console.log(obj)// {abc: 2, Symbol(abc): 1}
// 直接遍历obj无法得到Symbol类型的键
for(let key in obj) {
console.log(key)// abc
}
let symbol = Object.getOwnPropertySymbols(obj)// 通过这个方法只可以拿到Symbol数组,然后可以正常遍历
console.log(symbol)// [Symbol(abc)]
let all = Reflect.ownKeys(obj)// 通过这个方法可以拿到既包含普通的键又包含Symbol键的数组,然后可以正常遍历
console.log(all)// ["abc", Symbol(abc)]
}
{
// 声明时直接传入数组,用来生成组员
let a = new Set([1, 2])
// 通过add添加组员
a.add(3)
console.log(a)// Set(3) {1, 2, 3}
// 通过has验证是否含有此组员
console.log(a.has(2))// true
// 通过delete删除组员
a.delete(1)
console.log(a)// Set(2) {2, 3}
// 通过clear清空组员
a.clear()
console.log(a)// Set(0) {}
// 实例:数组去重
let arr = [1, 2, 3, 1]
let res = [...new Set(arr)]
console.log(res)// [1, 2, 3]
}
{
// 声明时直接传入二维数组,用来生成组员
let a = new Map([[1, 2], [3, 4]])
// 通过set添加组员
a.set('a', 'b')
console.log(a)// Map(3) {1 => 2, 3 => 4, "a" => "b"}
console.log(a.get(1))// 2
// 通过has验证是否含有此组员
console.log(a.has(3))// true
}
{
// obj set map作对比
let item = {a: 1},// 缓存的对象
obj = {},// 空对象(用来对比)
set = new Set(),// 空set(用来对比)
map = new Map()// 空map(用来对比)
// 添加一个组员
obj.a = 1
set.add(item)
map.set('a', 1)
console.log(obj, set, map)// {a: 1} Set(1) {Object {a: 1}} Map(1) {"a" => 1}
// 查看一个组员
console.log('a' in obj, set.has(item), map.has('a'))// true true true
// 修改一个组员
obj.a = 2
item.a = 2
map.set('a', 2)
console.log(obj, set, map)// {a: 2} Set(1) {Object {a: 2}} Map(1) {"a" => 2}
// 删除一个组员
delete obj.a
set.delete(item)
map.delete('a')
console.log(obj, set, map)// {} Set(0) {} Map(0) {}
// 由此可看,map和set的操作比较方便,所以建议在开发过程中,优先使用map数据结构,如果数据要求唯一性,那么使用set,放弃使用传统的数组和对象
}
{
let obj = {a: 1}
console.log(Reflect.get(obj, 'a'))// 1
Reflect.set(obj, 'a', 2)
console.log(obj)// {a: 2}
console.log(Reflect.has(obj, 'a'))// true
}
简单示例
// 原对象
let Person = {
name: 'hvb',
sex: 'male'
}
// 代理对象
let person = new Proxy(Person, {
get(target, key) {
return Reflect.get(target, key)// target[key]
},
set(target, key, value) {
if(key == 'sex') {
throw new Error('性别不允许修改')
}else {
return Reflect.set(target, key, value)
}
}
})
person.name = 'hwj'
console.log(person.name)// hwj
person.sex = 'female'// 抛出错误
通过对象代理给类属性增加验证规则
// 创建验证代理
function createValidator(target, rule) {
return new Proxy(target, {
set(target, key, value) {
if(rule[key]) {
if(rule[key].validate(value)) {
return Reflect.set(target, key, value)
}else {
throw new Error(rule[key].message(key, value))
}
}else {
throw new Error(`属性${key}不存在`)
}
}
})
}
// 定义验证规则
let rule = {
age: {// 年龄只能为数字
validate(val) {
return /\d/.test(val)
},
message(key, val) {
return `属性${key}是年龄,不能为${val}`
}
}
}
class Person {
constructor(name, age) {
this.name = name
this.age = age
return createValidator(this, rule)
}
}
let person = new Person('hvb', 22)
person.age = 12
console.log(person.age)// 12
person.age = 'qwe'// 抛出错误
{
class Person {
constructor(name='hvb') {
this.name = name
}
// getter
get longName() {
return 'long '+ this.name
}
// setter
set longName(value) {
return this.name = value
}
// 静态方法
static say() {
console.log('I am '+ this.name)// I am Person
}
}
// 静态属性
Person.age = 22
let person = new Person()
console.log(person.longName)// long hvb
person.longName = 'hwj'
console.log(person.longName)// long hwj
Person.say()
}
,这样可以直接在script标签里面正常使用import a from 'a.js';// node会在node_modules文件夹下寻找相应的模块
import a from './a.js;// node会在同级目录文件夹下寻找相应的模块
var obj1 = {
a: 1,
b: 2
}
var obj2 = {
a: 3,
c: 4
}
var obj = { ...obj1, ...obj2 }
console.log(obj)// {a: 3, b: 2, c: 4}
this指向是不可改变的
正常函数写法
var sex = 'male';
function Foo() {
console.log(this.sex);
}
Foo.call({sex: 'female'});// => female
箭头函数写法
var sex = 'male';
var Foo = () => {console.log(this.sex)};
Foo.call({sex: 'female'});// => male // Foo的this指向全局,由于函数使用箭头函数写法,所以使用call无法改变this指向,依然输出male
直接返回对象要加()
var Foo = x => ({x: x});
console.log(Foo(2).x);// => 2
箭头函数可以嵌套使用
正常函数写法
function A(a) {
return {
B: function(b) {
return a+b;
}
}
}
console.log(A(1).B(2));// => 3
箭头函数写法
var A = a => ({B: b => a+b});
console.log(A(1).B(2));// => 3
函数简写 (详见#11)
var obj = {
sex: 'male',
say: () => {
console.log(this.sex);
}
}
obj.say();// => undefined // 箭头函数的this指向它定义时所在的作用域,即全局
var obj = {
sex: 'male',
say() {
console.log(this.sex);
}
}
obj.say();// => male // 简写函数的this指向对象obj本身
其他
es6写法
var sex = 'male',
age = 22,
say = function(a, b) {
return a+b;
};
var f1 = () => ({sex, age});
var f2 = () => (sex, age);
var f3 = () => (sex, age) => say(sex, age);
编译成es5写法
var sex = 'male',
age = 22,
say = function say(a, b) {
return a + b;
};
var f1 = function f1() {
return { sex: sex, age: age };
};
var f2 = function f2() {
return sex, age;
};
var f3 = function f3() {
return function (sex, age) {
return say(sex, age);
};
};
[#1] shim和polyfill有什么区别
[#2] shim和polyfill有什么区别?
[#3] ES6 Rest参数
[#4] ES2015系列(二) 理解Object.assign
[#5] 在JavaScript ES6中使用let和const定义变量
[#6] ES6详解六:赋值语法糖 destructing & spread
[#7] ES6中新增的数据结构Set与Map
[#8] 深入解读JavaScript中的Iterator和for-of循环
[#9] ES6详解八:模块(Module)!
[#10] ES6中箭头函数的使用
[#11] es6对象方法简写?
[#12] 关于ES6的 模块功能 Module 中export import的用法和注意之处
[#13] babel的polyfill和runtime的区别
[#14] 触摸ES6 - 模板字符串
class Foo {
log() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000)
})
}
async say() {
return await this.log()
}
}
let f = new Foo()
f.say()
.then(data => {
console.log(data)
})
promise化
var Promise = require('bluebird')
var async = Promise.promisifyAll(require('async'))
async.seriesAsync([(cb) => {
cb(null, 1)
}])
.then((data) => {
console.log(data, 11)
})
caolan/async
Async使用简介之流程控制
体验异步的终极解决方案-ES7的Async/Await