1、块变量let
for (var i=0;i<3;i++){
for (var i=0;i<3;i++){
}
}
// 该循环中的变量i是公用的,只会循环3次
for (let i=0;i<3;i++){
for (let i=0;i<3;i++){
}
}
// 该循环中的变量i是块级变量,第一层循环和第二层循环不互相影响 可以循环9次
2、使用闭包摆脱全局作用域的变量
var elements = [{},{},{}];
for (var i=0; i < elements.length; i++){
elements[i].onclick = (function(i){
return function(){
console.log(i)
}
})(i);
}
elements[0].onclick()
// 使用let达到闭包的效果
for (var i=0; i < elements.length; i++){
elements[i].onclick =function(){
console.log(i)
}
}
elements[0].onclick()
3、数组解构Destructing
从数组中快速获取元素的方式
// 以前的做法
const arr = [100,200,300]
const a = arr[0]
const b = arr[1]
const c = arr[2]
console.log(a, b, c)
// 解构
const [a, b, c] = arr;
const [, , c] = arr;
const [, ...ret] = arr;
console.log(ret) // [200, 300]
const [q] = arr; // 100
const [x, y, z, t] = arr; // 100, 200, 300, undefined
const [x, y, z, t = 400] = arr; // 100, 200, 300, 400
4、对象解构
const obj = {name: 'zhangsan', age: 18}
const {name} = obj
console.log(name) // zhangsan
const {username} = obj
console.log(username) // undefined
// 命名冲突的解决办法
const name = 'tom';
const {name: objName, username = 'test'} = obj
console.log(objName, username) // zhangsan test
// 解构console.log
const {log} = console
log('a')
5、模板字符串
const name = 'tom'
const test = `hello, ${name}`
// 高级用法 标签函数
const a = 'zhansgan'
const b = 'lisi'
/**
function myTagFunc(strings){
console.log(strings) // ['name: ', ' and name:', ' 111']
}
*/
function myTagFunc(strings, a, b){
console.log(strings, a, b) // ['name: ', ' and name:', ' 111'] zhangsan lisi
}
const result = myTagFunc`name: ${a} and name: ${b} 111`
字符串扩展
// includes()
// startsWith()
// endsWith()
const a = 'Error: 1234';
console.log(a.startsWith('Error')); // true
console.log(a.endsWith('1234')); // true
console.log(a.includes('Error')); // true
6、剩余参数
function a(b, ...args){
console.log(args); // [2, 3, 4]
}
a(1, 2, 3, 4)
7、展开数组Spread
const arr = [100, 200, 300];
console.log.apply(console, arr); // 100 200 300
// es2015
console.log(...arr); // 100 200 300
8、箭头函数
const inc = n => n + 1
console.log(inc(100)) // 101
const add = (x, y) => {
console.log(x + y );
return x + y;
}
// 最大作用,极大的简化了回调函数
const b = [1,2,3,4,5,6,7]
b.filter(x => x % 2)
// 箭头函数不会改变this的指向
const person = {
name: 'tom',
//sayHi: function() {
//console.log(`hi, my name is ${this.name}`) // hi, my name is tom 这里的name后来被改变了内容
//},
sayHiAsync: function(){
/**
const _this = this;
setTimeOut(function() => {
console.log(`hi, my name is ${_this.name}`)
}, 1000) // hi, my name is undefined 使用const _this = this;后何以使用this
*/
setTimeOut(() => {
console.log(`hi, my name is ${_this.name}`) // hi, my name is tom
}, 1000)
},
sayHi: () => {
console.log(`hi, my name is ${this.name}`) // hi, my name is undefined
}
}
person.sayHi()
9、对象字面量的增强
const bar = '456';
const obj = {
name: '123',
bar,
method1(){
console.log('111111');
console.log(this); // 指向当前变量
},
[Math.random()]: '11', // 计算属性名
['234']: '11', // 计算属性名可以是任意变量
[bar]: '11', // 计算属性名可以是任意变量 => '234': '11'
};
console.log(obj); // {name: '123', bar: '456', method1: [Function: method1]}
obj.method1(); // 调用method1
对象扩展方法
const source1 = {
a: 123,
b: 123
}
const source2 = {
b: 789,
d: 789
}
const target = {
a: 456,
c: 456
}
// 合并target 和 source1
const result = Object.assign(target, source1, source2); // 用后边对象的内容覆盖前边的对象
console.log(target); // {a: 123, c: 456, b: 789, d:789}
console.log(target === result); // true
// 函数内对象不影响函数外对象
function func(obj){
const funcObj = Object.assign({}, obj);
funcObj.name = 'lisi'
console.log(funcObj); // {name: lisi} 类似于深拷贝
}
const obj = {name: 'zhangsan'}
func(obj); // {name: lisi}
console.log(obj); // {name: zhangsan}
Object.is(+0, -0) // false
Object.is(NaN, NaN)
10、代理对象Proxy
const person = {
name: 'zhangsan',
age: 20
};
const personProxy = new Proxy(person, {
get(target, property){
console.log(target, property);
return property in target ? target[property] : undefined;
},
set(target, property, value){
target[property] = value;
return true; // 写入成功
// console.log(target, property, value);
},
deleteProperty(target, property): boolean {
delete target[property];
return true;
}
});
const list = [];
const listProxy = new Proxy(list, {
set(target, property, value){
console.log('set', property, value); // set 0 100
target[property] = value;
return true;
}
});
listProxy.push(100);
// Proxy和Object.defineProperty()的区别
// defineProperty智能监控到对象的属性的读写
// Proxy能监控到更多对象操作
// deleteProperty监控删除属性的事件
// Proxy是以非侵入的方式见惯了对象的读写
11、统一的对象操作API Reflect
// Reflect 是一个静态类 不能使用new Reflect()
const obj = {
name: 'zce',
age: 18
};
console.log('name' in obj); // true
console.log(delete obj.age); // true
console.log(Object.keys(obj)); // [ 'name']
console.log(Reflect.has(obj, 'name'));
console.log(Reflect.deleteProperty(obj, 'age'));
console.log(Reflect.ownKeys(obj)); // ['name']
12、唯一类型Symbol
// 使用Symbol创建对象的私有成员
const name = Symbol();
const person = {
[name]: 'zce',
say(){
console.log(this[name]);
}
}
// 该name只能在person内访问,在person外无法访问
// Symbol最主要的作用就是为对象添加独一无二的属性名
console.log(Symbol() === Symbol()); // false
console.log(Symbol('bar') === Symbol('bar')); // false
console.log(Symbol.for('bar') === Symbol.for('bar')); // true
console.log(Symbol.for('true') === Symbol.for(true)); // true 自动降对象转为字符串 需要注意
console.log(Symbol.iterator); // Symbol(Symbol.iterator)
console.log(Symbol.hasInstance);
console.log({}.toString()); // [object Object]
console.log({[Symbol.toStringTag]: 'XObject'}.toString()) // [object XObject]
13、for循环
// for遍历普通数组
// for...in 适合遍历键值对
// 对象的foreach
// es2015引入for...of统一遍历方式
// for...of遍历原理
const set = new Set([100,200,300]);
const iterator = set[Symbol.iterator]();
console.log(iterator.next()); // {value: 100, done: false}
console.log(iterator.next()); // {value: 200, done: false}
console.log(iterator.next()); // {value: 300, done: false}
console.log(iterator.next()); // {value: undefined, done: true}
// 自定义实现对象的iterator迭代器
const a = {
store: [100, 200, 300],
[Symbol.iterator]: () => {
let index = 0;
const self = this;
return {
next: () => {
const result = {
value: a.store[index],
done: index >= a.store.length
};
index ++;
return result;
}
};
},
};
for (const item of a){
console.log('循环体', item);
}
14、迭代器的意义
// 对外提供统一接口
const todos = {
life: ['吃饭', '睡觉', '打豆豆'],
learn: ['语文', '数学', '英语'],
work: ['喝茶'],
each: (callback) => {
const all = [].concat(todos.learn, todos.learn, todos.work);
for (const item of all){
callback(item);
}
},
[Symbol.iterator]: (callback) => {
const all = [...todos.life, ...todos.learn, ...todos.work];
let index = 0;
return {
next: () => {
return {
value: all[index],
done: index ++ >= all.length
};
}
};
}
};
for (const item of todos){
console.log(item); // 遍历数组中所有的内容
}
15、生成器Generator
// 为了在复杂的异步代码中,减少异步函数嵌套的问题,提供更好的异步编程解决方案
// 定义生成器函数
function * a() {
console.log('zce');
return 100;
}
const result = a();
console.log(result); // Object [Generator]{} 生成器对象
console.log(result.next()); // 执行 zce {value: 100, done: true}
function * foo() {
console.log('1111');
yield 100;
console.log('2222');
yield 200;
console.log('3333');
yield 300;
}
const generator = foo();
console.log(generator.next()); // 1111 {value: 100, done: false}
console.log(generator.next()); // 2222 {value: 200, done: false}
console.log(generator.next()); // 3333 {value: 300, done: false}
生成器应用
// 案例一:发号器
function * createIdMaker(){
let id = 1;
while(true){
yield id++; // yield过后方法被暂停 不用担心死循环问题
}
}
const idMaker = createIdMaker();
console.log(idMaker.next().value); // 1
console.log(idMaker.next().value); // 2
console.log(idMaker.next().value); // 3
console.log(idMaker.next().value); // 4
// 案例二:使用Generator 实现 iterator 方法
const todos = {
life: ['吃饭', '睡觉', '打豆豆'],
learn: ['语文', '数学', '英语'],
work: ['喝茶'],
[Symbol.iterator]: function * a(callback) {
const all = [...todos.life, ...todos.learn, ...todos.work];
for (const item of all){
yield item;
}
}
};
for (const item of todos){
console.log(item);
}
16、ES2017特性
const obj = {
foo: 'value1',
bar: 'value2'
}
console.log(new Map(Object.entries(obj))); // Map('foo' => 'value1', 'bar' => 'value2')
// 对象拷贝 包含对象的方法
const p1 = {
firstName: 'Lei',
lastName: 'Wang',
get fullName(){
return this.firstName + ' ' + this.lastName;
}
};
// const p2 = Object.assign({}, p1);
// p2.firstName = 'zce';
// console.log(p2.fullName); // Lei Wang Object.assign会把fullName当作普通属性进行复制
const descriptiors = Object.getOwnPropertyDescriptors(p1); // 获取对象的所有描述信息
const p2 = Object.defineProperties({}, descriptiors);
p2.firstName = 'zce';
console.log(p2.fullName); // zce Wang
// 字符串补齐
const name = 'zhangsan';
const age = '18';
console.log(name.padEnd(10, '-')); // zhangsan--
console.log(age.padStart(5, '0')); // 00018