一:Let和const
(1)Let定义块级作用域的变量,var定义的变量会提升。Let不会提升。
如下。var可以先用,打印是undefined但是let在定义之前是不能用的。
会报错Uncaught ReferenceError: letter is not defined(…)
console.log(color)
console.log(letter)
var color = 'red';
let letter = 'a'
只要块级作用域内存在let命令,声明的变量不受外部影响。
var tmp = 123;
if (true) {
tmp = 'abc'; //tmp is not defined(…)
let tmp;
}
在代码块内,使用let命令声明变量之前,该变量都是不可用,称“暂时性死区”;
typeof x; //使用是在let声明之前x is not defined(…)
let x;
再如function bar(x = y, y = 1) {
return [x, y];
}
bar();// y is not defined(…)x的默认值等于y,此时y还没声明。
(2)通过var在块作用域中定义变量在外面可以访问,{}
通过let在块作用域中定义的变量,在外面不可以访问{}
if (true) {
// 块作用域里面都可以访问
var color = 'red';
let letter = 'a'
console.log(color) //可以访问
console.log(letter) //可以访问
}
console.log(color) //可以访问
console.log(letter) //不能访问 letter is not defined(…)
(3)let保存变量
var arr = []
for (var i = 0; i < 5; i++) {
arr[i] = function () {
console.log(i, 'iii')
}
}
arr[1]() //5,‘iii’
i是全局for循环外面也可以访问。For循环完之后i是5
var arr = [];
for (let j = 0; j < 5; j++) {
arr[j] = function () {
console.log(j, 'jjjj')
}
}
arr[1](); // 1,’iii’
这个函数的时候,会找到这个块作用域,这个作用域中定义了块作用域变量j
console.log(i, j) j是外面无法访问的。
(4):不允许重复声明
function () {
let a = 10;
var a = 1;
}
//Uncaught SyntaxError: Unexpected token (
function () {
let a = 10;
let a = 1;
}
//Uncaught SyntaxError: Unexpected token (
2:const
(1)定义之后再也无法修改 (大写,下划线)
var PI = Math.PI;
PI = 3;
console.log(PI) //3
const PI = Math.PI
PI = 3;
console.log(PI) // 报错Assignment to constant variable.(…)
(2)在块作用域中定义一个常量 块作用域内访问有效。外面是访问不到的
if (true) {
const PIa = Math.PI
}
console.log(PIa) //PIa is not defined(…)
(3)必须先定义再使用
console.log(PIa) //Identifier 'PI' has already been declared(…)
const PI = Math.PI;
二:模板字符串
使用反引号,直接写变量。
多行字符串,不再使用之前的+拼接字符串
例如:
name ="xiaomei"
age=4
之前:console.log("hello"+name+"my age is"+age)
ES6: console.log(`hello ${name} my age is ${age}`)
三:字符串的拓展方法
(1)startsWith 判断字符串是否以某个字符开头
可以传两个参数{第一个参数表示要判断的字符串,第二个参数表示判断的位置(不传参数表示整个字符串)}
注:截取的是字符串后面的部分
返回值是布尔值:true或者false
eg:
var str = '这是一个美好的传说';
var result = str.startsWith('传说', 7);
//result 为true
(2)endsWith 判断字符串是否以某个字符结尾
可以传两个参数{第一个参数表示要判断的字符串,第二个参数表示判断的位置(不传参数表示整个字符串)}
注:截取的是字符串前面的部分
返回值是布尔值:true或者false
eg:
var str = '这是一个美好的传说';
var result = str.startsWith('个', 4);
//result 为true
(3)includes 判断字符串是否包含一个字符串
可以传两个参数{第一个参数表示要判断的字符串,第二个参数表示判断的位置(不传参数表示整个字符串)}
注:截取的是字符串后面的部分
返回值是布尔值:true或者false
eg:
var str = '这是一个美好的传说';
var result = str.includes ('传说', 7);
//result 为true
(4)repeat 字符串的复写
参数是重复次数
eg:
let str = '这是一个美好的传说';
var result = str.repeat(2);
Console.log(result); //'这是一个美好的传说这是一个美好的传说'
(5)raw String的方法。获取原始字符串 里面转义字符不会被转义
注:标点符号 tab上面的那个``
var result = String.raw`你\n是一个\n好人`;
console.log(result)
// 你\n是一个\n好人
(6)模板字符串
语法是 ${书写表达式} ``支持多行字符串
eg:
var title = '你';
var str = `${title}是一个好人
啊`
console.log(str)
//你是一个好人
//啊
四:数值的拓展方法
(1)Number.isFinite() 用来检查一个数值是否为有限的(finite);
注:返回值为true表示有限 false表示无限
eg:
Number.isFinite(15);
true
Number.isFinite(0.8);
true
Number.isFinite(NaN);
false
Number.isFinite(Infinity);
false
Number.isFinite(-Infinity);
false
Number.isFinite('foo');
false
Number.isFinite('15');
false
Number.isFinite(true);
false
Number.isFinite(false);
False
(2)Number.isNaN() 检查一个值是否是NaN
注:返回值为true表示是NaN false表示不是NaN
eg:
Number.isNaN(NaN)
true
Number.isNaN(15)
false
Number.isNaN('15')
false
Number.isNaN(true)
false
Number.isNaN(9/NaN)
true
Number.isNaN('true'/0)
true
Number.isNaN('true'/'true')
True
(3)Number.isInteger() 检查一个值是否是整数
注:返回值为true表示是整数(.0会转化为整数) false表示不是整数
eg:
Number.isInteger(25)
true
Number.isInteger(25.0)
true
Number.isInteger(25.1)
false
Number.isInteger("15")
false
Number.isInteger(true)
False
(4) Number.parseInt() Number.parseFloat() 用法同es5
Eg:
es5用法
parseInt('12.34')
parseFloat('123.45#')
123.45
es6用法
Number.parseInt('12.34')
Number.parseFloat('123.45#')
123.45
Number.parseInt === parseInt
true
Number.parseFloat === parseFloat
true
五:Math对象的扩展
(1)Math.trunc() 去除一个数的小数部分,返回整数部分
注:对于非数值,先用Number().转成数值。对于无法截取整数的返回NaN
Eg:
Math.trunc(4.1)
Math.trunc(4.9)
Math.trunc(-4.1)
-4
Math.trunc(-4.9)
-4
Math.trunc(-0.1234)
-0
Math.trunc('123.456')
Math.trunc(NaN);
NaN
Math.trunc('foo');
NaN
Math.trunc();
NaN
(2)Math.sign() 判断一个数字是正数,负数,还是0;
只有5种结果
NaN传递一个非数字
0 传递的是一个正零(0)
-0 传递的是一个负零(-0)
1 传递的是一个正数(有理数和正无穷)
-1 传递的是一个负数(有理数负无穷等)
Eg:
Math.sign(-5)
-1
Math.sign(5)
Math.sign(0)
Math.sign(-0)
-0
Math.sign(NaN)
NaN
Math.sign('foo');
NaN
六:数组对象的扩展
(1) Array.from()
类数组,可以像数组一样访问成员,但是不能使用数组的方法
该方法将类数组对象转化为真正的数组
注:可以传两个参数:
第一个参数是类数组对象
第二个参数是处理函数(value,index,类数组对象,作用域是window,返回值构成from方法处理的结果的一个新数组)
<ul>
<li>1 1 1</li>
<li>2 2 2</li>
<li>3 3 3</li>
</ul>
var lis = document.getElementsByTagName('li');
console.log(lis[1]) //222
但是不能对lis执行forEach方法(类数组不能使用数组的方法)
lis.forEach(function () {
console.log(111)
})
转化:
var result = Array.from(lis);
查看是不是数组:
console.log(Array.isArray(result)) //true
console.log(result instanceof Array) //true
console.log(result.constructor === Array) //true
console.log(Object.prototype.toString.call(result) === '[object Array]') //true
var result = Array.from(lis, function (value, index) {
//value dom
value.innerHTML += '修改内容' + index;
return value;
})
console.log(result)
Eg:
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arrayLike);
console.log(arr2)
// ["a", "b", "c"]
(2) Array.of() 将一组值转化为数组(不论传递几个参数,得到得都是一个数组。数组的成员就是参数的成员)
var arr = Array.of()
console.log(arr) //[]
var arr = Array.of(5)
console.log(arr) //[5]
var arr = Array.of(5,6)
console.log(arr) //[5,6]
var arr = Array.of([5,6])
console.log(arr) //[Array[2]]
之前:
var arr = new Array();
console.log(arr); //[] 空数组 arr.lenght=0;
var arr = new Array(5);
console.log(arr); //[] 空数组 arr.lenght=5;
如果参数是一个非数字参数,得到结果是一个包含一个参数成员的数组
var arr = new Array([1,2,3]);
console.log(arr); //[[1,2,3]]
var arr = new Array(‘abc’);
console.log(arr); //["abc"]
var arr = new Array(‘12’);
console.log(arr); //["12"]
console.log(arr); //[] 空数组 arr.lenght=5;
var arr = new Array(5,6); 传递两个或者更多参数得到一个数组,数组的成员就是传递参数
console.log(arr); //[5,6]
(3) 数组实例的方法copyWithin()
当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。
接受三个参数:
target(必需):从该位置开始替换数据。
start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
Eg:
[1, 2, 3, 4, 5].copyWithin(0, 3)
//[4, 5, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
//[4, 2, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, -2, -1) 4表示-2 5表示-1
//[4, 2, 3, 4, 5]
(4) 数组实例的方法find()和findIndex();
find()获取数组成员 返回值是一个成员值 非贪婪搜索找到就停止
findIndex();获取数组成员索引值 返回值是一个索引值 非贪婪搜索找到就停止
都可以接受一个回调函数作为处理函数(value,index,原数组)作用域是window.返回值是判断条件。
Eg:
var arr = ['宋小宝', '小沈阳', '赵四', '刘能'];
var result = arr.find(function (value, index, arr) {
return value.indexOf('小') > -1;
})
console.log(result); //宋小宝
[1, 4, -5, 10].find((n) => n < 0)
-5
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
})
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
})
(5)数组实例的fill方法 使用给定值填充数组
用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。
(可以接受三个参数。填充值,起始位置,结束位置)
Eg:
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2) 从1开始到2之前
//["a", 7, "c"]
['a', 'b', 'c'].fill(7, 1, 3)
// ["a", 7, 7]
(6)数组实例的 includes()返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。
可以接受第二个参数,表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
Eg:
[1, 2, 3].includes(2)
// true
[1, 2, 3].includes(4)
// false
[1, 2, NaN].includes(NaN)
// True
[1, 2, 3].includes(3, 3);
// false
[1, 2, 3].includes(3, -1);
// True
[1, 2, 3].includes(3, -4);
// true
(7)数组实例的entries(),keys()和values()
这个三个方法返回的都是迭代器对象,可以用for...of循环进行遍历
或者手动调用遍历器对象的next方法,进行遍历。
Keys 表示获取数组中所有成员的索引值(键名)
Values 表示获取数组中所有成员的值(键值)
Entries 表示获取数组中所有成员与索引值组成数组对(键值对)
Eg:
var colors = ['red', 'green', 'blue'];
var keys = colors.keys();
console.log(keys); 迭代器对象
for (var index of keys) {
console.log(index)
}
// 0
// 1
// 2
var colors = ['red', 'green', 'blue'];
var entries = colors.entries();
for (var entry of entries) {
console.log(entry)
}
// [0, "red"]
// [1, "green"]
// [2, "blue"]
七:对象的拓展
a:Object.keys(),Object.values(),Object.entries()方法
const obj={name:"xiaomei",age:"18"};
console.log(Object.keys(obj))
//["name","age"]
console.log(Object.values(obj))
//["xiaomei","18"]
console.log(Object.entries(obj))
//[["name","xiaomei"],["age","18"]]
b:变量
const name="xiaomei";
const obj={
name
}
console.log(obj)
//{name: "xiaomei"}
c:...运算符合并对象合并对象
const obj1={name:"xiaomei",age:18};
const obj2={name:"xiaoli",age:19};
console.log({...obj1,...obj2});
//{name: "xiaoli", age: 19} 会覆盖
const obj1={name:"xiaomei",age:18};
const obj2={name:"xiaoli",ages:19};
console.log({...obj1,...obj2});
//{name: "xiaoli", age: 18, ages: 19}
const obj1={name:"xiaomei",age:18};
const obj2={name:"xiaoli",age:19};
console.log({...obj1,...obj2,date:"1.5"});
//{name: "xiaoli", age: 19, date: "1.5"}
d:结构赋值
const arr=["xiaomei","xiaoli"];
let arr1=arr[0];
let arr2=arr[1];
console.log(arr1,arr2);
//xiaomei xiaoli
let [arr1,arr2]=[arr]
console.log(arr1,arr2);
//["xiaomei", "xiaoli"]
const obj3={name:"xiaoli",ages:19};
const {name,ages}=obj3;
console.log(name,ages)
//xiaoli 19
(1) 如果属性的名称跟设置的变量名称相同,这个名称可以省略
在属性名称中可以使用表达式(表达式一定要用[]括起来)
如果方法的名称跟定义的方法名称相同,我们可以省略function(在定义类的时候一样定义方法)
Eg:
var color = 'red';
var title = '爱';
Es5:
var obj = {
color: color,
title: title
}
Es6:
function f(x, y) {
return {x, y};
}
f(1, 2)
// Object {x: 1, y: 2}
var obj = {color, title, num: 100}
// Object {color: "red", title: "爱", num: 100}
var color = 'red';
var title = '爱';
var obj = {
// 定义一个redgreen的属性
[color + 'green']: 200
}
console.log(obj);
// Object {redgreen: 200}
var color = 'red';
var title = '爱';
var obj = {
color,
getColor() {
return this.color;
}
}
console.log(obj)
console.log(obj.getColor())
// Object {color: "red"}
// red
function getPoint() {
var x = 1;
var y = 10;
return {x, y};
}
getPoint()
// Object {x: 1, y: 10}
(2)Object.is() 判断两个数据是不是同一个数据
ES5比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。
+0 === -0
//true
NaN === NaN
//false
Object.is('foo', 'foo')
//true
Object.is({}, {})
//false
Object.is(+0, -0)
//false
Object.is(NaN, NaN)
//true
(3)Object.assign()
将源对象(source)的所有可枚举属性,复制到目标对象(target)
第一个参数表示源对象(source),后面的参数表示目标对象
Object.assign(obj1, obj2, obj3)
注:是一个浅复制,只是对对象上的属性做简单copy而已
源对象中如果有相同的属性会被覆盖,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
Eg:
var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target);
// Object {a: 1, b: 2, c: 3}
var target = { a: 1, b: 1 };
var source1 = { b: 2, c: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target)
// Object {a: 1, b: 2, c: 3}
只有一个参数,Object.assign会直接返回该参数。
var obj = {a: 1};
Object.assign(obj) === obj
//true
(4)Symbol对象
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
symbol函数前不能使用new命令,否则会报错。因为生成的 Symbol 是一个原始类型的值,不是对象。
Eg:
let s = Symbol();
typeof s
// "symbol"
let s = new Symbol();
typeof s
// Identifier 's' has already been declared at
var s1 = Symbol('foo');
var s2 = Symbol('bar');
s1
// Symbol(foo)
s2
// Symbol(bar)
s1.toString()
// "Symbol(foo)"
s2.toString()
// "Symbol(bar)"
Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
var s1 = Symbol();
var s2 = Symbol();
s1 === s2
//false
var s1 = Symbol('foo');
var s2 = Symbol('foo');
s1 === s2
//false
用途:通常在定义对象属性的时候使用它,(此时对象的属性名就是一个独一无二的字符串),是为了防止重复属性被覆盖的。
var obj = {
color: 'red',
color: 'green'
}
console.log(obj)
// Object {color: "green"}
var key1 = Symbol('color');
var key2 = Symbol('color');
console.log(key1) //Symbol(color)
console.log(key2) //Symbol(color)
console.log(key2 == key1) false
var obj = {
[key1]: 'red',
[key2]: 'green'
}
console.log(obj[key1])
// red
八:函数的拓展
箭头函数:
a:基础语法
function hello(name){
console.log(`hello ${name} !`)
}
const helloa=(name)=>{
console.log(`hello ${name} !`)
}
hello('xiaomei')
helloa('xiaomei')
//hello xiaomei !
//hello xiaomei !
b:this问题
setTimeout(()=>{
console.log("aaa");
// this问题
},1000)
c: 一行省略(){}
const double= x => x*2
console.log(double(5));
//10
d:默认参数问题
const hello = (name = "xiaomei")=>{
console.log(`hello ${name} !`)
}
hello();
// hello xiaomei !
hello("xiaoli");
// hello xiaoli !
d:展开符...
function hello(name1,name2){
console.log(name1,name2);
}
let arr=["xiaomei","xiaoli"];
hello.apply(null,arr);
//xiaomei xiaoli
hello(...arr);
//xiaomei xiaoli
(1)在ES6之前,不能直接为函数的参数指定默认值
function log(x, y) {
y = y || 'World';
console.log(x, y);
}
log('Hello')
//Hello World
log('Hello', 'China')
//Hello China
log('Hello', '')
//Hello World
上面检查函数log的参数y有没有赋值,如果没有,则指定默认值为World。这种写法的缺点在于,如果参数y赋值了,但是对应的布尔值为false,则该赋值不起作用。就像上面代码的最后一行,参数y等于空字符,结果被改为默认值。
解决办法:
if (typeof y === 'undefined') {
y = 'World';
}
先判断再赋值
ES6可以为函数设置默认值,直接写在参数定义的后面
function say (msg = 'hello') {
console.log(msg)
}
say ()
// hello
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello')
//Hello World
log('Hello', 'China')
//Hello China
log('Hello', '')
//Hello
function Point(x = 0, y = 0) {
this.x = x;
this.y = y;
}
var p = new Point();
Log(p)
//Point {x: 0, y: 0}
如下参数变量是默认声明的,在函数体中,不能用let或const再次声明,否则会报错。
function foo(x = 5) {
let x = 1;
}
//Identifier 'x' has already been declared
function foo(x = 5) {
const x = 2;
}
//Identifier 'x' has already been declared
(2)Rest参数即剩余参数
用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
...语法可以实现对剩余参数的定义
注:在箭头函数中不能使用arguments
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3)
// 10
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
// 1
// 2
// 3
rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
function f(a, ...b, c) {
// ...
}
//Rest parameter must be last formal parameter
九:类的拓展
class App{
constructor(){
this.name="xiaomei"
}
sayhello(){
console.log(`hello ${this.name} !`)
}
}
const app=new App();
app.sayhello();
//hello xiaomei !
十:模块化机制
export const name = "xiaomei";
export function add(){
console.log("xiaoli");
}
export default function minus(){
console.log("xiaolis");
}
import { name , add } from './路径地址';
import minus from './路径地址';
console.log(name);
add();
minus();
//"xiaomei"
//"xiaoli"
//"xiaolis"
*导入文件中所有命名为exportobg
import * as exportobg from './路径地址';
十一:箭头函数详解
箭头函数是ES6中新增一个函数表达形式,它是对函数的一种简化ES6允许使用“箭头”(=>)定义函数。
Eg:
var f = v => v;
等同于之前
var f = function(v) {
return v;
};
const Even = n => n % 2 == 0;
const Square = n => n * n;
注:
箭头函数就是省略了function
参数集与函数体之间一定要有一个箭头=>
对于参数集而言:
零个参数用 () 表示;
一个参数可以省略 ();
多参数不能省略 ();
Eg:
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号。
Eg:
var getTempItem = id => ({ id: id, name: "Temp" });
[1,2,3].map(function (x) {
return x * x;
});
// [1, 4, 9]
[1,2,3].map(x => x * x);
//[1, 4, 9]
不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
const numbers = (...nums) => nums;
numbers(1, 2, 3, 4, 5)
// [1,2,3,4,5]
const haha = (head, ...tail) => [head, tail];
haha(1, 2, 3, 4, 5)
[1, Array[4]]
箭头函数有几个使用注意点。
(1) 箭头函数内部没有constructor方法,也没有prototype,所以不支持new操作。但是它对this的处理与一般的普通函数不一样。箭头函数的 this 始终指向函数定义时的 this,而非执行时。。
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 22 });
// id: 22
setTimeout的参数是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它的真正执行要等到100毫秒后。如果是普通函数,执行时this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 22}),所以输出的是22。
var o = {
x : 1,
func : function() { console.log(this.x) },
test : function() {
setTimeout(function() {
console.log(this);
this.func();
}, 100);
}
};
o.test();
//Window {external: Object, chrome: true, document: document, CNT_SELECT: undefined, jQuery17105021754387381239: Object…}
// this.func is not a function(anonymous function)
出现错误,因为this的指向从o变为了全局(函数调用中的this都是指向全局的)。
var o = {
x : 1,
func : function() { console.log(this.x) },
test : function() {
var _this = this;
setTimeout(function() {
_this.func();
}, 100);
}
};
o.test();
// 1
先保存的this就行了。
var o = {
x : 1,
func : function() { console.log(this.x) },
test : function() {
setTimeout(() => { this.func() }, 100);
}
};
o.test();
// 1
(2)this是不会改变指向对象的
var x = 1,
o = {
x : 10,
test : () => this.x
};
o.test();
// 1
o.test.call(o);
// 1
十二:Promise对象
$.ajax({
url: '......',
success: function (data) {
$.ajax({
// 要在第一个请求成功后才可以执行下一步
url: '......',
success: function (data) {
// ......
}
});
}
});
当执行一些异步操作时,我们需要知道操作是否已经完成,当执行完成的时候会返回一个回调函数,表示操作已经完成。 再继续进行下一个接口请求。。。。。
回调函数的形式在实际的应用当中会有以下的缺点:
在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观。
如果几个异步操作之间并没有前后顺序之分(例如不需要前一个请求的结果作为后一个请求的参数)时,同样需要等待上一个操作完成再实行下一个操作。
为了解决上述的问题,Promise 对象应运而生
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。一个允诺对象有三种状态,
Padding阶段 表示状态在进行
Resolved阶段 表示状态成功的结束
Rejected阶段 表示状态失败的结束
在允诺对象中只有两个两个执行的方向
一个是从padding状态进入resolved状态,表示异步操作成功执行完毕
一个是从padding状态进入rejected状态,表示异步操作失败执行完毕
Promise对象是一个构造函数,用来生成Promise实例。
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 Pending 变为 Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 Pending 变为 Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
then方法可以接受两个回调函数作为参数。
第一个回调函数是Promise对象的状态变为Resolved时调用,
第二个回调函数是Promise对象的状态变为Rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
允诺对象内部的状态不会受到外部的干扰,只有其内部改动才会改变状态
因此我们无法或者允诺对象当前处在哪个状态,
允诺对象一旦状态改变定义的允诺就会执行
Promise.all可以注册多个允诺对象,
当所有的允诺对象都执行成功时候会,成功回调函数才会执行
当遇到一个失败的就会立即执行失败的回调函数
function helloWorld (ready) {
return new Promise(function (resolve, reject) {
if (ready) {
resolve("Hello World!");
} else {
reject("Good bye!");
}
});
}
helloWorld(true).then(function (message) {
console.log(message);
}, function (error) {
console.log(error);
});
//Hello World!
helloWorld(true).then(function (message) {
console.log(message);
}, function (error) {
console.log(error);
helloWorld(false).then(function (message) {
console.log(message);
}, function (error) {
console.log(error);
});
// Good bye!
helloWord 函数接受一个参数,如果为 true 就打印 "Hello World!",如果为 false 就打印错误的信息。helloWord 函数返回的是一个 Promise 对象。
通过then方法可以定义诺言,两个参数
第一个参数定义成功时候的回调函数resolved状态
作用域是window
参数是执行resolve方法时候传递参数
第二个参数定义失败时候的回调函数rejected状态
作用域是window
参数是执行reject方法时候传递参数
Promise.all()
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
var p = Promise.all([p1, p2, p3]);
Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例