前端技术日新月异,这一两年ES6, ES7, ES8快速普及, 的确给我我们的开发工作带来了很大的便利,以下介绍一下我自己在工作中常用到的ES新语法
(一) ES6 语法:
let const
块级作用域
没有变量提升, 并且块级作用域(封闭作用域)
if (true) {
console.log(a) // 报错 : Uncaught ReferenceError: a is not defined(…)
let a = 'js'
}
// 这里也访问不到 a
一个作用域不能重复声明同一个值
if(true){
var a = 1;
if (true) {
let a = 'js' // a == 'js'
}
a = 3; // a == 3;
let a = 2 ; // 报错Uncaught SyntaxError: Identifier 'a' has already been declared ;
// 题外话, 在console中, 产生报错后a的内存指引被清除, 可以重新赋值
let a = 0; // a == 0
// 但实际开发中, 产生报错, 后面的代码不再执行, 所以不会有这种情况产生
}
const 不能被重新赋值
const声明一个只读的常量。一旦声明,常量的值就不能改变。
const a = 1;
a = 2; // 报错 : Uncaught TypeError: Assignment to constant variable.(…)
const声明的数组, 对象, 还可以进行增改查, 但是不能重新定义
const a = [];
a.push(2) // a == [2]
const b = {};
b.a = a ; // 包含了a数组的对象
只在声明的作用域有效(与let一样)
if(true){
const c = 1;
}
// 此处访问会报错: Uncaught ReferenceError: c is not defined(…)
箭头函数
我们经常要给回调函数给一个父级的this
常用办法就是 var self = this 定义一个变量接住他
使用 箭头函数,this 将不会受到影响,可以直接用this调用父级的this
判断字符串
includes()
返回布尔值,表示是否找到了参数字符串。
str.includes(searchString[, position])
searchString
要在此字符串中搜索的字符串
position
可选。从当前字符串的哪个索引位置开始搜寻子字符串;默认值为0。
'Blue Whale'.includes('blue'); // return false
'Blue Whale'.includes('Whale' , 2); // return true
startsWith()
返回布尔值,表示参数字符串是否在源字符串的头部。
'Blue Whale'.startsWith('blue'); // return false
'Blue Whale'.startsWith('Whale' , 2); // return false
'Blue Whale'.startsWith('Whale' , 5); // return true
endsWith()
返回布尔值,表示参数字符串是否在源字符串的尾部。
'Blue Whale'.endsWith('blue'); // return false
'Blue Whale'.endsWith('Whale' , 10); // return true
'0Blue'.endsWith('Blue' , 5); // return true
模板字符串
const name = 'Tiger';
const age = 13;
console.log(`My cat is named ${name} and is ${age} years old.`);
// My cat is named Tiger and is 13 years old.
解构
解构数组
let [a, b, c, d] = [1, 2, 3, 4];
console.log(a); //1
console.log(b); //2
解构对象
let luke = { occupation: 'jedi', father: 'anakin' };
let {occupation, father} = luke;
console.log(occupation); // jedi
console.log(father); // anakin
模块
导出
function sumThree(a, b, c) {
return a + b + c;
}
export { sumThree };
引入
import { sumThree } from 'math/addition';
默认参数
function addTwoNumbers(x=0, y=0) {
return x + y;
}
addTwoNumbers() // 0
剩余参数
function(a, b, ...restArgs) {
// ...restArgs 即为剩余参数, 是一个Array对象
}
剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参。
arguments 对象不是一个真实的数组,而剩余参数是真实的 Array实例,也就是说你能够在它上面直接使用所有的数组方法,比如 sort,map,forEach,pop。
arguments 对象对象还有一些附加的属性 (比如callee属性)。
function fun1(...theArgs) {
alert(theArgs.length);
}
fun1(); // 弹出 "0", 因为theArgs没有元素
fun1(5); // 弹出 "1", 因为theArgs只有一个元素
fun1(5, 6, 7); // 弹出 "3", 因为theArgs有三个元素
Object.keys(object)
var obj = {'a': 'Beijing', 'b': 'Haidian'};
console.log(Object.keys(obj)); //['a', 'b']
Object.assign()
// target目标对象。
// sources(多个)源对象。
Object.assign(target, ...sources)
实例:
var obj = { a: 1 };
var copy = Object.assign({}, obj); // {a: 1}
-
继承属性和不可枚举属性是不能拷贝的
-
原始类型会被包装为 object
异常会打断接下来的拷贝任务
var v1 = "abc";
var v2 = true;
var v3 = 10;
var v4 = Symbol("foo")
var obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 原始类型会被包装,null 和 undefined 会被忽略。
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
展开操作
Math.max(...[-1, 100, 9001, -32]);
let cities = ['San Francisco', 'Los Angeles'];
let places = ['Miami', ...cities, 'Chicago']; // ['Miami', 'San Francisco', 'Los Angeles', 'Chicago']
类
// 声明一个类名为 Rectangle 的JS类
// constructor方法用于创建和初始化使用一个类创建的一个对象。只允许存在一个
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
如果没有指定this, this值将为undefined。this可以在constructor
里声明
class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}
let obj = new Animal();
let speak = obj.speak;
speak(); // undefined
let eat = Animal.eat;
eat(); // undefined
static
static
方法可以不用实例化直接调用
class Animal {
static eat() {
console.log('eat');
}
}
let eat = Animal.eat
eat(); // eat
类的get 与 set
// 创建一个 Chef 类
class Chef {
// 初始化
// 接收参数
constructor(food){
this.food = food;
this.dishs = [];
}
get menu(){
return this.dishs;
}
set menu(dishs){
this.dishs.push(dish)
}
cook(){
console.log(this.food)
}
}
let qing = new Chef()
console.log(qing.menu = "?") //?
console.log(qing.menu = "❦") // ❦
类的继承extends
class Person{
constructor(name, birthday){
this.name = name
this.birthday = birthday
}
intro(){
return `${this.name}, ${this.birthday}`
}
}
// 使得Chef类 继承 Person类
class Chef extends Person{
constructor(name, birthday){
// 调用父类的constructor函数
super(name, birthday)
}
}
let qing = new Chef('qing', "1949-10-1");
// 实例化后才可使用 Chef类 的intro方法
qing.intro() // "qing, 1949-10-1"
Set对象
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
个人主要用于去重
//定义两个数组
var array = [1, 2, 1, 1, '1', '一'];
var array1 = [1, '二', 2, '一', 3, 4, '5', '1', '6'];
//构建带array,array1两个参数的函数
function uq(array, array1) {
//将array数组转换成set对象
setObj = new Set(array)
//循环数组array1,并将值通过add插入set对象中,此时重复数据并不会插入其中
for(i = 0; i < array1.length; i++) {
setObj.add(array1[i]);
}
//使用Array.from()方法将set对象转换成数组,并使用sort()方法排序
return Array.from(setObj).sort();
}
//查看输出结果
console.log(uq(array, array1)); // [1, "1", 2, 3, 4, "5", "6", "一", "二"]
Map对象
可以理解成键值对
let map = new Map();
map.set('name', 'david');
map.get('name');
map.has('name');
Map 结构转为数组结构
比较快速的方法是结合使用扩展运算符(…)
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
[...map.keys()]
// [1, 2, 3]
[...map.values()]
// ['one', 'two', 'three']
[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]
[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]
Map 循环遍历
keys()
:返回键名的遍历器。
values()
:返回键值的遍历器。
entries()
:返回所有成员的遍历器
let map = new Map([
['F', 'no'],
['T', 'yes'],
]);
for (let key of map.keys()) {
console.log(key);
}
// "F"
// "T"
for (let value of map.values()) {
console.log(value);
}
// "no"
// "yes"
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// 等同于使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
Map 获取长度
map.size;
Map 获取第一个元素
const m = new Map();
m.set('key1', {})
m.set('keyN', {})
console.log(m.entries().next().value); // [ 'key1', {} ]
Promises
远离回调地狱,可以转换成垂直代码(神器啊 不了解的同学一定要去看看)
const promist = new Promise(function(resolve,reject){
if(/*异步操作成功*/){
resolve(value);
}else{
reject(error);
}
})
resolve
函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject
函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Generators
用同步的代码风格来写异步代码
function* genFunc() {
// (A)
console.log('First');
yield; //(B)
console.log('Second'); //(C)
}
(二) ES7 语法
数组实例的 includes()
Array.prototype.includes
方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。该方法属于 ES7 ,但 Babel 转码器已经支持。
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, NaN].includes(NaN); // true
该方法的第二个参数表示搜索的起始位置,默认为 0 。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为 -4 ,但数组长度为 3 ),则会重置为从 0 开始。
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
(2) 求幂运算
2**3 == 8
(三) ES8 语法
object.entries()
let obj = {a: 1, b: 2, c: 3};
Object.entries(obj).forEach(([key, value]) =>{
console.log(key + ": " + value); // 输出a: 1, b: 2, c: 3
})
// 有木有感觉和ES6的Map 对象很像
Async Await
异步看起来和同步写法一样
async fetchData(query) =>{
try {
const response = await axios.get(`/q?query=${query}`);
const data = response.data;
return data;
}
catch (error) {
console.log(error)
}
}
fetchData(query).then(data => {
this.props.processfetchedData(data)
})