ES6学习

let声明变量和声明特性

声明变量

同var一样

let a;
let b,c,d;
let e = 100;
let f = 521,g = 'jll',h=[];

声明特性

  • 变量不能重复声明
  • 块级作用域:变量只在作用域里有效。(因为var声明的变量是添加在window中,所以可以在作用域外读取,而let声明的变量不会添加在window中,因此不能读取)
  • 不存在变量提升console.log(song); let song = '恋爱达人';会报错,而var存在变量提升,则不会报错
  • 不影响作用域链
{
	let school = '北京大学';
	function fun(){
	    //虽然fun函数中没有school变量,但会向上查找,因此不影响作用域链
		console.log(school);//北京大学
	}
	fun();
}

const声明常量和特点

const school = '北京大学';

特点

  • 一定要赋初始值
  • 一般常量使用大写
  • 常量的值不可修改
  • 块级作用域
  • 对于数组和对象的元素修改,不算做对常量做修改,不会报错。因为这个常量所指向的地址没有发生改变。
const TEAM = ['WW','EE','RR','YY']
TEAM.push('II');//不会报错
TEAM = 100;//会报错。因为里面的值发生了变化

变量解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值

数组的解构

const F4 = ['小沈阳','刘能','赵四','宋小宝'];
let [xiao, liu, zhao, song] = F4;//相当于声明了四个变量,每个变量对应的值就是数组的位置
console.log(xiao);//小沈阳
console.log(liu);//刘能

对象的解构

const zhao = {
	name:'赵本山',
	age:'不详',
	xiaopin: function(){
		console.log('我可以演小品')
	}
}
let {name, age, xiaopin} = zhao;
console.log(name)//赵本山
console.log(age)//不详
xiaopin()//我可以演小品
zhao.xiaopin();

模板字符串

ES6引入新的声明字符串的方式 [``]

声明

let str = `我也是一个字符串哦`;
console.log(str,typeof str);//我也是一个字符串哦 string

特性

  • 内容中可以直接出现换行符;
  • 可以直接进行变量的拼接

es6前

let str = '<ul>'
            +'<li>沈腾<li>'
            +'<li>马丽<li>'
            +'<li>魏翔<li>'
            +'<li>艾伦<li>'
            +'</ul>'

//变量拼接
let lovest = '魏翔';
//输出'xxx是我心目中最搞笑的演员'
let result = lovest + ''
console.log(result);

es6后

let str = `<ul>
            <li>沈腾<li>
            <li>马丽<li>
            <li>魏翔<li>
            <li>艾伦<li>
            </ul>`

//变量拼接
let lovest = '魏翔';
let out = `${lovest}是我心目中最搞笑的演员!!`

ES6对象的简化写法

ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。

let name = '尚硅谷';
let change = function(){
	console.log('我们可以改变你!!');
}
const school = {
	name,
	change
	//方法的简化
	improve(){
		console.log('我们可以提高你的技能')
	}
}

箭头函数

声明一个函数

let fn = function(){
	
};
let fn = (形参) =>{
	函数体
}

特性

  • this是静态的,始终指向函数在声明时所在作用域下的this的值
function getName(){
	console.log(this.name);
}
let getName2 = () => {
	console.log(this.name);
}

//设置window对象的name属性
window.name = '北京大学';
const school = {
	name:'beijindaxue'; 
}

//直接调用
getName(); //北京大学
getName2(); //北京大学

//call方法调用(可以改变函数内部this)
getName.call(school); //beijindaxue
getName2.call(school); //北京大学

//箭头函数的this值是静态的,始终指向函数在声明时所在作用域下的this的值
  • 不能作为构造实例化对象
let Person = (name,age){
	this.name = name;
	this.age = age;
}
let me = new Person('xiao',30);
console.log(me);//会报错,Person不是一个构造器
  • 箭头函数本身不绑定arguments参数,使用...rest参数代替(但如果箭头函数的 this如果指向普通函数,它的 argumens 继承于该普通函数)
