您好,登錄后才能下訂單哦!
★★代碼都是從上到下依次執行,寫在前面的先執行,別跳看!!一步一步的來!!
一、promise對象的使用
Promise處理的是一個異步問題
通常情況:回調函數是異步編程解決方案的一種
只要是回調函數,都可以改寫成promise寫法!
function send( url,callback ){
//var xhr =...
//...
callback(); //回調函數這么使用
}
send( 'url1',()=>{ //參數是一個回調函數
//do something
} )
Promise是一個構造函數,使用的時候需要new一下,Promise需要接收一個參數,這個參數是一個函數,并且該函數需要傳入2個參數resolve、reject,分別表示異步操作執行成功后的回調函數和異步操作執行失敗后的回調函數。
1.1、我們用Promise的時候一般是包在一個函數中,在需要的時候去運行這個函數,因為new promise的時候,傳入其中的函數會自動執行,所以我們需要控制其中的函數在需要的時候才去執行
1.2、對于Promise的then()方法,then總是會返回一個Promise實例,因此你可以一直調用then,then接收一個函數,函數接收2個參數resolve、reject
var p = new Promise( ()=>{
console.log('執行了'); //定義Promise對象的時候,一定要傳入一個函數,否則報錯,而且這個函數在創建Promise對象的時候聚立即執行了。 此時Promise對象的狀態是pending
} )
//傳入參數resolve,reject,執行 resolve();就把Promise變成成功的狀態了;執行 reject();就把Promise變成失敗的狀態了
var p = new Promise( (resolve,reject)=>{
//這里面可以執行別的自定義方法,不一定只能是resolve或者reject,在自定義方法里面,設置什么時候執行resolve,什么時候執行reject,下面使用catch捕捉reject
console.log(1); //執行到這里,下面馬上把promise變為成功狀態
resolve(); //把Promise變成成功的狀態
} )
var p = new Promise( (resolve,reject)=>{ //內部有三種狀態,pending、resolve、reject
return resolve("成功"); //進入成功執行的代碼 一般會加個return,阻止后續代碼的執行
reject(); //進入執行失敗的代碼 resolve與reject二者只會執行前一個,后者不會執行,但是后續的代碼還會繼續執行;resolve(data)有參數,then用data接收,reject(err)也有參數,catch用err接收
console.log(); //會繼續執行到這里
} )
p.then( (data)=>{ //這里的data接收上面resolve傳入的"成功"字符串
console.log("then:"+data);
} )
1.3、then方法是一個實例方法,建立在返回p實例的基礎上
then( ()=>{ //then接收一個函數,函數接收2個參數,前者是上面進入成功狀態執行,后者是上面進入失敗狀態執行
console.log('成功') //上面的resolve()時進入這里
},()=>{ //上面的reject()時進入這里
console.log('失敗')
} )
tips、但是一般不使用上面的寫法
p.then( (data)=>{ //then默認返回成功狀態
console.log(data); //成功
} ) //成功狀態時進入
p.catch( ()=>{
console.log("失敗");
} ) //失敗狀態時進入
var p = new Promise( (resolve,reject)=>{
resolve("成功");
} )
var p2 = p.then( ()=>{} ); //執行完返回的promise是成功的狀態,p2.then走成功resolve()方法
//這里沒有返回值,就相當于return undefined,返回undefined
var p2 = p.then( ()=>{
return "非promise對象" //執行完返回的promise也是成功的狀態
} )
后續鏈式調用then方法,返回的是一個Promise對象,這個返回的Promise對象的狀態是成功還是失敗,取決于then方法內部的代碼,如果內部代碼返回的是非Promise對象,無論是有值還是undefined,都是resolve(),否則,如果內部返回的是Promise對象,那么如果該返回的Promise對象是reject,那么then返回的是reject,否則就是resolve
1.4、catch方法
catch相當于then的第二個參數
var p = new Promise( (res,rej)=>{
res('成功');
} )
p.then( ()=>{
console.log( 1 )
} ).then( ()=>{
console.log( 2 )
} ).catch( (err)=>{ //捕捉失敗
console.log(err)
} ).finally( ()=>{ //匿名函數里面沒有參數了,不管執行了成功還是失敗,這里都會執行到
console.log('執行完畢');
} )
console.log('這兒的代碼仍然能執行');
//執行了catch方法,捕捉錯誤,不會影響后續代碼的執行
=====等價于======
var p = new Promise( (res,rej)=>{
res('成功');
} )
let res = p.then( ()=>{ //執行完then,永遠都返回promise對象,成功還是失敗取決于返回的類型,成功繼續走then,失敗走catch
console.log( 1 )
} ).then( ()=>{
console.log( 2 )
} )
res.catch( (err)=>{ //捕捉失敗
console.log(err)
} ).finally( ()=>{ //匿名函數里面沒有參數了,不管執行了成功還是失敗,這里都會執行到
console.log('執行完畢');
} )
console.log('這兒的代碼仍然能執行');
//執行了catch方法,捕捉錯誤,不會影響后續代碼的執行
p.then(data)里面的data接收的是上面resolve()里面傳入的值
1.5、Promise靜態方法
一個成功
p.then( ()=>{ console.log(1)} )
.then( ()=>{ return new Promise( (res,rej)=>{return res(400)} ) } )
.then( ()=>{ return Promise.resolve(400) } ) //兩種寫法一樣
.then( (data)=>{console.log(data)} ) //400
一個失敗
p.then( ()=>{ console.log(1)} )
.then( ()=>{ return new Promise( (res,rej)=>{return rej(400)} ) } )
.then( ()=>{ return Promise.reject('失敗!') } ) //兩種寫法一樣
.catch( (err)=>{console.log(err)} ) //失敗!
//all方法:合并所有的promise對象,返回所有promise全部執行完之后的結果
let p1 = new Promise(()=>{ setTimeout(()=>{ res('a') },500) })
let p2 = new Promise(()=>{ setTimeout(()=>{ res('b') },500) })
let p3 = new Promise(()=>{ setTimeout(()=>{ res('c') },500) })
var p = Promise.all( [p1,p2,p3] );
p.then( (data)=>{ console.log(data) } ) //獲取所有的promise完成之后的數據,保存為一個數組 ['a','b','c']
//race方法:返回所有promise中最先執行完的那個的結果
var p = Promise.race( [p1,p2,p3] );
p.then( (data)=>{ console.log(data) } ) //獲取所有的promise中最先完成的那個數據
案例:
let p = new Promise((resolve,reject)=>{
resolve('成功');
})
p.then((data)=>{
console.log(data); //成功
})
console.log(p); //Promise?{<resolved>: "成功"}
new Promise((resolve,reject)=>{
resolve('成功啊啊啊');
})
.then((data)=>{
console.log(data); //成功啊啊啊
})
let box = document.getElementById("box");
function movePromise(obj,attr,target,duration){
return new Promise((res,rej)=>{
let b = parseInt(getComputedStyle(obj)[attr]); //obj沒有引號,attr是字符串類型
let c = target - b ;
let d = duration;
let temp = new Date().getTime();
let timer = setInterval(function(){
let t = new Date().getTime() - temp;
if(t >= d){
clearInterval(timer);
t = d;
}
let v = c/d*t + b;
obj.style[attr] = v + 'px';
if(t === d){
res();
}
},20)
})
}
movePromise(box,"width",200,500)
.then( (res,rej)=>{
movePromise(box,"height",300,500)
} )
//這里面不是直接promise后接著執行then,而是promise外面的函數來執行then方法,所以里面的peomise需要加上return了,讓外面的函數執行完畢之后返回一個promise對象
雖然promise會默認返回一個promise,但是需要return出來,才能讓外面的函數接著執行then方法
二、定義變量:var、let聲明變量,const聲明常量
1、var聲明的變量支持預解析(變量提升),let不支持
var a = 1;
console.log(a); //1
var c;
console.log(c); //undefined,先聲明未賦值,值為undefined,沒有保錯
console.log(d); //undefined,預解析(變量提升),值為undefined,沒有保錯
var d;(var d = 2;)都是輸出undefined
let e;
console.log(e); //undefined,先聲明未賦值,值為undefined,沒有保錯
console.log(f); //Uncaught ReferenceError: f is not defined,報錯
let f;
console.log(g); //Uncaught ReferenceError: g is not defined,報錯
let g = 1;
let b = 2;
console.log(b); //2,正確輸出
2、var可以重復聲明,后面的值會覆蓋前面的,let不能重復聲明,會報錯
var x = 1;
var x = 2; //2
let m = 1;
let m = 100; //Uncaught SyntaxError: Identifier 'm' has already been declared,報錯
3、let支持塊級作用域,塊級作用域內的變量外部訪問不到,但是var可以,(內部二者都可以訪問到)
{
var a = 1;
console.log(a); //1
}
console.log(a); //1
{
let a = 1;
console.log(a); //1
}
console.log(a); //Uncaught ReferenceError: a is not defined
4、const聲明常量
const聲明一個常量之后,不可修改,
和let一樣,不可重復聲明,不支持預解析,支持塊級作用域
let和var可以只聲明,不賦值;const不可以,聲明的同時必須進行賦值
三、函數聲明
1、JS中常見的兩種函數聲明(statement)方式有這兩種:
// 函數表達式(function expression)
h(); //報錯
var h = function() {
// h
}
h(); //正確
m(); //正確
// 函數聲明(function declaration)
function m() {
//m
}
m(); //正確
2、總結
四、解構賦值
1、數組的解構賦值
和對象差不多,嚴格按照數組下標來取值
let arr = [1,2,3];
let [a,b,c] = arr
console.log(a,b,c); // 1 2 3
let [a,,c] = arr;
console.log(a,c); // 1 3
let [a,,c,d=4] = arr; //支持賦默認值
console.log(a,c,d); //1 3 4
let [a,...rest] = arr;
console.log(a,rest); //1 (2)?[2, 3]
2、字符串的解構賦值
3、對象的解構賦值
let obj = {
name:'leo',
age:20,
b:1,
move:function(){
console.log(1)
}
}
let {name,age} = obj;//聲明的同時解構賦值,{}里的變量名必須和obj里面的變量名一致
console.log(name,age); //leo 20
★對象的結構賦值,可以只取對象中的某一個屬性,不是必須一次性全部取出來
let {name} = obj;
console.log(name); //20
//可以解構賦值取別名
let { name : str } = obj;
console.log(str) //leo
console.log(name) //無值
//可以賦默認值,obj里面沒有該屬性則取賦的默認值,有屬性則取obj里面的值
let { name = 'xx' } = obj;
console.log(name) //leo
let { c = 'xx' } = obj;
console.log(c) //xx
//...取剩余的元素,歸到一個數組里
let {b,...r} = obj;
console.log(b,r); //1 {name: "leo", age: 20, move: ?}
五、擴展運算符...與rest運算符...
1、擴展運算符
1.1、用三個點號表示,功能是把數組或類數組對象展開成一系列用逗號隔開的值
var foo = function(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
var arr = [1, 2, 3];
//傳統寫法
foo(arr[0], arr[1], arr[2]);
//使用擴展運算符
foo(...arr); //這里面的arr就可以看作,獲取到了arr里面所有的值了
//1
//2
//3
1.2、特殊應用場景:
//數組深拷貝
var arr2 = arr;
var arr3 = [...arr];
console.log(arr===arr2); //true, 說明arr和arr2指向同一個數組
console.log(arr===arr3); //false, 說明arr3和arr指向不同數組
//把一個數組插入另一個數組字面量
var arr4 = [...arr, 4, 5, 6];
console.log(arr4);//[1, 2, 3, 4, 5, 6]
//字符串轉數組
var str = 'love';
var arr5 = [...str];
console.log(arr5);//[ 'l', 'o', 'v', 'e' ]
2、rest運算符
2.1、rest運算符也是三個點號,不過其功能與擴展運算符恰好相反,把逗號隔開的值序列組合成一個數組
//主要用于不定參數,所以ES6開始可以不再使用arguments對象
var bar = function(...args) {
for (let el of args) {
console.log(el);
}
}
bar(1, 2, 3, 4);
//1
//2
//3
//4
bar = function(a, ...args) {
console.log(a);
console.log(args);
}
bar(1, 2, 3, 4);
//1
//[ 2, 3, 4 ]
2.2、rest運算符配合解構使用:
var [a, ...rest] = [1, 2, 3, 4];
console.log(a);//1
console.log(rest);//[2, 3, 4]
小結:
等號表達式是典型的賦值形式,函數傳參和for循環的變量都是特殊形式的賦值。解構的原理是賦值的兩邊具有相同的結構,就可以正確取出數組或對象里面的元素或屬性值,省略了使用下標逐個賦值的麻煩。
一點經驗:
let arr1 = [1,2,3];
let arr2 = arr1.map((value,key,arr) => {
console.log(value) // 1,2,3
console.log(key) // 0,1,2
console.log(arr) //[1,2,3] [1,2,3] [1,2,3]
return value * value;
})
console.log(arr1); // [ 1, 2, 3 ]
console.log(arr2); // [ 1, 4, 9 ] //返回一個新的數組,如果在forEach里面使用return,則沒有這個效果
filter函數可以看成是一個過濾函數,返回符合條件的元素的數組
filter需要在循環的時候判斷一下是true還是false,是true才會返回這個元素;
let arr1 = [1,2,3];
let arr2 = arr1.filter((value,key,arr) => {
console.log(value) // 1,2,3
console.log(key) // 0,1,2
console.log(arr) // [1,2,3]
return value >= 3 ? false : true;
})
console.log(arr1); // [ 1, 2, 3 ]
console.log(arr2); // [ 1, 2 ]
some()方法
Array.some(function( item ){})
七、Object.assign
Object.assign是ES6新添加的接口,主要的用途是用來合并多個JavaScript的對象。
Object.assign()接口可以接收多個參數,第一個參數是目標對象,后面的都是源對象,assign方法將多個原對象的屬性和方法都合并到了目標對象上面,如果在這個過程中出現同名的屬性(方法),后合并的屬性(方法)會覆蓋之前的同名屬性(方法)。
assign的基本用法如下:
var target = {a : 1}; //目標對象
var source1 = {b : 2}; //源對象1
var source2 = {c : 3}; //源對象2
var source3 = {c : 4}; //源對象3,和source2中的對象有同名屬性c
var obj = Object.assign(target,source1,source2,source3);
//結果如下:
//{a:1,b:2,c:4}
1、Object.assign進行的拷貝是淺拷貝。也就是說,如果拷貝過來的屬性的值是對象等復合屬性,那么只能拷貝過來一個引用。
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
由于是淺拷貝,拷貝的是引用,obj1的值改變,obj2的屬性值也會隨之改變
2、Object.assign進行合并的時候,一旦碰到同名屬性,就會出現覆蓋現象。所以使用時務必小心。
3、Object.assign是針對Object開發的API,一旦在源對象的參數未知接收到了其他類型的參數,會嘗試類型轉換。如果是數組類型的話,類型轉換的結果是將每個數組成員的值作為屬性鍵值,將數組成員在數組中的位置作為屬性鍵名。多個數組組成參數一同傳入的話還會造成覆蓋。具體例子如下:
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
上面代碼中,assign把數組視為屬性名為 0、1、2 的對象,因此源數組的 0 號屬性4覆蓋了目標數組的 0 號屬性1。
4、Object.assign只能將屬性值進行復制,如果屬性值是一個get(取值函數)的話,那么會先求值,然后再復制。
// 源對象
const source = {
//屬性是取值函數
get foo(){return 1}
};
//目標對象
const target = {};
Object.assign(target,source);
//{foo ; 1} 此時foo的值是get函數的求值結果
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。