let和const
let
- 块级作用域 let声明的变量只在它所在的代码块有效;
- 不存在变量提升;
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
- 在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”;
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
- 不允许重复声明; let不允许在相同作用域内,重复声明同一个变量。
const
- const声明一个只读的常量,const一旦声明变量,就必须立即初始化;
let count; // 不会报错
const count; //SyntaxError: Missing initializer in const declaration
const count = 30; // 正确声明
- const声明的变量不能再赋值;如果变量是引用类型,可以修改对象的属性值,但不可以重新修改绑定的对象。
const count = 20;
count = 30; // TypeError: Assignment to constant variable.
const obj = {};
obj.name = 'jackson';
本质: const变量不能修改指针,但是可以修改值.
let、const与var的区别
- 块级作用域,不存在变量提升;
- 不允许重复定义;
- 声明前不允许使用变量,存在暂时性死区;
- for循环中每次创建新的副本:let声明的变量则只在循环体内有效;
- 全局声明不作为 window 属性:利用 var 在全局声明变量,会作为window对象的一个属性存在,而let 和const则不会。
模板字符串
用反撇号代 ` 替单引号或者双引号:
const message = `template+`;
console.log(message);
字符串占位符
${js表达式}
const name = 'hh';
const msg = `Hello, I am ${name}`; // Hello, I am hh
变量解构赋值(常用)
对象
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
数组
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
字符串新增方法
includes(), startsWith(), endsWith()
传统上,JavaScript 只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
padStart(),padEnd()
字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
padStart()和padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。
函数扩展
常用的有参数默认值,不定参数,展开运算符和箭头函数等。
参数默认值
在es5函数的默认值是用||实现;在es6中,可以直接在参数列表直接用=赋值方式定义默认值:
function func(url, timeout = 2000, cb = function() {}) {
console.log(url, timeout, cb);
}
rest参数
ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数。 arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.prototype.slice.call先将其转为数组。 rest 参数是一个数组,数组特有的方法都可以使用。
// arguments变量的写法
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
展开运算符
展开运算符用...符号表示
const arr = [1, 2, 3]
let arr2=[44, ...arr]
console.log(arr2)//[44, 1, 2, 3]
箭头函数
箭头函数只是当作是普通函数一种简写方式。特点如下:
(1)没有this绑定:在箭头函数中无this对象;
(2)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(3)不能作为new调用:不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(4)没有arguments参数:不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
数组扩展
扩展运算符...
展开数组,将一个数组转为用逗号分隔的参数序列。
1、展开数组
console.log(...[1, 2, 3])
// 1 2 3
2、复制数组
let colors = ['red', 'green', 'blue'];
let [...cloneColors] = colors; // es6
let cloneColors=[...colors] //es6
3、合并数组
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
4、将字符串转为真正的数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]
Array.from()
将类对象转换为数组;将字符串转为数组,然后返回字符串的长度。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
array.of()
Array.of()方法用于将一组值,转换为数组。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
对象扩展
字面量语法扩展
当对象属性名和变量名相同时,赋值的时候可以省略变量名
function getObj(name, age) {
return {
name,
age
}
}
对象的扩展运算符(...)
用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。等同于使用Object.assign()方法;
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
let aClone = { ...z };
// 等同于
let aClone = Object.assign({}, z);
新增对象方法
1、利用 Object.is 判断两个值是否全相等:
console.log(Object.is(5, '5')); // false
console.log(Object.is(5, 5)); // true
2、利用 Object.assign 合并对象
Symbol对象
表示独一无二的值。调用全局函数 Symbol 创建,该函数接收一个字符串作为描述参数。
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
- 用途
- 作为对象的属性和方法,模拟对象的私有属性;
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
- 定义常量,防止常量重复定义:
const COLOR_RED = Symbol('red');
const COLOR_BLUR = Symbol('blue');
switch (color) {
case COLOR_RED:
break;
case COLOR_BLUR:
break;
//
}
Set 和 Map
- Set Set本身是一个构造函数,用来生成 Set 数据结构。
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
去重
1、利用Set 进行数组去重
[...new Set(array)]
2、去除字符串里面的重复字符
[...new Set('ababbc')].join('')
// "abc"
Proxy
用 new Proxy(target, handler) 新建一个代理对象,target 表示代理的目标对象,handler 是一个拦截行为的配置对象。
var proxy = new Proxy(target, handler);
let obj = {
name: 'hhh'
};
let proxy = new Proxy(obj, {});
console.log(proxy.name);
proxy.name = 'aaa';
console.log(obj.name);
Promise对象
用new Promise() 创建一个 Promise 对象:
let p = new Promise((resolve, reject) => {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
})
Promise 对象有3种状态:
- pending: 表示进行中的状态
- fulfilled: 任务完成的状态,调用resolve()后触发
- rejected: 任务失败的状态, 调用reject()后触发
async函数
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。
错误处理
1、在try...catch 中捕获;
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))
// hello world
2、在 await 后面的 Promise 对象的后面再跟上一个 catch() 方法;
async function f() {
await Promise.reject('出错了').catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))
// 出错了
// hello world