javascript
javascript 总结笔记
時(shí)間匆匆, 轉(zhuǎn)眼畢業(yè)已經(jīng)快兩年了。 最為一個(gè)前端小白的我, 現(xiàn)在怎么說也是灰色的了吧? 前段時(shí)間一直有個(gè)想法: 想把自己學(xué)到的前端知識(shí)點(diǎn)整理下,感覺這樣有助于自己基礎(chǔ)的鞏固。 所以才有個(gè)今天這個(gè)js知識(shí)點(diǎn)回顧文章。 好吧,廢話少說了, 先從javascript開席吧!
前言:
畢業(yè)的時(shí)候本來不是做前端的。 作為一個(gè)后臺(tái)培訓(xùn)出來的應(yīng)屆生。 匆匆培訓(xùn)java、html、 css、 java2ee 、ssh等一大堆東西。第一家公司是來上海做后臺(tái)。 記得有一次項(xiàng)目中老大說讓我整理個(gè)頁面, 當(dāng)時(shí)懵逼了都。 什么? 讓我寫個(gè)ajax ? !雖然培訓(xùn)過前端方面的知識(shí), 但是也只是匆匆而過,有個(gè)大概的了解。 沒辦法只能硬著頭皮上網(wǎng)上找資料啊。 心想如果做不出來,會(huì)不會(huì)被開除啊?( 我想每個(gè)實(shí)習(xí)期的童鞋都有這樣的經(jīng)歷吧 哈哈...)這就算是我第一次真正接觸前端。 嗯 ,沒毛病。
正文:
1、 JavaScript簡介
JavaScript 和java 沒個(gè)卵的關(guān)系。 ECMAScript就是對(duì)實(shí)現(xiàn)該標(biāo)準(zhǔn)規(guī)定的各個(gè)方面內(nèi)容的語言的描述。
JavaScript實(shí)現(xiàn)了ECMAScript。 所以什么es5 es6 es7 是ECMAScript5 6 7 的簡寫。 至于其它概念,大概看下就行。(只是本人自己的看法)!
JavaScript在當(dāng)前五個(gè)主要瀏覽器( IE、 Firefox、 Chrome、 Safari和 Opera) 中 都得到了不同程度的支持。 所以才有了兼容性的問題。 但人類的腳步是向前的。 比如babel 編譯器解決了這種差異。統(tǒng)一編譯成es5。呵呵噠!
2、 推薦在javaScript 中使用 "use strict" 。why ? 讓我就舉個(gè)栗子:
"use strict"; //在正常模式中,如果一個(gè)變量沒有聲明就賦值,默認(rèn)是全局變量。嚴(yán)格模式禁止這種用法,全局變量必須顯式聲明。v = 1; // 報(bào)錯(cuò),v未聲明for (i = 0; i < 2; i++) { // 報(bào)錯(cuò),i未聲明 } //因此, 嚴(yán)格模式下, 變量都必須先用var命令聲明, 然后再使用。function f() { return this; //非嚴(yán)格模式下 因?yàn)?span id="ze8trgl8bvbq" class="hljs-string">"this"指向全局對(duì)象,返回全局對(duì)象 }function f() { "use strict"; //這行代碼看起來像是字符串,而且也沒有賦值給任何變量,但其實(shí)它是一個(gè)編譯指示(pragma), // 用于告訴支持的 JavaScript引擎切換到嚴(yán)格模式 return this; //嚴(yán)格模式下 this的值為undefined, } 復(fù)制代碼嚴(yán)格模式下方法入?yún)⒉荒苡兄貜?fù)定義的變量、 對(duì)象不能有重復(fù)的屬性。。。
而且有時(shí)候 "use strict"可以節(jié)省函數(shù)執(zhí)行的時(shí)間。
推薦語句以一個(gè)分號(hào)結(jié)尾。(以前做的一個(gè)vuejs項(xiàng)目 eslint 不能用; 結(jié)尾 結(jié)果我們公司有個(gè)大大牛就問了 你們js為什么語句不以分號(hào)結(jié)尾都添加上 加上!!!。。。。。好吧 結(jié)果我們把eslint關(guān)了哎。。。)
3、 js 基本數(shù)據(jù)類型
字符串 string var const let
數(shù)值 Number Number()
真假 Boolean new Boolean()
數(shù)組 Array new Array() | []
對(duì)象 Object new Object | {}
NaN isNaN(a) //轉(zhuǎn)成Number類型進(jìn)行判斷 so alert(isNaN("10")); //false(可以被轉(zhuǎn)換成數(shù)值 10)
what you find that ?
so not use Number use parseInt()
var num2 = parseInt(""); // NaN var num1 = parseInt("1234blue"); // 1234 剛發(fā)現(xiàn) 666 var num4 = parseInt(22.5); // 22 var num5 = parseInt("070"); // 56(八進(jìn)制數(shù))var num6 = parseInt("70"); // 70(十進(jìn)制數(shù))var num7 = parseInt("0xf"); // 15(十六進(jìn)制數(shù)) 復(fù)制代碼false 的8個(gè)值: ''
0、 - 0、 NaN、 false 、null、 undefined、 newBoolean()
問個(gè)問題:
[] === '' []== '' 復(fù)制代碼結(jié)果是什么? why?
typeof 返回的是字符串, 有六種可能:
"number"、
"string"、
"boolean"、
"function"、
"undefined"、
"object": {
[],
{}
}
其中 null類型typeof null === "object" 復(fù)制代碼so 判斷變量是數(shù)組還是對(duì)象的時(shí)候 要過濾null。
eg:
if (isWaitting && isWaitting instanceof Array) {} 復(fù)制代碼舉個(gè)例子吧:
var shallowCopy = function(obj) { //一個(gè)淺拷貝方法 應(yīng)該知道為什么有這個(gè)方法吧 (數(shù)組、對(duì)象中地址引用的鍋) if (typeof obj != 'object') return; var newObj = obj instanceof Array ? [] : {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj;} 復(fù)制代碼再來個(gè)深拷貝: //記得gitHub 上有一個(gè)deep-assign npm可以install哦 有需要的大家可以搜下
var deepCopy = function(obj) { if (typeof obj !== 'object') return; //null NaN Math var newObj = obj instanceof Array ? [] : (!obj ? null : {}); for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; } } return newObj; } 復(fù)制代碼4、 在html引入js要注意的事項(xiàng)
肯定要寫在 < script > < /script>里面嘍!沒話說的。如果瀏覽器不支持js的話 那用
<noscript ><p> 本頁面需要瀏覽器支持( 啟用) JavaScript。 </noscript>
我是至今也沒見過瀏覽器顯示這個(gè)的。 除非你把瀏覽器設(shè)置了不支持js語法。
這樣當(dāng)我沒說!!
js一般引入的位置是在body后面而不是header里面。 因?yàn)闉g覽器渲染的過程中是單線程的。 當(dāng)js加載完成并執(zhí)行后才能繼續(xù)往下加載別的。
一句話概括吧: 就是你他媽的js加載多的話,
入口頁面渲染完成所用的時(shí)間過多, 體驗(yàn)不要。 嗯, 這個(gè)也引發(fā)了后面的前端優(yōu)化什么的。 有點(diǎn)人說盡量不再js中改變dom節(jié)點(diǎn)的更改、 減少http的請(qǐng)求、
使用img snipe、 根據(jù)路由懶加載依賴的文件、 外部引用js文件的時(shí)候加defer( 這個(gè)屬性的用途是表明腳本在執(zhí)行時(shí)不會(huì)影響頁 面的構(gòu)造。也就是說, 腳本會(huì)被延遲到整個(gè)頁面都解析完畢后再運(yùn)行。 因此, 在 < script > 元素中設(shè)置 defer 屬性, 相當(dāng)于告訴瀏覽器立即下載,但延遲執(zhí)行。
拓展:
同樣與 defer 類似,async 只適用于外部腳本文件, 并告訴瀏覽器立即下載文件。 但與 defer 不同的是, 標(biāo)記為 async 的腳本并不保證按照指定它們的先后順序執(zhí)行。 例如:
<script type = "text/javascript" async src = "example1.js" > < /script> <script type = "text/javascript" async src = "example2.js" > < /script> 復(fù)制代碼在以上代碼中, 第二個(gè)腳本文件可能會(huì)在第一個(gè)腳本文件之前執(zhí)行。 因此, 確保兩者之間互不依賴 非常重要。
指定 async 屬性的目的是不讓頁面等待兩個(gè)腳本下載和執(zhí)行, 從而異步加載頁面其他內(nèi)容。
為此, 建議異步腳本不要在加載期間修改 DOM。 異步腳本一定會(huì)在頁面的 load 事件前執(zhí)行,但可能會(huì)在 DOMContentLoaded 事件觸發(fā)之前或之 后執(zhí)行。
支持異步腳本的瀏覽器有Firefox 3.6、 Safari5 和 Chrome
5、 來個(gè)運(yùn)算符吧
var a = 0; a++; ++a; 復(fù)制代碼老生常談了
6、 Boolean
以前常常看到人們判斷一個(gè)變量是否為空 是否是沒定義
if( a != null && typeof a != 'undefined') {} 復(fù)制代碼忘了上面的‘ false 的8個(gè)值’ 了嘛? 今天以后就可以這樣寫
if(a) {} // a 不能是 0 -0 NaN '' false null undefined 復(fù)制代碼特殊情況特殊對(duì)待
追加:
7、 函數(shù)function
函數(shù)中的結(jié)束: return;
函數(shù)中沒有java的重載。 只有替換
函數(shù)中沒有類但能模擬類
//es5
var superClass = function() { this.name = null; }superClass.prototype.setName = function(name) { this.name = name; } superClass.prototype.getName = function() { return this.name; } var superC = new superClass(); superC.setName('fd'); superC.getName();var subClass = superClass.prototype; //繼承 subClass.prototype.mackSound = function() { this.name = '電風(fēng)扇'; } 復(fù)制代碼//es6
class superClass2 { constructor() { this.name = name; } getName() { return this.name; }setName(name) { this.name = name; } show() { console.log(this.name); } } var as = new superClass2();as.setName('fdsf');as.show(); class superClass3 extends superClass2 { //繼承 } var sdf = new superClass3(); 復(fù)制代碼8、閉包
(function sd() { console.log(12) })()//自動(dòng)執(zhí)行函數(shù) 復(fù)制代碼9、上下文執(zhí)行環(huán)境 作用域
var a = 10; function sum(b) { return a + b; }function add() { var a = 20; var c = sum(30); return c; }add(); //40 復(fù)制代碼why?為什么不是50呢?我的理解是:當(dāng)函數(shù)沒有執(zhí)行前,函數(shù)中的變量就已經(jīng)確定指向。比如sum()中 當(dāng)沒有調(diào)用add()方法的時(shí)候,sum()方法里的a已經(jīng)的指針已經(jīng)指向了全局作用域下定義的var a = 10;而非調(diào)用時(shí)候的var a = 20;
總結(jié):函數(shù)創(chuàng)建的時(shí)候 就已經(jīng)確定了作用域 . 要到創(chuàng)建這個(gè)函數(shù)的那個(gè)作用域中取值——是“創(chuàng)建”,而不是“調(diào)用”,切記切記.
上面描述的只是跨一步作用域去尋找。如果跨了一步,還沒找到呢?——接著跨!——一直跨到全局作用域?yàn)橹埂R窃谌肿饔糜蛑卸紱]有找到,那就是真的沒有了。
這個(gè)一步一步“跨”的路線,我們稱之為——作用域鏈。
我們拿文字總結(jié)一下取自由變量時(shí)的這個(gè)“作用域鏈”過程:(假設(shè)a是自由量)
第一步,現(xiàn)在當(dāng)前作用域查找a,如果有則獲取并結(jié)束。如果沒有則繼續(xù);
第二步,如果當(dāng)前作用域是全局作用域,則證明a未定義,結(jié)束;否則繼續(xù);
第三步,(不是全局作用域,那就是函數(shù)作用域)將創(chuàng)建該函數(shù)的作用域作為當(dāng)前作用域;
第四步,跳轉(zhuǎn)到第一步。
//當(dāng)一個(gè)函數(shù)被call和apply調(diào)用時(shí),this的值就取傳入的對(duì)象的值
既然說到了call apply 那就再繼續(xù)說點(diǎn)吧
用call()apply() 可以強(qiáng)制指定this的指向。那么this又是什么玩意呢?代表當(dāng)前作用域本身。在全局作用域下
在函數(shù)塊級(jí)作用域下
這樣應(yīng)該明白了吧
有一天看到了一個(gè)這種寫法
var arr = [1,2,4,5,7,34] Math.max.call(null,1,2,4,5,7,34) //34 Math.max.apply(null,arr) //34 復(fù)制代碼從上面可以看出兩個(gè)東西:
1、call apply 接收參數(shù)的格式不同 怎么不同? 自己看
2、重新定義了Math.max函數(shù)的this指向
Es6:Math.max(...arr) //了解下就行。
上下文執(zhí)行環(huán)境:就是當(dāng)前函數(shù)執(zhí)行時(shí)候所處的環(huán)境 環(huán)境應(yīng)該都知道 java開發(fā)前都要先配置jre jdk開發(fā)環(huán)境 咱們的javascript中 函數(shù)運(yùn)行時(shí)候也要有自己的環(huán)境。當(dāng)一個(gè)函數(shù)執(zhí)行完成后
當(dāng)前上下文執(zhí)行環(huán)境就會(huì)被銷毀。至于涉及到堆棧方面的知識(shí),技術(shù)有限,說不出來。。。。。想知道這樣面的知識(shí)可以自行g(shù)oogle。
10.地址引用遇到的坑
地址引用的數(shù)據(jù)類型有:array object
Var arr = [1,2];
自己理解:變量arr 中其實(shí)放的不是數(shù)據(jù) 1,2 。寄存的只是一個(gè)hash地址。該地址指向存放[1,2]的數(shù)據(jù)池。如果重新給arr賦值 arr = [1,3] 則arr指針重新指向了另一個(gè)數(shù)據(jù)池[1,3] 。
但是:當(dāng) var arr= [1,2] ;arr.push(4); 這時(shí)候指針是不變化的。變化的是指針定向的數(shù)據(jù)池里的數(shù)據(jù)。這點(diǎn)要注意。
記得有個(gè)面試題如下:
var arr = [1, 2, 3]; var c = arr; arr = [1, 2]; console.log(c); //[1, 2, 3] arr.push(4); console.log(arr); //[1, 2,4] console.log(c); //[1, 2, 3]var arr2= [1, 2, 3]; var c2 = arr2; arr2.push(4); console.log(arr2); //[1, 2, 3,4] console.log(c); //[1, 2, 3]var obj = [{ name: 'ssh' }, { name: 'ssh2' }] var obj2 = []; obj.forEach((item, index) => { item.name == 'ssh' ? obj2.push(item) : false; }) obj2[0].name = 'ssh2222'; console.log(obj) // 有變化嘛如果有 why? 復(fù)制代碼11、Math
常用的幾種:
Math.abs() //返回?cái)?shù)的絕對(duì)值。
Math.floor() //對(duì)數(shù)進(jìn)行下舍入。 地板 懂?
Math.ceil() //對(duì)數(shù)進(jìn)行上舍入。 天花板 懂?
Math. max(x,y) //返回 x 和 y 中的最高值。
Math.min(x,y)// 返回x 和 y 中的最低值。
Math. pow(x,y) //返回 x 的 y 次冪。
Math. random()// 返回 0 ~ 1 之間的隨機(jī)數(shù)。
Math. round(x) //把數(shù)四舍五入為最接近的整數(shù)。
Math.trunc(2.643) //2 截取小數(shù)點(diǎn)前面的數(shù)字
12、Date
Var a = new Date(); 本地全部時(shí)間格式: toLocaleString(); // "2017/11/16 下午4:27:09" a.toLocaleDateString() //"2017/11/16" toLocaleTimeString() // "下午4:27:09" getFullYear() //2017 getTime() getTime() 返回從 1970 年 1 月 1 日至今的毫秒數(shù)。//+new Date() getDay() //如何使用 getDay() 和數(shù)組來顯示星期幾,而不僅僅是數(shù)字 //周日 =>0 ? 復(fù)制代碼13、 Array 方法
主要幾點(diǎn)就行了:
push pop 都是從數(shù)組后面開始處理數(shù)據(jù)的 (棧) shift unshift 從頭開始 (隊(duì)列) slice() 相當(dāng)于重新定義了個(gè)數(shù)組 即不同的指針 splice() //從數(shù)組中移除一個(gè)或多個(gè)數(shù)組,并用新的item代替他們 返回被替換的數(shù)組var a = ['a','b','c','d']; var b = a.splice(1,3,'f'); a// ["a", "f"] b// ["b", "c","d"] 復(fù)制代碼14、數(shù)組去重的正確編寫姿勢(shì)(面試很愛問!)
//使用數(shù)組的indexOf()方法可以很簡單的達(dá)到目的。 Array.prototype.unique = function() { // 創(chuàng)建一個(gè)新的臨時(shí)數(shù)組,用于保存輸出結(jié)果 var n = []; // 遍歷當(dāng)前數(shù)組 for (var i = 0; i < this.length; i++) { // 如果當(dāng)前數(shù)組的第i個(gè)元素已經(jīng)保存進(jìn)了臨時(shí)數(shù)組,那么跳過,否則把當(dāng)前項(xiàng)push到臨時(shí)數(shù)組里面 if (n.indexOf(this[i]) == -1) n.push(this[i]); // if (!n.includes(this[i])) n.push(this[i]); } return n; } 復(fù)制代碼最快姿勢(shì)
//把已經(jīng)出現(xiàn)過的元素通過下標(biāo)的形式存入一個(gè)Object內(nèi)。下標(biāo)的引用的實(shí)現(xiàn)原理利用的是哈希算法,要比用indexOf()搜索數(shù)組快的多。 Array.prototype.unique = function() { // n為hash表,r為臨時(shí)數(shù)組 var n = {}, r = []; for (var i = 0; i < this.length; i++) { // 如果hash表中沒有當(dāng)前項(xiàng) if (!n[this[i]]) { // 存入hash表 n[this[i]] = true; // 把當(dāng)前數(shù)組的當(dāng)前項(xiàng)push到臨時(shí)數(shù)組里面 r.push(this[i]); } } return r; } 復(fù)制代碼但從耗時(shí)的角度來講,這是最優(yōu)的一種解決方式。但是從內(nèi)存占用角度來說,這并不是最優(yōu)的,因?yàn)槎嗔艘粋€(gè)hash表。這就是所謂的空間換時(shí)間(世間安得雙全法?)。
中庸姿勢(shì) //推薦
Array.prototype.unique = function() { this.sort(); var re = [this[0]]; for (var i = 1; i < this.length; i++) { if (this[i] !== re[re.length - 1]) { re.push(this[i]); } } return re; } 復(fù)制代碼既然提到了new Set() 那么就延伸點(diǎn)別的吧
刪除數(shù)組中指定的項(xiàng):
Array.prototype.$remove = function (v) { const index = this.indexOf(v) //this代表數(shù)組本身 if (index !== -1) this.splice(index, 1) return this; }const arr = [1, 2, 3] arr.$remove(2) //下標(biāo)從1開始 復(fù)制代碼es6 新添加了很多方法
如foreach、map 、filter 、reduce 、objectAssign 、copy、 includes 、indexof 、Array.isArray() 、Array.from() new Set() new Map() 等 。
在此不做詳細(xì)的說明,想了解的可以自行g(shù)oogle。
15、單線程中的異步
我們還經(jīng)常遇到setTimeout(fn,0)這樣的代碼,0秒后執(zhí)行又是什么意思呢?是不是可以立即執(zhí)行呢?
答案是不會(huì)的,setTimeout(fn,0)的含義是,指定某個(gè)任務(wù)在主線程最早可得的空閑時(shí)間執(zhí)行,意思就是不用再等多少秒了,只要主線程執(zhí)行棧內(nèi)的同步任務(wù)全部執(zhí)行完成,棧為空就馬上執(zhí)行。
舉例說明:
console.log('先執(zhí)行這里'); setTimeout(() => { console.log('執(zhí)行啦1') },10); setTimeout(() => { console.log('執(zhí)行啦2') },0);console.log('最后執(zhí)行這里'); 復(fù)制代碼16、異步(重點(diǎn) 面試還是愛問!)
Promise:異步
下面是一個(gè)Promise對(duì)象的簡單例子。
function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms, 'done'); }); }timeout(100).then((value) => { console.log(value); //'done' }); 復(fù)制代碼上面代碼中,timeout方法返回一個(gè)Promise實(shí)例,表示一段時(shí)間以后才會(huì)發(fā)生的結(jié)果。過了指定的時(shí)間(ms參數(shù))以后,Promise實(shí)例的狀態(tài)變?yōu)閞esolve,就會(huì)觸發(fā)then方法綁定的回調(diào)函數(shù)。
Promise 實(shí)例
const wait = function(val) {// 定義一個(gè) promise 對(duì)象const promise = new Promise((resolve, reject) => {// 將之前的異步操作,包括到這個(gè) new Promise 函數(shù)之內(nèi)const task = function() {if (val) {console.log('執(zhí)行完成');resolve(true)} else { console.log('執(zhí)行失敗');reject(false) }// callback 中去執(zhí)行 resolve 或者 reject}setTimeout(task, 2000)})// 返回 promise 對(duì)象return promise }const w = wait (1); var a = 0; w.then((val) => {console.log('ok 1' + val);a = 231;console.log(a);return w; }, (val) => {console.log('err 1' + val) }).then((val) => {console.log('ok 2' + val);var b = a + 2;console.log(b) }, (val) => {console.log('err 2' + val) }) 復(fù)制代碼async :異步
依次讀取兩個(gè)文件:
var asyncReadFile = async function () { var f1 = await readFile('/etc/fstab'); var f2 = await readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };//注意 封裝的readFile ()方法要返回promise對(duì)象async function getStockPriceByName(name) { var symbol = await getStockSymbol(name); var stockPrice = await getStockPrice(symbol); return stockPrice; } getStockPriceByName('goog').then(function (result) { console.log(result); }); 復(fù)制代碼使用注意點(diǎn):
第一點(diǎn),前面已經(jīng)說過,await命令后面的Promise對(duì)象,運(yùn)行結(jié)果可能是rejected,所以最好把a(bǔ)wait命令放在try...catch代碼塊中。
async function myFunction() { try { await somethingThatReturnsAPromise(); } catch (err) { console.log(err); } }// 另一種寫法 (推薦) async function myFunction() { await somethingThatReturnsAPromise().catch(function (err) { console.log(err); });} 復(fù)制代碼因?yàn)橐韵滤械拇a都會(huì)用到Promise,因此干脆在所有介紹之前,先封裝一個(gè)Promise,封裝一次,為下面多次應(yīng)用。
const fs = require('fs') const path = require('path') // 后面獲取文件路徑時(shí)候會(huì)用到 const readFilePromise = function (fileName) {return new Promise((resolve, reject) => {fs.readFile(fileName, (err, data) => {if (err) {reject(err) // 注意,這里執(zhí)行 reject 是傳遞了參數(shù),后面會(huì)有地方接收到這個(gè)參數(shù)} else {resolve(data.toString()) // 注意,這里執(zhí)行 resolve 時(shí)傳遞了參數(shù),后面會(huì)有地方接收到這個(gè)參數(shù)}})}) } 復(fù)制代碼那么前面步驟return的值會(huì)被當(dāng)做參數(shù)傳遞給后面步驟的函數(shù),如下面代碼中的a就接收到了return JSON.parse(data).a的值
const fullFileName = path.resolve(__dirname, '../data/data2.json') const result = readFilePromise(fullFileName) result.then(data => {// 第一步操作console.log(data)return JSON.parse(data).a // 這里將 a 屬性的值 return }).then(a => {// 第二步操作console.log(a) // 這里可以獲取上一步 return 過來的值}) 復(fù)制代碼我們知道then會(huì)接收兩個(gè)參數(shù)(函數(shù)),第一個(gè)參數(shù)會(huì)在執(zhí)行resolve之后觸發(fā)(還能傳遞參數(shù)),第二個(gè)參數(shù)會(huì)在執(zhí)行reject之后觸發(fā)(其實(shí)也可以傳遞參數(shù),和resolve傳遞參數(shù)一樣),但是上面的例子中,我們沒有用到then的第二個(gè)參數(shù)。這是為何呢 ———— 因?yàn)椴唤ㄗh這么用。
對(duì)于Promise中的異常處理,我們建議用catch方法,而不是then的第二個(gè)參數(shù)。請(qǐng)看下面的代碼,以及注釋。
const fullFileName = path.resolve(__dirname, '../data/data2.json') const result = readFilePromise(fullFileName) result.then(data => {console.log(data)return JSON.parse(data).a; }).then(a => {console.log(a) }).catch(err => {console.log(err.stack) // 這里的 catch 就能捕獲 readFilePromise 中觸發(fā)的 reject ,而且能接收 reject 傳遞的參數(shù) }) 復(fù)制代碼讀取兩個(gè)文件data1.json和data2.json,現(xiàn)在我需要一起讀取這兩個(gè)文件,等待它們?nèi)慷急蛔x取完,再做下一步的操作。此時(shí)需要用到Promise.all。(以前記得做個(gè)打印報(bào)表的功能。當(dāng)時(shí)報(bào)表數(shù)據(jù)差不多幾萬條。所以想到了分頁打印。比如分5頁,每頁200條。那么打印的時(shí)候肯定要按順序打印。即1-200,201-300以此打印。那么就寫了個(gè)方法,循環(huán)遍歷整個(gè)數(shù)據(jù),每200條放到一個(gè)方法中,結(jié)果把5個(gè)方法再push到一個(gè)數(shù)組中。記得當(dāng)時(shí)用的是$q 里面的all()方法來執(zhí)行的。)
// Promise.all 接收一個(gè)包含多個(gè) promise 對(duì)象的數(shù)組Promise.all([result1, result2]).then(datas => {// 接收到的 datas 是一個(gè)數(shù)組,result1, result2 依次執(zhí)行,返回包含了多個(gè) promise的內(nèi)容console.log(datas[0])console.log(datas[1]) })var funcA = function(){console.log("funcA");return "hello,funA";}var funcB = function(){console.log("funcB");return "hello,funB";}var a = [funcA ,funcB];Promise.all([funcA , funcB]).then(datas => { // Promise.all(a).then()// 接收到的 datas 是一個(gè)數(shù)組,依次包含了多個(gè) promise 返回的內(nèi)容console.log(datas[0])console.log(datas[1]) }) 復(fù)制代碼讀取兩個(gè)文件data1.json和data2.json,現(xiàn)在我需要一起讀取這兩個(gè)文件,但是只要有一個(gè)已經(jīng)讀取了,就可以進(jìn)行下一步的操作。此時(shí)需要用到Promise.race
// Promise.race 接收一個(gè)包含多個(gè) promise 對(duì)象的數(shù)組 Promise.race([result1, result2]).then(data => { // data 即最先執(zhí)行完成的 promise 的返回值 console.log(data) }) 復(fù)制代碼栗子:
var uploadQuestion = function(questions) { var promises = []; angular.forEach(questions, function(question) { var promise = $http({ // url: 'upload/question', method: 'POST', data: question }); promises.push(promise);}); return $q.all(promises); } 復(fù)制代碼$q:異步
大家都是到 jquery v1.5 之后$.ajax()返回的是一個(gè)deferred對(duì)象,而這個(gè)deferred對(duì)象和我們現(xiàn)在正在學(xué)習(xí)的Promise對(duì)象已經(jīng)很接近了,但是還不一樣。那么 ———— deferred對(duì)象能否轉(zhuǎn)換成 ES6 的Promise對(duì)象來使用??
答案是能!需要使用Promise.resolve來實(shí)現(xiàn)這一功能,請(qǐng)看以下代碼:
// 在瀏覽器環(huán)境下運(yùn)行,而非node 環(huán)境
const jsPromise = Promise.resolve($.ajax('/whatever.json')) jsPromise.then(data => { // ... })//ajax 異步執(zhí)行方法 復(fù)制代碼其實(shí),在我們的日常開發(fā)中,這種將thenable轉(zhuǎn)換為Promise的需求并不多。真正需要的是,將一些異步操作函數(shù)(如fs.readFile)轉(zhuǎn)換為Promise(就像文章一開始readFilePromise做的那樣)而且then必須返回一個(gè)promise,同一個(gè) promise 的then可以調(diào)用多次(鏈?zhǔn)?#xff09;” ——— 這兩句話說明了一個(gè)意思 ——— then肯定要再返回一個(gè)promise,要不然then后面怎么能再鏈?zhǔn)降母粋€(gè)then呢?
eg:
function readFilePromise() {return new Promise((resolve, reject) => {resolve(setTimeout(() => {console.log(1111);}));}) };const readFileAsync = async function() {const f1 = await readFilePromise();const f2 = await readFilePromise();return 'done' // 先忽略,后面會(huì)講到}// 執(zhí)行 const result = readFileAsync() //1111 1111 result.then(data => {console.log(data) // done }) 復(fù)制代碼使用async-await的不同和好處
第一,await后面不能再跟thunk函數(shù),而必須跟一個(gè)Promise對(duì)象(因此,Promise才是異步的終極解決方案和未來)。跟其他類型的數(shù)據(jù)也OK,但是會(huì)直接同步執(zhí)行,而不是異步。
第二,執(zhí)行const result = readFileAsync()返回的是個(gè)Promise對(duì)象,而且上面代碼中的return 'done'會(huì)直接被下面的then函數(shù)接收到
result.then(data => { console.log(data) // done }) 復(fù)制代碼第三,從代碼的易讀性來將,async-await更加易讀簡介,也更加符合代碼的語意。而且還不用引用第三方庫,也無需學(xué)習(xí)Generator那一堆東西,使用成本非常低。
總結(jié):
異步操作 : promise \generator yield \async-await\$q
17、正則
這個(gè)我只會(huì)簡單的就不在此賣弄了。。。呵呵噠
18、window 對(duì)象(html5 api)
下期見。。。
19、模塊化封裝方法(exports、 module exports 、export default)
下期見。。。
總結(jié): 文章穿插有點(diǎn)大 .都是筆者隨心寫的。第一次寫,如有錯(cuò)誤請(qǐng)指正。請(qǐng)多多關(guān)照!!呵呵噠.
備注:文章有些是以前的學(xué)習(xí)筆記,直接拷貝上來的。侵刪!
總結(jié)
以上是生活随笔為你收集整理的javascript 总结笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 非DFS使用空间
- 下一篇: 解决启动flanneld失败的方法