let fn = () => {
	console.log(arguments);
}
fn(1,2,3);//报错,arguments没有定义
  • 箭头函数不能变量提升,必须在声明之后调用
fun()
let fun = ()=>{
	console.log('测试一下!')
}
  • 普通函数有原型prototype属性,箭头函数没有原型属性
let a = () =>{};
console.log(a.prototype); // undefined
  • 箭头函数的简写:当形参有且仅有一个时,省略小括号;当代码体只有一句话时,可以省略花括号;此时,return必须省略,而且语句的执行结果就是函数的返回值。

箭头函数的适用范围

  • 箭头函数适合与this无关的回调,比如定时器,数组的方法回调等
  • 箭头函数不适合与this有关的回调:事件回调,对象的方法

tips

如果没有特殊指向,setInterval和setTimeout的回调函数中this的指向都是window。这是因为JS的定时器方法是定义在window下的

函数参数的默认值设置

形参初始值

具有默认值的参数,一般位置要靠后(潜规则)

如果不传c这个参数,且不给c赋初始值,c就是NaN。

function add(a,b,c){
	return a + b + c;
}
let result = add(1,2);
console.log(result);

与解构赋值结合

function connect({host='127.0.0.1',username,password,post}){
	console.log(host);
	console.log(username);
	console.log(password);
	console.log(port);
}
connect({
	host:'localhost',
	username:'root',
	password:'root',
	port:3306
})

rest参数

用于获取函数的实参,用来代替arguments

ES5获取实参的方式

function date(){
	console.log(arguments);//得到类数组的对象
}
date('小明','小米','小白');

ES6后使用rest参数

function date(...args){
	console.log(args);//得到一个数组
}
date('小明','小米','小白');
  • rest参数必须放在最后

扩展运算符

扩展运算符能将【数组】转化为逗号分隔的【参数序列】

const boys = ['qq','ee','rr'];
function chunwan (){
	console.log(arguments);
}
chunwan(boys);//arguments只有一个数组元素,等同于chuanwan(boys)
chuanwan(...boys);//arguments有三个元素;等同于chuanwan('qq','ee','rr')

跟rest参数的区别

rest参数是将其放在函数声明的形参位置上,而扩展运算符是放在函数调用的实参上

使用范围

数组的合并
const kuaizi = ['王太利','肖央'];
const fenghuang = ['曾毅','玲花'];

const zuixuanxiaopingguo = [...kuaizi,...fenghuang];
console.log(zuixuanxiaopingguo);
数组的克隆
const sanzhihua = ['E','G','M'];
const sanyecao = [...sanzhihua];
console.log(sanyecao);

将伪数组转为真正的数组

const divs = document.querySelectorAll('div');
const divArr = [...divs];
console.log(divArr);

symbol

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值,是一种类似于字符串的数据类型

symbol特点

  • Symbol的值是唯一的,用来解决命名冲突问题;
  • Symbol值不能与其他数据进行运算
let s = Symbol();
let result1 = s + 100;//报错
let result2 = s + s;//报错
  • Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键明

创建symbol

//通过函数创建
let s = Symbol();
console.log(s,typeof s);//Symbol() 'symbol'

//通过函数创建并传入字符串
let s2 = Symbol('北京大学');
let s3 = Symbol('北京大学');
console.log(s2 === s3);//fasle;相当于两个人都叫张三,但是身份证号却不一样

//使用Symbol.for创建
let s4 = Symbol.for('北京大学');
let s5 = Symbol.for('北京大学');
console.log(s4,typeof s);//Symbol(北京大学) 'symbol'
console.log(s4 === s5)//true

使用Symbol.for创建可以通过描述字符串得到唯一的symbol值

使用场景

给对象添加属性和方法,表示独一无二的。

以下这种方法也可以,但是有一定的风险,我们不知道game对象中有没有up,有没有down;所以需要判断,就增加了复杂度

let game = {};
game.up = function(){
}

使用symbol:安全,高效

let game = {};

//声明一个对象
let methods = {
	up: Symbol(),
	down: Symbol()
}

