做用域就是變量的做用範圍。也就是你聲明一個變量之後,這個變量能夠在什麼場合下使用。之前的JavaScript只有全局做用域,和函數做用域。javascript
1.var 沒有塊級做用域,定義後在當前包中都均可以訪問,若是變量名重複,就會覆蓋前面定義的變量,而且很能夠被他人修改。css
if(true){
var a = "a"; //指望a是某一個值
}
console.log(a);
複製代碼
2.var 在for循環標記變量共享,通常在循環中會使用的i會被共享,其本質也是因爲沒有塊級做用域形成的
html
for (var i = 0; i < 3; i++) {
setTimeout(function () {
alert(i);
}, 0);
}
// 結果就是 彈窗三次 3
for ( i = 0; i < 3; i++) {
setTimeout(function () {
alert(i);
}, 0);
}
// 結果就是 彈窗三次 0-2
複製代碼
在用var定義變量的時候,變量經過閉包進行隔離的,如今用了let,不只僅能夠經過閉包隔離,還能夠增長了一些塊級做用域隔離。塊級做用用一組大括號定義一個快,使用let定義的變量字啊大括號的外面是訪問不到的。java
if(ture){
let name = 'wjh'
}
consloe.log('name'); // ReferenceError: name is not defined
複製代碼
if(ture){
let name = 'wjh'
}
console.log(window.name); // undefined
複製代碼
// 嵌套循環不會相互影響
for (let i = 0; i < 3; i++) {
console.log("out", i);
for (let i = 0; i < 2; i++) {
console.log("in", i);
}
}
// 結果 out 0 in 0 in 1 out 1 in 0 in 1 out 2 in 0 in 1
複製代碼
if(ture){
let a = 1;
let a = 2; //Identifier 'a'
}
複製代碼
for(let i = 0;i<2;i++){
console.log('inner',i);
let i =100;
}
// 結果 i is not defined
複製代碼
;(function(){
})();
複製代碼
如今git
{
}
複製代碼
使用 const 咱們能夠聲明一個常量,一旦聲明以後,就不能夠更改。github
const MY_NAME = 'wjw';
MY_NAME = 'wjw2';//Assignment to constant variable
複製代碼
注意const限制的是不能給變量從新賦值,而變量的值自己是能夠改變的,下面的操做是能夠的ajax
const names = ['wjw1'];
names.push('wjw2');
console.log(names);
複製代碼
const A = "0";
{
const A = "A";
console.log(A)
}
{
const A = "B";
console.log(A)
}
console.log(A)
// 結果 A B 0
複製代碼
解構意思就是分解一個東西的結構,能夠用一種相似數組的方式定義N個變量,能夠將一個數組中的值按照規則賦值過去。
npm
var [name,age]=['wjh',8];
console.log(name,age);
複製代碼
let [x,[y],z]=[1,[2.1]];
console.log(x,y,z);
let [x,[y,z]] = [1,[2.1,2.2]];
console.log(x,y,z);
let [json,arr,num] = [{name:'wjw'},[1,2],3];
console.log(json,arr,num);
// 1 2.1 undefined 1 2.1 2.2 { name: 'wjw' } [ 1, 2 ] 3
複製代碼
let [,,x]=[1,2,3]
console.log(x);
複製代碼
對象也能夠被解構json
var obj = {name:'wjw',age:8};
//對象裏的name屬性的值會交給name這個變量,age的值會交給age這個變量
var {name,age} = obj
//對象裏的name屬性的值會交給myname這個變量,age的值會交給myage這個變量
let {name: myname, age: myage} = obj;
console.log(name,age,myname,myage);
複製代碼
在賦值和傳參的時候可使用默認值bootstrap
let [a='a',b='b',c=new Error('C必須指定')] = [1, , 3];
console.log(a,b,c);
function ajax(options){
var method = options.method || "get";
var data = options.data || {};
}
function ajax(method='get',data){
console.log(arguments);
}
ajax({
method:'post',
data:{'name':'wjh'}
})
複製代碼
模板字符串用反應號(數字1左邊的那個建)包含,用${}
括起來
var name = 'wjw',age = 8;
let desc = `${name} is ${age} old!`;
console.log(desc);
//全部模板字符串的空格和換行,都是被保留的
var str = `<ul> <li>a</li> <li>b</li> </ul>`;
console.log(str);
複製代碼
其中的變量會用變量的值替換掉
function replace(desc){
return desc.replace(/\$\{([^}]+)\}/g,function(matched,key){
return eval(key);
});
}
複製代碼
能夠在模板字符串的前面添加一個標籤,這個標籤能夠去處理模板字符串 標籤其實就是一個函數,函數能夠接收兩個參數,一個是 strings 就是模板字符串裏的每一個部分的字符 還有一個參數可使用rest的形式values,這個參數裏面是模板字符串裏的值。
var name = 'wjh',age = 8;
function desc(strings,...values){
console.log(strings,values);
}
desc`${name} is ${age} old!`;
複製代碼
字符串新方法
var s = 'wjh';
s.startsWith('w') // true
s.endsWith('h') // true
s.includes('j') // true
複製代碼
第二個參數,表示開始搜索的位置
var s = 'wjh';
console.log(s.startsWith('j',2)); // true
console.log(s.endsWith('j',2)); // true
console.log(s.includes('j',2)); // false
複製代碼
endsWith的行爲與其餘其餘方法有所不一樣。它針對前n個字符,而其餘方法是從第幾位開始到字符串結束
repeat 方法返回一個新字符串,表示將原字符串重複n次。
'x'.repeat(3);
'x'.repeat(0);
複製代碼
能夠給定義的函數接收的參數設置默認的值 在執行這個函數的時候,若是不指定函數的參數的值,就會使用參數的這些默認的值。
function ajax(url,method='GET',dataType="json"){
console.log(url);
console.log(method);
console.log(dataType);
}
複製代碼
把...放在數組前面能夠把一個數組進行展開,能夠把一個函數而不須要使用apply
//傳入參數
let print = function(a,b,c){
console.log(a,b,c);
}
print([1,2,3]);
print(...[1,2,3]);
// 能夠替代apply
var m1 = Math.max.apply(null, [8, 9, 4, 1]);
var m2 = Math.max(...[8, 9, 4, 1]);
// 能夠替代concat
var arr1 = [1, 3];
var arr2 = [3, 5];
var arr3 = arr1.concat(arr2);
var arr4 = [...arr1, ...arr2];
console.log(arr3,arr4);
//類數組的轉數組
function max(a,b,c) {
console.log(Math.max(...arguments));
}
max(1, 3, 4);
複製代碼
剩餘操做符能夠把其他參數的值放在一個叫作b的數組裏
let rest = function(a,...rest){
console.log(a,rest);
}
rest(1,2,3);
複製代碼
let destruct = function({name,age}){
console.log(name,age);
}
destruct({name:'wjh',age:10})
複製代碼
箭頭函數簡化了函數的定義方式
[1,2,3].forEach(val=>console.log(val));
複製代碼
輸入參數若是多於一個要用()包含,函數體若是有多條語句須要用{}包起來
箭頭函數根本沒有本身的this,致使內部的this就是外層代碼塊的this。 正是由於它沒有this,從而避免了this指向的問題。
var person = {
name:'wjh',
getName:function(){
- setTimeout(function(){console.log(this);},1000); //在瀏覽器執行的話this指向window
+ setTimeout(() => console.log(this),1000);//在瀏覽器執行的話this指向person
}
}
person.getName();
複製代碼
// 相同的陣列
var people = [
{
name : 'Casper' ,
like : '鍋燒意麪' ,
age : 18
},
{
name : 'Wang' ,
like : '炒麪' ,
age : 24
},
{
name : 'Bobo' ,
like : '蘿蔔泥' ,
age : 1
},
{
name : '滷蛋' ,
like : '蘿蔔泥' ,
age : 3
}
];
複製代碼
filter() 會回傳一個陣列,其條件是return 後方爲true 的物件,很適合用在搜尋符合條件的資料。
var filterEmpty = people.filter( function ( item, index, array ) {
});
console.log(filterEmpty); //沒有條件,會是一個空陣列
var filterAgeThan5 = people.filter( function ( item, index, array ) {
return item.age > 5 ; //取得大於五歲的 若是這邊符合條件 只要爲ture便可
});
console .log(filterAgeThan5); // Casper, Wang這兩個物件
複製代碼
find()與filter()很像,但find() 只會回傳一次值,且是第一次爲true的值。
var findEmpty = people.find( function ( item, index, array ) {
});
console .log(findEmpty); //沒有條件,會是undefined
var findAgeThan5 = people.find( function ( item, index, array ) {
return item.age > 5 ; //取得大於五歲的
});
console .log(findAgeThan5); //雖然答案有兩個,但只會回傳Casper這一個物件
var findLike = people.find( function ( item, index, array ) {
return item.like === '蘿蔔泥' ; //取得陣列like === '蘿蔔泥'
});
console .log(findLike); //雖然答案有兩個,但只會回傳第一個Bobo物件
複製代碼
forEach 是這幾個陣列函式最單純的一個,不會額外回傳值,只單純執行每一個陣列內的物件或值。
var forEachIt = people.forEach( function ( item, index, array ) {
console .log(item, index, array); //物件,索引,所有陣列
return item; // forEach沒在return的,因此這邊寫了也沒用
});
console .log(forEachIt); // undefined
people.forEach( function ( item, index, array ) {
item.age = item.age + 1 ; // forEach就如同for,不過寫法更容易
});
console .log(people); //所有age + 1
複製代碼
使用map() 時他須要回傳一個值,他會透過函式內所回傳的值組合成一個陣列。 若是不回傳則是 undefined 回傳數量等於原始陣列的長度 這很適合將原始的變數運算後從新組合一個新的陣列。
var mapEmpty = people.map( function ( item, index, array ) {
});
console .log(mapEmpty); // [undefined, undefined, undefined, undefined]
var mapAgeThan5 = people.map( function ( item, index, array ) {
return item.age > 5 ; //比較大於五歲的
});
console .log(mapAgeThan5); // [true, true, false, false]
var mapAgeThan5_2 = people.map( function ( item, index, array ) {
// 錯誤示範
if (item.age > 5 ) {
return item; //回傳大於五歲的
}
return false ; //別覺得空的或是false就不會回傳
});
console .log(mapAgeThan5_2); // [{name: 'Casper'...}, {name: 'Wang'...}, false, false]
var mapEat = people.map( function ( item, index, array ) {
if (item.like !== '蘿蔔泥' ) {
return ` ${item.like}好吃` ;
} else {
return ` ${item.like}很差吃` ;
}
});
console .log(mapEat); // ["鍋燒意麪好吃", "炒麪好吃", "蘿蔔泥很差吃", "蘿蔔泥很差吃"]
複製代碼
every()能夠檢查全部的陣列是否符合條件,這僅會回傳一個值trueor false,能夠用來檢查陣列中的內容是否符合特定條件。
var ans = array.every( function ( item, index, array ) {
console .log(item, index, array); //物件,索引,所有陣列
return item.age > 10 //當所有age大於10才能回傳true
});
console .log(ans); // false:只要有部分不符合,則爲false
var ans2 = array.every( function ( item, index, array ) {
return item.age < 25
});
console .log(ans2); // true:所有age都小於25
複製代碼
some() 與every() 很是接近,都是回傳true or false,差別僅在every() 需徹底符合,some() 僅須要部分符合。
var ans = people.some( function ( item, index, array ) {
return item.age > 10 //當所有age大於10才能回傳true
});
console .log(ans); // true:只要有部分符合,則爲true
var ans2 = people.some( function ( item, index, array ) {
return item.age < 25
});
console .log(ans2); // true:只要有部分符合,則爲true
var ans2 = people.some( function ( item, index, array ) {
return item.age > 25
});
console .log(ans2); // false:所有都不符合則爲false
複製代碼
reduce() 和其餘幾個差別就很大了,他能夠與前一個回傳的值再次做運算,參數包含如下: accumulator: 前一個參數,若是是第一個陣列的話,值是以另外傳入或初始化的值 currentValue: 當前變數 currentIndex: 當前索引 array: 所有陣列
var reduceEmpty = people.reduce( function ( accumulator, currentValue, currentIndex, array ) {
});
console .log(reduceEmpty); //沒有條件,會是undefined
var reducePlus = people.reduce( function ( accumulator, currentValue, currentIndex, array ) {
// 分別爲前一個回傳值, 目前值, 當前索引值
console .log(accumulator, currentValue, currentIndex);
return accumulator + currentValue.age; //與前一個值相加
}, 0 ); //傳入初始化值爲0
console .log(reducePlus); //總和爲46
var reducePlus = people.reduce( function ( accumulator, currentValue, currentIndex, array ) {
console .log( 'reduce' , accumulator, currentValue, currentIndex)
return Math .max( accumulator, currentValue.age ); //與前一個值比較哪一個大
}, 0 );
console .log(reducePlus); //最大值爲24
複製代碼
若是你想在對象裏添加跟變量名同樣的屬性,而且屬性的值就是變量表示的值就能夠直接在對象里加上這些屬性
let name = 'wjh';
let age = 8;
let getName = function(){
console.log(this.name)
}
let person ={
name,
age,
getName
}
person.getName();
複製代碼
對比兩個值是否相等
console.log(Object.is(NaN,NaN));
複製代碼
把多個對象的屬性複製到一個對象中,第一個參數是複製的對象,從第二個參數開始日後,都是複製的源對象
var nameObj = {name:'wjh'}
var ageObj = {age:8};
var obj = {};
Object.assign(obj,nameObj,ageObj);
console.log(obj);
//克隆對象
function clone(obj){
return Object.assgin({},obj);
}
複製代碼
將一個指定的對象原型設置爲另外一個對象或者null
var obj1 = {name:'wjh1'};
var obj2 = {name:'wjh2'};
var obj = {};
Object.setPrototypeOf(obj,obj1);
console.log(obj.name);
console.log(Object.getPrototypeOf(obj));
Object.setProtoypeOF(obj,obj2);
console.log(obj.name);
console.log(Object.getPrototypeOf(obj));
複製代碼
直接對象表達式中設置prototype
var obj1 = {name:'wjh'};
var obj3 = {
_proto_:obj1
}
console.log(obj3.name);
console.log(Object.getPrototypeOf(obj3));
複製代碼
經過super能夠調用protype上的屬性或方法
let person ={
eat(){
return 'milk';
}
}
let student = {
_proto_:person,
eat(){
return super.eat()+'bead'
}
}
console.log(student.eat());
複製代碼
使用 class 這個關鍵詞定義一個類,基於這個建立實例之後就會建立 constructor 方法,此方法能夠用來初始化
class Person{
constructor(name){
this.name = name;
}
getName(){
console.log(this.name)
}
}
let person = new Person('wjh');
person.getName();
複製代碼
getter 能夠用來獲取屬性,setter 能夠去設置屬性
class Person {
constructor(){
this.hobbies = [];
}
set hobby(hobby){
this.hobbies.push(hobby);
}
get hobby(){
return this.hobbies;
}
}
let person = new Person();
person.hobby = 'aa';
person.hobby = 'bb';
console.log(person.hobby)
複製代碼
在類裏面添加靜態的方法可使用static 這個關鍵詞,靜態方法就是不須要實例化類就能使用的方法
class Person{
static add(a,b){
return a+b;
}
}
console.log(Person.add(1,x));
複製代碼
一個類能夠繼承其餘的類裏的東西
class Person{
constructor(name){
this.name = name;
}
}
class Teacher extends Person{
constructor(name,age){
super(name);
this.age = age;
}
}
var teacher = Teacher('wjh',8);
console.log(teacher.name,teacher.age)
複製代碼
Generator 是一個特殊的函數,執行它會返回一個Iterator對象。經過遍歷迭代器,Generator函數運行後悔返回遍歷器對象,而不是函數的返回值。
迭代器有一個next方法,每次執行的時候會返回一個對象 對象裏面有兩個函數,一個是value表示返回的值,還有就是布爾值done,表示是迭代完成
function buy(books){
let i = 0;
return{
next(){
let done = i ===books.length;
let value = !done ? books[i++]:undefined;
return {
value:value,
done:done
}
}
}
}
let iterators = buy(['js','html']);
var curr;
do{
curr = iterators.next();
console.log(curr);
}while(!curr.done);
複製代碼
生成器用於建立迭代器
function* buy(boos){
for(var i=0;i<boos.length;i++){
yield books[i];
}
}
let buying = buy(['js','html]);
var curr;
do {
curr = buying.next();
console.log(curr);
}while(!curr.done);
複製代碼
一個Set是一堆東西的集合,Set 有點像數組,不過跟數組不同的是,Set裏面不能有重複的內容
var books = new Set();
books.add('js');
books.add('js');//添加劇復元素的集合元素個數不會變化
books.add('html');
books.forEach(function(book){ // 循環集合
console.log(book);
})
console.log(book.size);//集合中元數的個數
console.log(books.has('js'));//判斷集合是否有此元素
books.delete('js');
console.log(books.size);
console.log(books.has('js'));
books.clear();//清空set
console.log(books.size);
複製代碼
可使用Map來組織這個名值對的數據
var books = new Map();
books.set('js',{name:'js'});//向map中添加元素
books.set('html',{name:'html'});
console.log(books.size);//查看集合中的元素
console.log(books.get('js'));//經過key獲取值
books.delete('js');//執行key刪除元素
console.log(books.has('js'));//判斷map中有沒有key
book.forEach((value,key)=>{
console.log(key+'='+value);
})
books.clear();//清空map
複製代碼
能夠根據應用的需求吧代碼分紅不一樣的模塊,每一個模塊裏能夠導出它須要讓其餘模塊使用的東西,在其餘模塊裏面能夠導入這些模塊,導出的東西。
在瀏覽器中使用模塊須要藉助 導出
export var name = 'wjh';
export var age = 8;
複製代碼
導入
//import {name,age} from './school.js';
import * as school from './school.js';
console.log(school.name,school.age);
複製代碼
在頁面中引用
<script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script>
<script src="https://google.github.io/traceur-compiler/bin/BrowserSystem.js"></script>
<script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script>
<script type="module" src="index.js"></script>
複製代碼
導出時重命名
function say(){
console.log('say');
}
export {say as say2};
複製代碼
導入時重命名
import {say2 as say3} from './school.js'
複製代碼
每一個模塊均可以有一個默認要導出的東西
export default function say(){
console.log('say')
}
複製代碼
導入
import say from './school.js'
複製代碼
var parent = {
age: 5,
hobby: [1, 2, 3],
home: {city: '北京'},
};
var child = extendDeep(parent);
child.age = 6;
child.hobby.push('4');
child.home.city = '廣東';
console.log('child ', child); //[1, 2, 3, 4]
console.log('parent ', parent);
function extend(parent) {
let child;
if (Object.prototype.toString.call(parent) == '[object Object]') {
child = {};
for (let key in parent) {
child[key] = extend(parent[key])
}
} else if (Object.prototype.toString.call(parent) == '[object Array]') {
child = parent.map(item => extend(item));
} else {
return parent;
}
return child;
}
function extendDeep(parent, child) {
child = child || {};
for (var key in parent) {
if (typeof parent[key] === "object") {
child[key] = (Object.prototype.toString.call(parent[key]) === "[object Array]") ? [] : {};
extendDeep(parent[key], child[key]);
} else {
child[key] = parent[key];
}
}
return child;
}
複製代碼
function test(fruit) {
if (fruit == 'apple' || fruit == 'strawberry') {
console.log('red');
}
}
複製代碼
優化變成 ->>
function test(fruit) {
// 條件提取到數組中
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (redFruits.includes(fruit)) {
console.log('red');
}
}
複製代碼
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// 條件 1:fruit 必須有值
if (fruit) {
// 條件 2:必須爲紅色
if (redFruits.includes(fruit)) {
console.log('red');
// 條件 3:數量必須大於 10
if (quantity > 10) {
console.log('big quantity');
}
}
} else {
throw new Error('No fruit!');
}
}
// 測試結果
test(null); // 拋出錯誤:No fruits
test('apple'); // 打印:red
test('apple', 20); // 打印:red,big quantity
複製代碼
優化
/* 在發現無效條件時提早 return */
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// 條件 1:提早拋出錯誤
if (!fruit) throw new Error('No fruit!');
// 條件2:必須爲紅色
if (redFruits.includes(fruit)) {
console.log('red');
// 條件 3:數量必須大於 10
if (quantity > 10) {
console.log('big quantity');
}
}
}
複製代碼
爲了減小一個嵌套層級,優化編碼風格
/* 在發現無效條件時提早 return */
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (!fruit) throw new Error('No fruit!'); // 條件 1:提早拋出錯誤
if (!redFruits.includes(fruit)) return; // 條件 2:當 fruit 不是紅色的時候,提早 return
console.log('red');
// 條件 3:必須是大量存在
if (quantity > 10) {
console.log('big quantity');
}
}
複製代碼
function test(fruit, quantity) {
if (!fruit) return;
const q = quantity || 1; // 若是沒有提供 quantity 參數,則默認爲 1
console.log(`We have ${q} ${fruit}!`);
}
// 測試結果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
複製代碼
可是q在這邊不直觀全部優化
function test(fruit, quantity = 1) { // i若是沒有提供 quantity 參數,則默認爲 1
if (!fruit) return;
console.log(`We have ${quantity} ${fruit}!`);
}
// 測試結果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
複製代碼
可是這邊 也多是個對象
// 解構 —— 只得到 name 屬性
// 參數默認分配空對象 {}
function test({name} = {}) {
console.log (name || 'unknown');
}
//測試結果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
複製代碼
function test(color) {
// 使用 switch case 語句,根據顏色找出對應的水果
switch (color) {
case 'red':
return ['apple', 'strawberry'];
case 'yellow':
return ['banana', 'pineapple'];
case 'purple':
return ['grape', 'plum'];
default:
return [];
}
}
//測試結果
test(null); // []
test('yellow'); // ['banana', 'pineapple']
複製代碼
這邊建議使用對象,更加清晰
// 使用對象字面量,根據顏色找出對應的水果
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum']
};
function test(color) {
return fruitColor[color] || [];
}
複製代碼
可是這邊是頗有可能爲網絡數據,沒法判斷red這樣的變量,那麼就用arry.filter 來過濾
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'strawberry', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'pineapple', color: 'yellow' },
{ name: 'grape', color: 'purple' },
{ name: 'plum', color: 'purple' }
];
function test(color) {
// 使用 Array filter ,根據顏色找出對應的水果
return fruits.filter(f => f.color == color);
}
複製代碼
咱們想檢查全部水果是否都是紅色的
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
let isAllRed = true;
// 條件:全部的水果都必須是紅色
for (let f of fruits) {
if (!isAllRed) break;
isAllRed = (f.color == 'red');
}
console.log(isAllRed); // false
}
複製代碼
使用 arry.every來過濾
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
// 條件:簡短方式,全部的水果都必須是紅色
const isAllRed = fruits.every(f => f.color == 'red');
console.log(isAllRed); // false
}
複製代碼
若是咱們想要檢查是否有至少一個水果是紅色的,咱們可使用 Array.some 僅用一行代碼就實現出來
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
// 條件:是否存在紅色的水果
const isAnyRed = fruits.some(f => f.color == 'red');
console.log(isAnyRed); // true
}
複製代碼
在須要多個操做的時間,會致使多個回調函數嵌套,致使代碼不夠直觀,就常說的回調地獄
若是幾個異步操做之間並無先後順序之分,但須要等多個異步完成操做完成後才能執行後續的任務,沒法實現並行節約時間
promise本意是承諾,在程序中的意思就是承諾我過一段時間後會給你一個結果。什麼時間會用到過一段時間?答案是異步操做,異步是指可能比較長時間纔有結果的才作,例如網絡請求、讀取本地文件等
then方法就是用來指定Promise 對象的狀態改變時肯定執行的操做,resolve時執行第一個函數(onFulfilled),reject時執行第二函數(onRejected)
let promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
if(Math.random()>0.5)
resolve('This is resolve!')
else
reject('This is reject')
},1000);
});
promise.then(Fulfilled,Rejected)
複製代碼
function Promise(fn){
this.success(data);
},(error)=>{
this.error();
}
Promise.prtotype.resolve = function (data){
this.success(data);
}
Promise.prototype.then = function (success,error){
this.success = success;
this.error = error;
}
複製代碼
class Promise{
constructor(fn){
fn((data)=>{
this.success(data);
},(error)=>{
this.error();
})
}
resolve(data){
this.success(data);
}
reject(error){
this.error(error);
}
then(success,error){
this.success = success;
this.error = error;
console.log(this);
}
}
複製代碼
function ajaxPromise(queryUrl){
return new Promise((resolve,reject)=>{
xhr.open('GET',queryUrl,ture);
xhr.send(null);
xhr.onreadystatechange = () =>{
if(xhr.readyState === 4 ){
if(xhr.status === 200){
resolve(xhr.responseText);
}else{
reject(xhr.responseText);
}
}
}
})
}
ajaxPromise('http://www.baidu.com')
.then((value)=>{
console.log(value);
})
.catch((err)=>{
console.error(err);
});
複製代碼
then 可使用鏈式調用的寫法緣由在於,每一次執行該方法時老是會返回一個 Promise 對象
readFile('1.txt').then(function(data){
console.log(data);
}).then(function (data){
console.log(data);
return readFile(data);
}).then(function (data){
console.log(data);
}).catch(function (err){
console.log(err);
})
複製代碼
Promise.all([p1,p2]).then(function(result){
console.log(result); //[ '2.txt', '2' ]
})
複製代碼
無論兩個promise誰先完成,Promise.all 方法會按照數組裏面的順序將結果返回
Promise.race([p1,p2]).then(function(result){
console.log(result); //[ '2.txt', '2' ]
})
複製代碼
返回一個Promise 實例,這個實例處於resolve狀態。
根據傳入的參數不一樣有不一樣的功能:
返回一個Promise實例,這個實例處於reject狀態
var Q = require('q');
var fs = require('fs');
function read(filename){
var deferred = Q.defer();
fs.readFile(filename,'utf8',function)(err,data){
if(err){
deferred.reject(err);
}else{
deferred.resolve(data);
}
});
}
read('1.txt1').then(function(data){
console.log(data);
},funtcion(error){
console.error(error);
})
複製代碼
module.exports = {
defer(){
var _success,_error;
return {
resolve(data){
_success(data);
},
reject(err){
_error(err);
},
promise:{
then(success,error){
_success = success;
_error = error;
}
}
}
}
}
複製代碼
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = _value;
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
callback(value);
}
pending = undefined;
}
},
promise: {
then: function (callback) {
if (pending) {
pending.push(callback);
} else {
callback(value);
}
}
}
};
};
複製代碼
實現 promise 標準的庫是功能最全,速度最快的一個庫
var Promise = require('./bluebird');
var readFile = Promise.promisify(require("fs").readFile);
readFile("1.txt", "utf8").then(function(contents) {
console.log(contents);
})
var fs = Promise.promisifyAll(require("fs"));
fs.readFileAsync("1.txt", "utf8").then(function (contents) {
console.log(contents);
})
複製代碼
module.exports = {
promisify(fn){
return function () {
var args = Array.from(arguments);
return new Promise(function (resolve, reject) {
fn.apply(null, args.concat(function (err) {
if (err) {
reject(err);
} else {
resolve(arguments[1])
}
}));
})
}
},
promisifyAll(obj){
for(var attr in obj){
if(obj.hasOwnProperty(attr) && typeof obj[attr] =='function'){
obj[attr+'Async'] = this.promisify(obj[attr]);
}
}
return obj;
}
}
複製代碼
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>move</title> <style> .square{ width:40px; height:40px; border-radius: 50%; } .square1{ background-color: red; } .square2{ background-color: yellow; } .square3{ background-color: blue; } </style> </head> <body> <div class="square square1" style="margin-left: 0"></div> <div class="square square2" style="margin-left: 0"></div> <div class="square square3" style="margin-left: 0"></div> </body> <script> var square1 = document.querySelector('.square1'); var square2 = document.querySelector('.square2'); var square3 = document.querySelector('.square3'); /*function move(element,target,resolve){ let timer = setInterval(function(){ var marginLeft = parseInt(element.style.marginLeft, 10); if(marginLeft == target){ resolve(); }else{ element.style.marginLeft = ++marginLeft+'px'; } },13); }*/ function move(element,target,resolve){ let current = 0; let timer = setInterval(function(){ element.style.transform=`translateX(${++current}px)`; if(current>target){ clearInterval(timer); resolve(); }; },13); } function animate(element,target){ return new Promise(function(resolve,reject){ move(element,target,resolve); }); } animate(square1,100) .then(function(){ return animate(square2,100); }) .then(function(){ return animate(square3,100); }); </script> </html> 複製代碼
let fs = require('fs');
function getNumber(){
return new Promise(function (resolve,reject) {
setTimeout(function(){
let number = Math.random();
if(number >.5){
resolve(number);
}else{
reject('數字過小');
}
},1000);
});
}
function *read(){
let a = yield getNumber();
console.log(a);
let b = yield 'b';
console.log(b);
let c = yield getNumber();
console.log(c);
}
function co(gen){
return new Promise(function(resolve,reject){
let g = gen();
function next(lastValue){
let {done,value} = g.next(lastValue);
if(done){
resolve(lastValue);
}else{
if(value instanceof Promise){
value.then(next,function(val){
reject(val);
});
}else{
next(value);
}
}
}
next();
});
}
co(read).then(function(data){
console.log(data);
},function(reason){
console.log(reason);
});
複製代碼
let fs = require('fs');
function readFile(filename){
return new Promise(function (resolve,reject) {
fs.readFile(filename,'utf8',function(err,data){
if(err)
reject(err);
else
resolve(data);
})
});
}
function *read(){
let a = yield readFile('./1.txt');
console.log(a);
let b = yield readFile('./2.txt');
console.log(b);
}
function co(gen){
let g = gen();
function next(val){
let {done,value} = g.next(val);
if(!done){
value.then(next);
}
}
next();
}
複製代碼
function Promise(executor) {
let self = this;
self.status = "pending";
self.value = undefined;
self.onResolvedCallbacks = [];
self.onRejectedCallbacks = [];
function resolve(value) {
if (value instanceof Promise) {
return value.then(resolve, reject)
}
setTimeout(function () { // 異步執行全部的回調函數
if (self.status == 'pending') {
self.value = value;
self.status = 'resolved';
self.onResolvedCallbacks.forEach(item => item(value));
}
});
}
function reject(value) {
setTimeout(function () {
if (self.status == 'pending') {
self.value = value;
self.status = 'rejected';
self.onRejectedCallbacks.forEach(item => item(value));
}
});
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('循環引用'));
}
let then, called;
if (x != null && ((typeof x == 'object' || typeof x == 'function'))) {
try {
then = x.then;
if (typeof then == 'function') {
then.call(x, function (y) {
if (called)return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, function (r) {
if (called)return;
called = true;
reject(r);
});
} else {
resolve(x);
}
} catch (e) {
if (called)return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : function (value) {
return value
};
onRejected = typeof onRejected == 'function' ? onRejected : function (value) {
throw value
};
let promise2;
if (self.status == 'resolved') {
promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
if (self.status == 'rejected') {
promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
let x = onRejected(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
if (self.status == 'pending') {
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function (value) {
try {
let x = onFulfilled(value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
self.onRejectedCallbacks.push(function (value) {
try {
let x = onRejected(value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
return promise2;
}
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
let result = [];
let count = 0;
for (let i = 0; i < promises.length; i++) {
promises[i].then(function (data) {
result[i] = data;
if (++count == promises.length) {
resolve(result);
}
}, function (err) {
reject(err);
});
}
});
}
Promise.deferred = Promise.defer = function () {
var defer = {};
defer.promise = new Promise(function (resolve, reject) {
defer.resolve = resolve;
defer.reject = reject;
})
return defer;
}
/** * npm i -g promises-aplus-tests * promises-aplus-tests Promise.js */
try {
module.exports = Promise
} catch (e) {
}
複製代碼