3.1 const
{
const a = {
j: 2
};
a.k = 3; //a={j:2,k:3}
a.j = 1; //j=1
}
//const声明一个常量,不可更改。但声明一个对象的话,是指向对象的指针,而对象本身,是可以更改的
3.2 解构赋值
//数组的解构赋值
{
let a, b;
[a, b] = [1, 2]; //a=1,b=2
}
{
let a, b, rest;
[a, b, ...rest] = [1, 2, 3, 4, 5]; //a=1,b=2,rest=[3,4,5]
}
//对象的解构赋值
{
let a, b;
({ a, b } = { a: 1, b: 2 }); //a=1,b=2
}
{
let o = { p: 42, q: true };
let { p, q } = o; //p=42,q=true
}
{
let a, b;
({ a, b, c = 3 } = { a: 1, b: 2 }); //a=1,b=2,c=3
}
{
let { a = 10, b = 5 } = { a: 3 }; //a=3,b=5
}
{
let metaData = {
title: 'abc',
test: [{
title: 'test',
desc: 'description'
}]
}
let { title: esTitle, test: [{ title: cnTitle }] } = metaData;
//esTitle='abc',cnTitle='test'
}
//变量的交换
{
let a = 1,
b = 2;
[a, b] = [b, a]; //a=2,b=1
}
//获取函数返回值
{
function f() {
return [1, 2, 3, 4, 5];
}
let a, b;
[a, b] = f(); //a=1,b=2
let c, d;
[c, , , d] = f(); //c=1,b=4
let e, rest;
[e, , ...rest] = f(); //e=1,rest=[3,4,5]
}
3.3 正则拓展
//es5写法
let regex=new Regexp('xyz','i');
let regex=new Regexp(/xyz/i);
//es5的这种写法 只能为一个参数
//es6写法
let regex=new Regexp(/xyz/ig,'i')
后面的i会覆盖前面的ig
//Regexp.flags —— 获取正则对象的修饰符
let regex=bew Regexp(/a/g)
let regex=bew Regexp(/a/y)
//g修饰符和y修饰符都是全局匹配 ,g修饰符从上次匹配的位置继续寻
//找,不强调为下次匹配位置的第一个开始匹配,只能后续能找到即可,
// y修饰符必须为下次匹配位置的第一个位置开始就可以匹配到,否则第
//二次匹配为false
let a=/a+/y;
console.log(a.sticky) //true
//sticky 判断正则对象是否为粘连模式(含有y修饰符)
//添加u修饰符之后,会把后面的四个字节(两个字符)当做一个字符(实际为两个字符)
console.log('u-1', /^\uD83D/.test('/uD83D\uDC2A'));
console.log('u-2', /^\uD83D/u.test('/uD83D\uDC2A'));
console.log(/\u{61}/.test('a'));
console.log(/\u{61}/u.test('a'));
//如果大括号包裹的是unicode字符,需要加上u修饰符才能被识别
// ‘.’ 只能表示为不大于2个字节的字符。
//如果字符串中有大于两个字节的字符 则需要添加u修饰符,否则无法正确识别
3.4 字符串拓展
console.log('a','\u0061');
console.log('a','\u20BB7');
console.log('a','\u{20BB7}');
//当Unicode编码大于两个字节,则需要使用大括号包围,才可以正常解析
// codePointAt 取码值(es6的方法)
let a='𠮷a';
console.log(a.length);
console.log('0',a.charAt(0));
console.log('1',a.charAt(1));
console.log('2',a.charAt(2));
console.log('at0',a.charCodeAt(0).toString(16));
console.log('at1',a.charCodeAt(1).toString(16));
console.log('at2',a.charCodeAt(2).toString(16));
console.log('code0',a.codePointAt(0).toString(16));
console.log('code1',a.codePointAt(1).toString(16));
console.log('code2',a.codePointAt(2).toString(16));
//“𠮷”大于两个字节 会按照四个字节编译。每两个字节为一个长度,也
//就是有两个长度。codePointAt在处理大于两个字节的字符时,
//codePointAt(0)会按照四个字节进行编译
console.log(String.fromCharCode('0x20bb7'));
console.log(String.fromCodePoint('0x20bb7'));
//fromCodePoint 给码值取字符 (es6方法) 可解析大于0xFFFF的字符
{
let str = '\u{20BB7}abc';
for (let i of str) {
console.log(i);
}
}
//可使用let of遍历大于两个字节的字符
let str='string';
console.log('includes',str.includes('r'));
—— 判断字符串是否包含某些字符
console.log('start',str.startsWith('st'));
—— 判断字符串是否以某些字符开始
console.log('end',str.endsWith('ng'));
—— 判断字符串是否以某些字符结束
console.log(str.repeat(2));
—— 将字符串重复两次
//模板字符串
let a='jm';
let b='hello world';
let c=`i am ${a},${b}`;
console.log(c); // i am jm,hello world
ES7提案
//str.padStart(length,'value')
console.log('1'.padStart(2,'0')); //01
//字符串的起始位置补白
console.log('1'.padEnd(2,'0')); //10
//字符串的结束位置补白
#标签模板
//String.raw
console.log(String.raw`Hi\n${1+2}`); //Hi\n3
console.log(`Hi\n${1+2}`); //Hi(换行) 3
//String.raw对所有的斜杠进行转义
3.6 数值拓展
console.log(0b111110111);
console.log(0o767);
//0B位二进制,0o为八进制,大小写皆可;
//判断一个数是否为有尽
console.log(Number.isFinite(15)); //true
console.log(Number.isFinite(NaN)); //false
console.log(Number.isFinite(15/0)); //false
//判断一个值是否为非数字
console.log(Number.isNaN(15)); //false
console.log(Number.isNaN(NaN)); //true
console.log(Number.isNaN(15/0)) //false
//判断一个数是否为整数
console.log(Number.isInteger(25)); //true
console.log(Number.isInteger(25.0)); //true
console.log(Number.isInteger(25.1)); //false
console.log(Number.isInteger(‘a’)); //false
//一个数的有效值范围为-2的53次方到2的53次方(不包含端点本身)。ES6设置两个常量为:
console.log(Number.MAX_SAFE_INTEGER); //2的53次方
console.log(Number.MIN_SAFE_INTEGER); //-2的53次方
//Es6给出的API为:
console.log(Number.isSafeInteger(15)); //true
console.log(Number.isSafeInteger('a')); //false
//判断一个数是否为有效值,即是否安全
console.log(Math.trunc(4.1)); //4
console.log(Math.trunc(4.8)); //4
//取一个数的整数部分
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('aa')); //NaN
//判断一个数是大于0,小于0,或者等于0,如果为字符串,则会转换
//为数字进行解析,不通过则返回NaN;
//求一个数的立方根
console.log(Math.cbrt(-1)); //-1
console.log(Math.cbrt(8)); //2
3.7 数组拓展
//Array.of() 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。
Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
Array(7); // [ , , , , , , ]
Array(1, 2, 3); // [1, 2, 3]
// Array.of() 和 Array 构造函数之间的区别在于处理整数参数:
//Array.of(7) 创建一个具有单个元素 7 的数组,而 Array(7) 创建一个包
//含 7 个 undefined 元素的数组
//Array.from() 方法从一个类似数组或可迭代对象中创建一个新的数组实例。
const bar = ["a", "b", "c"];
Array.from(bar);
// ["a", "b", "c"]
Array.from('foo');
// ["f", "o", "o"]
Array.from([1,2,3],function(item){return item*2})
//Array.from可以有两个参数,第二个参数为一个函数可以进行MAP操作。
//替换数组内容
cnosole.log([1,2,3].fill(7)); //[7,7,7]
console.log([1,1,1,1,1].fill(7,1,3)); //[1,7,7,1,1]
//获取数组的index和值
for(let [index,value] of ['a','b','c'].entries()){
console.log(index); //1,2,3
}
//arr.copyWithin(target, start, end)
console.log([1,2,3,4,5,6,7,8,9].copyWithin(0,2,4)); //[1, 3, 4, 4, 5, 6, 7, 8, 9]
//target 复制序列到该位置。如果是负数,target 将从末尾开始计算
//start 开始复制元素的起始位置。如果是负数,start 将从末尾开始计算。
//end 开始复制元素的结束位置。copyWithin 将会拷贝到该位置,
//但不包括 end 这个位置的元素。如果是负数, end 将从末尾开始计算。
console.log([1,2,3,4,5,6].find(function(item){return item>3})) //4
console.log([1,2,3,4,5,6].findIndex(function(item){return item>3})) //3
//找到第一个符合条件的数组成员
console.log([1,2,NaN].includes(NaN)) //true
//参数不是函数,直接寻找数组里有没有这个值,可匹配NaN
3.8 函数拓展
{
let x = 'test';
function test2(x, y = x) {
console.log('作用域',
x, y)
}
test2('kill'); //作用域 kill kill
}
{
let x = 'test';
function test2(x, y = x) {
console.log('作用域',
x, y)
}
test2(); //作用域 undefined undefined
}
{
let x = 'test';
function test2(c, y = x) {
console.log('作用域',
x, y)
}
test2('kill'); // 作用域 kill test
}
//rest参数,将离散的值转为数组,使用rest参数之后,后面不能在添加别的参数
{
function test3(...arg) {
console.log(arg)
for (let v of arg) {
console.log('rest', v)
}
}
test3(1, 2, 3, 4)
}
//将数组转为离散的值。可添加别的参数
console.log(...[1,2,3,4]);
console.log('a',...[1,2,3,4])
//箭头函数 ( let + 函数名 + 参数 + 返回值 )
{
let demo = v => v * 2;
console.log(demo(10)); //20
let demo1 = () => 5;
console.log(demo1()); //5
}
3.9对象扩展
//简洁表示法
{
let [a, b] = [1, 2];
let es5 = {
a: a,
b: b
}
let es6 = {
a,
b
}
console.log(es5, es6)
}
{
let c = {
demo: function() {
console.log('es5的方法表示')
}
}
let d = {
demo() {
console.log('es6的方法表示')
}
}
console.log(c.demo(), d.demo())
}
//属性表达式(中括号中为变量,里面可填表达式)
{
let a = 'b';
let es5 = {
a: 'c',
b: 'c'
}
let es6 = {
[a]: 'c'
}
console.log(es5, es6)
}
//新增API
{
console.log('字符串', Object.is('abc', 'abc'), 'abc' === 'abc')
//判断两个参数是否相等,和‘===’在功能上是相同的
console.log('数组', Object.is([], []), [] === [])
//数组是引用类型,引用的两个不同地址,严格上是不相等的
console.log('拷贝', Object.assign({ a: 'a' }, { b: 'b' }))
//Object.assign(要拷贝到的对象,要拷贝的对象),浅拷贝。
//只拷贝自身对象的属性,不拷贝继承和不可枚举的属性
let test = { k: 123, o: 456 };
for (let [key, value] of Object.entries(test)) {
console.log(key, value)
}
//Object.entries配合对象的使用
}
//扩展运算符
let {a,b,...c}={a:'a',b:'b',c:'c',d:'d'}
//最后c应该为 c{c:'c',d:'d'}
3.10 Symbol用法
//Symblo的声明:
let a1=Symbol();
let a2=Symbol();
console.log(a1===a2); //false
let a3=Symbol.for('a3');
let a4=Symbol.for('a3');
console.log(a3===a4); //true
//使用Symbol声明的变量永远是独一无二的
Object.getOwnPropertySymbols(obj);
//可以拿到使用Symbol作为key值的对象的属性
Reflect.ownKeys(obj);
//可以拿到使用Symbol作为key值的对象的属性,也可以拿到非Symbol作为key值的对象的属性
3.11 set-map数据结构
{
//set的定义:
let list = New Set();
list.add(1);
list.add(2);
console.log(list.size); //2
}
{
//不同的定义方式:
let arr = [1, 2, 3.1, 2];
let list = New Set(arr);
console.log(list); //1,2,3(去重,不会做数据类型的转换)
}
//相当于数组,但是里面的值不能重复,add为添加元素,size相当于数组中的length,也就是长度
//set的方法:
obj.add() :添加元素
obj.delete():删除元素
obj.has():判断是否含有这个元素
obj.clear():清空Set集合中的元素
//遍历
{
let arr = ['add', 'delete', 'clear', 'has'];
let obj = New Set(arr);
for (let key of obj.keys()) {
console.log(key); //'add','delete','clear','has'
}
for (let value of obj.values()) {
console.log(value); //'add','delete','clear','has'
}
for (let [key, value] of obj.entries()) {
console.log(key, value) //key和value的值都是相同的
}
obj.forEach(function(item) {
console.log(item); //'add','delete','clear','has'
})
}
//WeakSet的定义:
let weakset=new WeakSet();
let arg={};
weakset.add(arg);
//WeakSet里只能放对象,没有size属性,没有clear方法,不能遍历,不会和垃圾回收机制挂钩。
//在WeakSet中添加一个对象,只是地址的引用,也不会检测这个对象是否已经被垃圾回收。
//Map的定义:
let map=New Map();
let arr=['123'];
map.set(arr,456);
console.log('map',map,map.get(arr));
//第二种定义方法:
let map =New Map([['a',123],['b',456]])
//Map中是一个数组,数组里还是数组
//Map的特性是key可以是任何数据类型,Map的添加元素的方法是set(),Map的获取元素的方法为get()
//长度为size(),删除为delete(),清空为clear(),遍历和Set是一样的。
//WeakMap的定义:
let weakmap=new WeakMap();
//WeakMap的key值只能是对象,没有size属性,没有clear方法,不能遍历。
3.13 Proxy和Reflect
//Proxy
{
let obj = {
time: '2017-3-11',
name: 'jm',
_r: 123
}
let monitor = new Proxy(obj, {
//拦截对象属性的读取
get(target, key) {
return target[key].replace('2017', '2018')
},
//拦截对象设置属性
set(target, key, value) {
if (key === 'name') {
return target[key] = value;
} else {
return target[key];
}
},
//拦截key in object操作
has(target, key) {
if (key === 'name') {
return target[key]
} else {
return false
}
},
//拦截delete
deleteProperty(target, key) {
if (key.indexOf('_') > -1) {
delete target[key];
return true;
} else {
return target[key]
}
},
//拦截object,keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames
ownKeys(target) {
return Object.keys(target).filter(item => item != 'time')
}
});
console.log('get', monitor.time); //2018-3-11
monitor.time = '2018';
monitor.name = 'muke';
console.log('set', monitor.time, monitor);
console.log('has', 'name' in monitor, 'time' in monitor); //true,false
delete monitor.time;
console.log('delete', monitor.time);
console.log('ownkeys', Obiect.keys(monitor))
}
//Proxy和Reflect只是写法不同,用法是一样的,都是对原数据的代理
{
let obj = {
time: '2017-3-11',
name: 'jm',
_r: 123
}
console.log('reflect', Refect.get(obj, 'time')); //2017-3-11
Refect.set(obj, 'name', 'muke');
console.log(obj)
}
3.14 类与对象
//基本定义和生成实例
{
class Parent {
constructor(name = 'moren') { //构造函数
this.name = name;
}
}
let v_parent = new Parent('v');
console.log('构造函数实例',
v_parent)
}
//继承
{
class Parent {
constructor(name = 'moren') {
this.name = name;
}
}
class Child extends Parent { //继承
}
console.log('继承',
new Child())
}
//继承传递参数
{
class Parent {
constructor(name = 'moren') {
this.name = name;
}
}
class Child extends Parent {
constructor(name = 'child') {
super(name); //如果为空会使用父类的默认值
this.type = 'child'; //子类定义属性调用this需要放在super之后
}
}
console.log(‘继承’, new Child())
}
//getter,setter
{
class Parent {
constructor(name = 'moren') {
this.name = name;
}
get longName() { //get后面为属性,不是方法
return 'mk' + this.name
}
set longName(value) {
this.name = value;
}
}
let v = new Parent();
console.log('getter', v.longName); // mkmoren
v.longName = 'hello';
console.log('setter', v.longName); //mkhello
}
//静态方法
{
class Parent {
constructor(name = 'moren') {
this.name = name;
}
static tell() { //加了static就变成了静态方法,通过类调用,而不是通过实例调用
console.log('tell')
}
}
Parent.tell(); //tell
}
//静态属性
{
class Parent {
constructor(name = 'moren') {
this.name = name;
}
static tell() {
console.log('tell')
}
}
}
Parent.type='test'; //静态属性 通过类去读取
console.log('静态属性',Parent.type) ; //test
3.15 Promise
//Promise的基本定义
{
let ajax=function(){
console.log('执行1');
return new Promise(function(resolve,reject){
//resolve为执行下一步操作,reject为中断当前操作
setTimeout(function(){
resolve()
},1000)
})
}
ajax().then(function(){
console.log('promise','timeout1')
},function(){ }) //第二个function为reject
}
//Promise的多步调用
{
let ajax = function() {
console.log('执行1');
return new Promise(function(resolve, resect) {
setTimeout(function() {
resolve()
}, 1000)
})
}
ajax().then(function() {
console.log('setTimeout2')
return new Promise(function(resolve, resect) {
setTimeout(function() {
resolve()
}, 1000)
})
}).then(function() {
console.log('setTimeout3')
})
}
// catch 错误捕获
{
let ajax=function(num){
console.log('执行1');
return new Promise(function(resole,resect){
if(num>5){
resole()
}else{
throw new Error('出错了')
}
})
}
ajax(6).then(function(){
console.log('6',6)
}).catch(function(err){
console.log('catch',err)
})
ajax(3).then(function(){
console.log('3',3)
}).catch(function(err){
console.log('catch',err)
})
}
//所有图片加载完再添加到页面 Promise.all
{
function loadImg(src){
return new Promise((resolve,resect)=>{
let img =document.createElement('img');
img.src=src;
img.onload=function(){
resolve(img)
}
img.onerror=function(err){
resect(err)
}
})
}
function showImgs(imgs){
imgs.forEach(function(img){
document.body.appendChild(img)
})
}
Promise.all([
loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png')
]).then(showImgs)
}
//Promise.rece 当有一张图片加载完成就添加到页面,其他的不再响应,用法和Promise.all相同
3.16 Iterator
//自定义部署interator方法 (使obj可遍历)
{
let obj = {
start: [1, 2, 3],
end: [4, 5, 6],
[Symbol.iterator]() {
let self = this;
let index = 0;
let arr = self.start.concat(self.end);
let len = arr.length;
return {
next() {
if (index < len) {
return {
value: arr[index++],
done: false
}
} else {
return {
value: arr[index++],
done: true
}
}
}
}
}
}
for (let key of obj) { //obj原本是不能使用for...of遍历
console.log(key)
}
}
3.17 Generator
//基本定义
{
let demo = function*() {
yield 'a';
yield 'b';
return 'c'
}
let k = demo();
console.log(k.next())
console.log(k.next())
console.log(k.next())
}
//使用Generator让obj具有iterator接口,让obj可遍历
{
let obj = {};
obj[Symbol.iterator] = function*() {
yield 1;
yield 2;
yield 3;
}
for (let value of obj) {
console.log('value', value)
}
}
//状态机
{
let state=function*(){
while(1){
yield 'A';
yield 'B';
yield 'C';
}
}
let status=state();
console.log(status.next())
console.log(status.next())
console.log(status.next())
console.log(status.next())
console.log(status.next())
console.log(status.next())
}
//async语法 用法和Generator一样,是Generator的语法糖
{
let state=async function(){
while(1){
await 'A';
await 'B';
await 'C';
}
}
let status=state();
console.log(status.next())
console.log(status.next())
console.log(status.next())
}
//抽奖小实例
{
let draw = function(count) {
//具体抽奖逻辑
console.log(`剩余${count}次`)
}
let residue = function*(count) {
while (count > 0) {
count--;
yield draw(count);
}
}
let star = residue(5);
let btn = document.createElement('button');
btn.id = 'start';
btn.textContent = '抽奖';
document.body.appendChild(btn);
document.getElementById('start').addEventListener('click', function() {
star.next()
}, false)
}
//长轮询
{
let ajax=function* (){
yield new Promise(function(resolve,reject){
setTimeout(function(){
resolve({code:1})
},200)
})
}
let pull=function(){
let generator=ajax();
let step=generator.next();
step.value.then(function(d){
if(d.code!=0){
setTimeout(function(){
console.info('wait');
pull()
},1000)
}else{
console.info(d)
}
})
}
pull()
}
3.18 Decorators修饰器
//基本定义与功能
{
//修饰器函数
let readOnly = function(target, name, descriptor) {
//(类本身,修改的属性名称,该属性的描述对象)
descriptor.writable = false;
return descriptor
}
// @readOnly 写在类前面也行
class Test {
@readOnly
time() {
return '2018-04-12';
}
}
let test = new Test();
console.log(test.time())
//第三方修饰器库: core-decorators
}
//日志系统
{
let log = (type) => {
return function(target, name, descriptor) {
let src_method = descriptor.value;
descriptor.value = (...arg) => {
src_method.apply(target, arg);
console.info(`log ${type}`)
}
}
}
class AD {
@log('show')
show() {
console.log('ad is show')
}
@log('click')
click() {
console.log('ad is click')
}
}
let ad = new AD();
ad.show();
ad.click()
}
3-19 Module模块化
//export导出
{
export let A = 123;
export function test() {
console.log('test')
}
export class Hello{
test() {
console.log('class')
}
}
}
//import导入
{
import {A,test,Hello} from src
console.log(A,test,Hello)
}
{
import {A} from src
console.log(A)
}
//导入所有
{
import * as lesson from src
console.log(lesson.A,lesson.test)
}
// export default 默认导出
{
let A = 123;
let test = function() {
console.log('test')
}
class Hello {
test() {
console.log('class')
}
}
export default {
A,
test,
Hello
}
}
//导入
{
import Lesson17 from src //名字可以自己随意取
console.log(Lesson17.A, Lesson17.test)
}