game[method.up] = function(){
	console.log('我可以向上');
}

game[method.down] = function(){
	console.log('我可以向下');
}


let youxi = {
	name:'狼人杀',
	[Symbol('say')]:function(){
		console.log('我可以说话!');	
	},
	[Symbol('zibao')]:function(){
		console.log('我可以自爆!');	
	}
}

迭代器

迭代器是一个接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口(js中Iterator接口其实就是对象的属性:symbol.iterator),都可以完成遍历操作。

  • ES6创造了一种新的遍历命令 for … of循环,Iterator接口主要供for… of消费
  • 原生具备iterator接口的数据(可用for of遍历) Array Arguments Set Map String TypedArray NodeList
const xiyouji = ['唐僧','孙悟空','猪八戒','沙僧'];
for(let v of xiyou){
	console.log(v);//c,孙悟空,猪八戒,沙僧
}

for(let v of xiyou){
	console.log(v);//0,1,2,3
}

console.log(xiyou)//原型上有symbol.iterator属性,值为一个函数

let iterator = xiyou[Symbol.iterator]();//xiyou[Symbol.iterator]对应的是一个函数
console.log(iterator)//iterator 原型上有一个next的方法
console.log(iterator.next());//第一次调用对象的next方法指针自行指向数据结构的第一个成员{value:'唐僧',done:false}
console.log(iterator.next());//{value:'孙悟空',done:false} done表示是否完成
console.log(iterator.next());//{value:'猪八戒',done:false}
console.log(iterator.next());//{value:'沙僧',done:false}
console.log(iterator.next());//{value:'undefined',done:true} done为真表示遍历已完成

迭代器的工作原理

  • symbol.iterator对应的函数创建一个指针对象,指向当前数据结构的起始位置
  • 第一次调用对象的next方法,指针自行指向数据结构的第一个成员
  • 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
  • 每调用next方法返回一个包value和done属性的对象

生成器

生成器函数是ES6提供的一种异步编程解决方案,语法行为和传统函数不同
ES6之前:纯回调函数

生成器函数

  • 声明时需要加星号,星号在前,后,中间都可以,只要有就行
  • 不会直接输出结果,需要调用next函数
  • 在生成器函数中可以出现yield语句,yield相当于函数代码的分隔符
function *gen(){
	console.log('hello generator');
}
let iterstor = gen();
console.log(iterstor);//返回了一个迭代器对象gen{}

iterstor.next();//hello generator

function  *ken(){
	console.log(111);
	yield '一只没有耳朵',
	console.log(222);
	yield '一只没有尾巴',
	console.log(333);
	yield '真奇怪';
	console.log(444);
}
let iterstor2 = ken();
iterstor2.next();//111
console.log(iterstor2.next())//{value:'一只没有耳朵',done:false}
iterstor2.next();//222
console.log(iterstor2.next())//{value:'一只没有尾巴',done:false}
iterstor2.next();//333
console.log(iterstor2.next())//{value:'真奇怪',done:false}
iterstor2.next();//444
console.log(iterstor2.next())//{value:undefined,done:false}

生成器函数参数

  • 生成器函数接受到的参数,如果里面有输出语句也必须使用next方法才能打印
  • next方法也能传参,而且这个参数将作为上一个yield语句的返回结果
function * gen(arg){
   console.log(arg); //AAA
	let one = yield 111;
	console.log(one); //BBB
	let two = yield 222;
	console.log(two); //CCC
	let three = yield 333;
	console.log(three); //DDD
}

//执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next());//{value:111,done:false}
//next方法可以传入实参
console.log(iterator.next('BBB'));// {value:222,done:false}
console.log(iterator.next('CCC'));// {value:333,done:false}
console.log(iterator.next('DDD'));// {value:undefined,done:true}

Promise

Promise是ES6引入的异步编程的解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

promise对象的状态

一个 Promise对象有以下三种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled(resolved): 意味着操作成功完成。
  • rejected: 意味着操作失败。

promise基本语法

Promise接受一个参数,该参数为一个函数类型的值,该函数有两个形参:resolve,reject。分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数;resolve是将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected

new一个Promise对象

//实例化Promise对象
var p = new Promise(function(resolve, reject){
    //做一些异步操作
    setTimeout(function(){
        console.log('执行完成');
        resolve('随便什么数据');
    }, 2000);
});
console.log(p);

在这里插入图片描述
传入的是一个匿名函数,因此会立即执行。所以我们用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数,如:

function runAsync(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('执行完成');
            resolve('随便什么数据');
        }, 2000);
    });
    return p;            
}
runAsync()

执行这个函数我们得到了一个Promise对象,这个对象上有then、catch方法。then 表示异步成功执行后的数据状态变为reslove ;catch 表示异步失败后执行的数据状态变为reject 。all表示把多个没有关系的Promise封装成一个Promise对象使用then返回一个数组数据

调用该对象的.then方法,then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法),将相应的回调函数放入微任务(microtask)中

runAsync().then(function(data){
    console.log(data);//随便什么数据
});

因此,.then里面的函数就跟我们平时的回调函数是一个意思,能够在runAsync这个异步任务执行完成之后被执行。

下面是回调函数的写法:

function runAsync(callback){
    setTimeout(function(){
        console.log('执行完成');
        callback('随便什么数据');
    }, 2000);
}

runAsync(function(data){
    console.log(data);
});

如果有多层回调,比如callback也是一个异步操作,而且执行完后也需要有相应的回调函数,这样就势必会造成回调地狱。

promise的链式操作

function runAsync1(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务1执行完成');
            resolve('随便什么数据1');
        }, 1000);
    });
    return p;            
}
function runAsync2(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务2执行完成');
            resolve('随便什么数据2');
        }, 2000);
    });
    return p;            
}
function runAsync3(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务3执行完成');
            resolve('随便什么数据3');
        }, 2000);
    });
    return p;            
}
runAsync1()
.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return runAsync3();
})
.then(function(data){
    console.log(data);
});

这样能够按顺序,每隔两秒输出每个异步回调中的内容,在runAsync2中传给resolve的数据,能在接下来的then方法中拿到。运行结果如下:
在这里插入图片描述
相对应的回调函数的写法:

  function runAsync4(callback){
      callback();
   };
  runAsync4(function(){
    setTimeout(function(){
      console.log('异步任务1执行完成');
      console.log('随便什么数据1');
      setTimeout(function(){
        console.log('异步任务2执行完成');
        console.log('随便什么数据2');
        setTimeout(function(){
          console.log('异步任务3执行完成');
          console.log('随便什么数据3');
        }, 2000);
      }, 2000);
    }, 2000);
  })

promise的reject的用法

reject的作用就是把Promise的状态置为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调

getNumber函数用来异步获取一个数字,2秒后执行完成,如果数字小于等于5,我们认为是“成功”了,调用resolve修改Promise的状态。否则我们认为是“失败”了,调用reject并传递一个参数,作为失败的原因。

function getNumber(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            var num = Math.ceil(Math.random()*10); //生成1-10的随机数
            if(num<=5){
                resolve(num);
            }
            else{
                reject('数字太大了');
            }
        }, 2000);
    });
    return p;            
}

getNumber()
.then(
    function(data){
        console.log('resolved');
        console.log(data);
    }, 
    function(reason, data){
        console.log('rejected');
        console.log(reason);
    }
);

promise的catch用法

它和then的第二个参数一样,用来指定reject的回调,用法是这样:

getNumber()
.then(function(data){
    console.log('resolved');
    console.log(data);
})
.catch(function(reason){
    console.log('rejected');
    console.log(reason);
});

效果和写在then的第二个参数里面一样。不过它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。请看下面的代码:

getNumber()
.then(function(data){
    console.log('resolved');
    console.log(data);
    console.log(somedata); //此处的somedata未定义
})
.catch(function(reason){
    console.log('rejected');
    console.log(reason);
});

在resolve的回调中,我们console.log(somedata);而somedata这个变量是没有被定义的。如果我们不用Promise,代码运行到这里就直接在控制台报错了,不往下运行了。但是在这里,会得到这样的结果:

在这里插入图片描述

也就是说进到catch方法里面去了,而且把错误原因传到了reason参数中。即便是有错误的代码也不会报错了,这与我们的try/catch语句有相同的功能。

promise的all用法

Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。

Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});

用Promise.all来执行,all接收一个数组参数,里面的值最终都返回Promise对象。这样,三个异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面呢,all会把所有异步操作的结果放进一个数组中传给then,就是上面的results。所以上面代码的输出结果就是

在这里插入图片描述
有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据

promise的race用法

all方法的效果实际上是谁跑的慢,以谁为准执行回调,那么race方法谁跑的快,以谁为准执行回调;我们把上面runAsync1的延时改为1秒来看一下

Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});

1秒后runAsync1已经执行完了,此时then里面的就执行了
在这里插入图片描述
在then里面的回调开始执行时,runAsync2()和runAsync3()并没有停止,仍旧再执行。于是再过1秒后,输出了他们结束的标志。

race的使用场景

用race给某个异步请求设置超时时间,并且在超时后执行相应的操作

//请求某个图片资源
function requestImg(){
    var p = new Promise(function(resolve, reject){
        var img = new Image();
        img.onload = function(){
            resolve(img);
        }
        img.src = 'xxxxxx';
    });
    return p;
}

//延时函数,用于给请求计时
function timeout(){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('图片请求超时');
        }, 5000);
    });
    return p;
}

Promise
.race([requestImg(), timeout()])
.then(function(results){
    console.log(results);
})
.catch(function(reason){
    console.log(reason);
});

requestImg函数会异步请求一张图片,我把地址写为"xxxxxx",所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息。运行结果如下:
在这里插入图片描述

promise封装读取文件

//1.引入fs模块
const fs = require('fs');

// //2.调用方法读取文件
// fs.readFile('./为学',(err,data) =>{
//   //如果失败,则抛出错误
//   if(err) throw err;
//   //如果没有出错,则输出内容
//   console.log(data.toString());
// });

//使用Promise封装
const p = new Promise(function (resolve, reject) {
  fs.readFile('./为学',(err,data)=>{
    //如果失败就不能像上面一样抛出错误了,而是要改变Promise对象的一个状态,调用reject(err),
    // 通过调用reject,可以改变他的状态为失败,并且他失败的值是err这个错误对象
    if(err) reject(err)
    //如果成功,调用resolve,修改Promise的状态为成功,往里传参可以设置他成功的值
    resolve(data);
  })
})

p.then(function (value) {
  console.log(value.toString());
},function (reason) {
  console.log('读取失败');
})

Promise封装Ajax请求

Promise.prototype.then方法

const p = new Promise((resolve,reject) => {
		setTimeout(()=>{
			reject('出错啦');
		},1000)
	})

const result = p.then((value) => {
  console.log(value);
},reason=>{console.warn(reason);
})

console.log(result);

先打印出console.log(result); 一个Promise对象,再打印出console.warn(reason);出错啦,不仅仅因为1s的延迟,更是因为异步调用,浏览器主线程不会阻塞

上述代码可以.then方法返回一个promise对象,但是这个promise的状态是由回调函数的执行结果来决定的

  • 如果回调函数中返回的结果是非promise类型的数据,状态为成功,返回值为对象的成功值
const p = new Promise((resolve,reject) => {
		setTimeout(()=>{
			resolve('用户数据');
		},1000)
	})

const result = p.then((value) => {
  console.log(value);//用户数据
  return 123;//返回的是一个非promise类型的数据
},reason=>{console.warn(reason);
})

console.log(result);//promise对象

result为一个promise对象,并且点开后状态为成功[[PromiseStatus]]:'fulfilled';返回值为对象的成功值[[PromiseValue]]:123

如果没有return 123 ,没有return,默认返回结果为undefined,undefined并不是一个Promise对象,因此点开后状态为成功[[PromiseStatus]]:'fulfilled';返回值为对象的成功值[[PromiseValue]]:undefined

  • 如果是Promise,内部返回Promise的状态就决定then方法返回的Promise的状态
const p = new Promise((resolve,reject) => {
		setTimeout(()=>{
			resolve('用户数据');
		},1000)
	})

const result = p.then((value) => {
  console.log(value);//用户数据
  return new Promise((resolve,reject)=>{
  	resolve('ok');
  });//返回的是一个promise类型的数据
},reason=>{console.warn(reason);
})

console.log(result);//promise对象

result作为Promise对象,由于内部返回的是resolve,点开后状态为成功[[PromiseStatus]]:'fulfilled'值为[[PromiseValue]]:ok

const p = new Promise((resolve,reject) => {
		setTimeout(()=>{
			resolve('用户数据');
		},1000)
	})

const result = p.then((value) => {
  console.log(value);//用户数据
  return new Promise((resolve,reject)=>{
  	reject('error');
  });//返回的是一个promise类型的数据
},reason=>{console.warn(reason);
})

console.log(result);//promise对象

result作为Promise对象,由于内部返回的是reject,点开后状态为成功[[PromiseStatus]]:'rejected'值为[[PromiseValue]]:error

const p = new Promise((resolve,reject) => {
		setTimeout(()=>{
			resolve('用户数据');
		},1000)
	})

const result = p.then((value) => {
  console.log(value);//用户数据
  throw '出错啦!';
},reason=>{console.warn(reason);
})

console.log(result);//promise对象

点开后状态为成功[[PromiseStatus]]:'rejected'值为[[PromiseValue]]:出错啦!

Promise封装Ajax请求

const p = new Promise((resolve,reject)=>{
	// 1.创建对象
	const xhr = new XMLHttpRequest();
	// 2.初始化
	//发 GET类型的请求 给这个接口发请求https://api.apiopen.top/getJoke
	xhr.open("GET","https://api.apiopen.top/getJoke");
	// 3.发送
	xhr.send();
	// 4.绑定事件,处理响应结果
	xhr.onreadystatechange=function(){
		// 对状态做出一个判断
		if(xhr.readyState===4){
			// 判断响应状态码 200-300 2系列的响应状态码都为成功
			if(xhr.status >= 200 && xhr.status <= 300){
				// 表示成功 resolve修改promise的状态
				resolve(xhr.response);
			}else{
				// 如果失败
				reject(xhr.status);
			}
		}
	}
})

// 指定回调 结构清晰
p.then(function(value){
// 如果成功打印value
console.log(value);
},function(reason){
console.log(reason);
})

then方法的链式调用

p.then(value=>{},reason=>{}).then(value=>{},reason=>{})

then方法在指定回调的时候是可以只指定一个的

p.then(value=>{}).then(vale=>{})

Set集合

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator
接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法:

  • size返回集合的元素个数
  • add增加一个新元素,返回当前集合
  • delete删除元素,返回boolean值
  • has检测集合中是否包含某个元素,返回boolean值;
  • clear清空集合,返回undefined。
let s = new Set();
console.log(s,typeof s); //类型为object
let s2 = new Set(['大事儿','小事儿','好事儿','坏事儿','小事儿')];
console.log(s2);//自动去重['大事儿','小事儿','好事儿','坏事儿',]
//元素个数
console.log(s2.size);
//添加新的元素
s2.add('喜事儿');
console.log(s2)//('大事儿','小事儿','好事儿','坏事儿','小事儿','喜事儿');
//删除元素
s2.delete('坏事儿');
console.log(s2)//('大事儿','小事儿','好事儿','小事儿','喜事儿');
//检测
console.log(s2.has('糟心事'))//false
//清空
sw.clear();
console.log(s2)//{}

//使用for of遍历
for(let v of s2){
	console.log(v);
}

Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类
型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和
『for…of…』进行遍历;

// Map集合
// 创建一个空 map 
let m = new Map(); 
// 添加元素一
m.set('name','北京大学');
m.set('change',function(){console.log('我们可以改变你!')})
console.log(m);
//添加元素二:键为对象,值为数组
let key = {
	country:'中国'
};
m.set(key,['北京','上海''深圳']);
console.log(m);

//size:元素个数
console.log(m.size);//3

//delete 删除元素
m.delete('name');

//获取
console.log(m.get('change'));//function(){console.log('我们可以改变你!')};
console.log(m.get(key))//['北京','上海','深圳']

//清空
m.clear();

//遍历
for(let v of m){
	console.log(v);
}

class

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键
字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做
到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已;

ES6之前实例化对象

//手机
function Phone (brand,price){
	this.brand = brand;
	this.price = price;
}

//添加方法
Phone.prototype.call = function() {
	console.log('我可以打电话!');
}

//实例化对象
let Huawei = new Phone('华为',5999);
Huawei.call();
console.log(Huawei);

ES6之后通过类名来实例化对象

class Phone{
	//构造方法,名字不能修改
	constructor(brand,price){
		this.brand = brand;
		this.price = price;
	}
	call(){
		console.log('我可以打电话!');
	}
}
let onePlus = new Phone('1+',1999);
console.log(onePlus);

类的静态成员

function Phone(){

}
//构造函数本身也是一个对象,因此是可以往这个对象上面添加属性和方法
Phone.name = '手机';
Phone.change = function(){
	console.log('我可以改变世界');
}
//实例对象
let nokia = new Phone();
console.log(nokia.name)//undefined
nokia.change();//报错

从上述例子中可以看出实例对象是没有构造函数对象上的属性,也没有构造函数上的方法.因此函数对象是函数对象,实例对象是实例对象

那么,实例对象上的属性跟什么是相同的呢?

实例对象上的属性跟构造函数上的原型对象是相同的。

function Phone(){

}
//构造函数本身也是一个对象,因此是可以往这个对象上面添加属性和方法
Phone.name = '手机';
Phone.change = function(){
	console.log('我可以改变世界');
}
Phone.prototype.size = '5.5inch';
let nokia = new Phone();
console.log(nokie.size);//5.5inch

上面中的name,change属于构造函数这个对象.并不属于实例对象。在面向对象中这样的属性就称为 静态属性

而类似的在类中,某些属性属于类而不属于实例对象就称为class的静态成员。

class Phone{
	static name = '手机';
	static change(){
		console.log('我可以改变这个世界');
	}
}
let nokie = new Phone();
console.log(nokia.name);//undefined
console.log(Phone.name);//手机

类的继承

ES5中使用构造函数继承

function Phone (brand,price){
	this.brand = brand;
	this.price = price;
}

Phone.prototype.call = function() {
	console.log('我可以打电话!');
}

//智能手机
function SmartPhone(brand, price, color, size){
   //改变this值,此时this指向SmartPhone的实例
	Phone.call(this,brand,price);
	this.color = color;
	this.size = size;
}

//设置子集构造函数的原型:这样子级的实例对象就会有父级的方法
SmartPhone.prototype = new Phone;
//做一个矫正,不写也可
SmartPhone.prototype.constructor = SmartPhone;

//声明子类的方法
SmartPhone.prototype.photo = function(){
	console.log('我可以拍照');
}
SmartPhone.prototype.playGame= function(){
	console.log('我可以玩游戏');
}

const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch')
console.log(chuizi)

ES6类的继承

class Phone{
	constructor(brand,price){
		this.brand = brand;
		this.price = price;
	}
	
	//父类的成员属性
	call(){
		console.log('我可以打电话!!');
	}
};

class SmartPhone extends Phone {
	//构造方法
	constructor(brand,price,color,size){
		supper(brand,price);
		this.color = color;
		this.size = size;
	}
	phone(){
		console.log('拍照');
	}
	playGame(){
		console.log('玩游戏');
	}
}

const xiaomi = new SmartPhone('小米',799,'黑色','4.7inch');
console.log(xiaomi);

子类对父类方法的重写

在子类中声明一个同父类同名的方法,即重写

class Phone{
	constructor(brand,price){
		this.brand = brand;
		this.price = price;
	}
	
	//父类的成员属性
	call(){
		console.log('我可以打电话!!');
	}
};

class SmartPhone extends Phone {
	//构造方法
	constructor(brand,price,color,size){
		supper(brand,price);
		this.color = color;
		this.size = size;
	}
	phone(){
		console.log('拍照');
	}
	playGame(){
		console.log('玩游戏');
	}
	call(){
		console.log('我可以进行视频通话')
	}
}

const xiaomi = new SmartPhone('小米',799,'黑色','4.7inch');
console.log(xiaomi);
xiaomi.call();

这个时候子类是不可以调用父类的同名call方法

getter和setter设置

  1. get和set是方法,因为是方法,所以可以进行判断
  2. get一般是要返回的;而set是设置,不用返回
  3. get负责查询,不带任何参数;set负责设置,是通过参数的形式传递。
  4. 如果调用对象内部的属性约定的命名方式是变量名前加_
  5. 每一个对象都有一个get和set方法。
ES6之前:对象中getter和setter设置
var p={
  _age:18,
  get age(){    //Getter不能有任何形式的参数
   	return this._age;
  },
  set age(val){    //Setter必须恰好有一个形式参数
  	console.log(val);
  	this._age=val;
  }
}
p.age; // 18
p.age=20; // 20
p.age; // 20
ES6后:class中getter和setter设置
class Phone{
	get price(){
		console.log('价格属性被读取了');
		return 'iloveyou'//返回值就是price这个属性的值
	}
}
let s = new Phone();
console.log(s.price)//价格属性被读取了 iloveyou

如果不写get

class Phone{
	 price(){
		console.log('价格属性被读取了');
		return 'iloveyou'
	}
}
let s = new Phone();
console.log(s.price)

输出的是price这个函数

price(){
		console.log('价格属性被读取了');
		return 'iloveyou'//返回值就是price这个属性的值
	}

set:对属性进行赋值

class Phone{
	get price(){
		console.log('价格属性被读取了');
		return 'iloveyou'//返回值就是price这个属性的值
	}
	//使用set必须有一个参数
	set price(newVal){
		console.log('价格属性被修改了');
		console.log(newVal);//free
	}
}
let s = new Phone();
s.price //iloveyou
s.price = 'free'//价格属性被修改了

ES6的数值扩展

Number.EPSILON:

  • Number.EPSILON 是 JavaScript 表示的最小精度;
  • EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16;
  • 只要两个数的差值小于EPSILON的属性值就认为这两数相等

二进制和八进制:

  • ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示;

Number.isFinite() 与 Number.isNaN() :

  • Number.isFinite() 用来检查一个数值是否为有限的;
  • Number.isNaN() 用来检查一个值是否为NaN;

Number.parseInt() 与 Number.parseFloat():

  • ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变;

Math.trunc:

  • 用于去除一个数的小数部分,返回整数部分;

Number.isInteger:

  • Number.isInteger() 用来判断一个数值是否为整数;

Math.sign

  • Math.sign判断一个数到底为正数,负数,还是零。正数返回1,负数返回-1,0返回0

ES6对象方法扩展

ES6 新增了一些 Object 对象的方法:

  1. Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN);
  2. Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象;
  3. proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型;

ES6模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来;

模块化的好处:

模块化的优势有以下几点:

  1. 防止命名冲突;
  2. 代码复用;
  3. 高维护性;

模块化规范产品:

ES6 之前的模块化规范有:

  1. CommonJS => NodeJS、Browserify;
  2. AMD => requireJS;
  3. CMD => seaJS;

ES6 模块化语法:

模块功能主要由两个命令构成:export 和 import;

  • export 命令用于规定模块的对外接口(导出模块);
  • import 命令用于输入其他模块提供的功能(导入模块);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值