常見的水平垂直方式有幾種?
//利用絕對定位具练,先將元素的左上角通過 top:50%和 left:50%定位到頁面的中心乍构,然后再通過 translate 來調(diào)整元素的中心點(diǎn)到頁面的中心。該方法需要考慮瀏覽器兼容問題扛点。
.parent {
position: relative;
}
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
//利用絕對定位哥遮,設(shè)置四個(gè)方向的值都為 0,并將 margin 設(shè)置為 auto陵究,由于寬高固定眠饮,因此對應(yīng)方向?qū)崿F(xiàn)平分,可以實(shí)現(xiàn)水平和垂直方向上的居中铜邮。該方法適用于盒子有寬高的情況:
.parent {
position: relative;
}
.child {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
//利用絕對定位仪召,先將元素的左上角通過 top:50%和 left:50%定位到頁面的中心,然后再通過 margin 負(fù)值來調(diào)整元素的中心點(diǎn)到頁面的中心牲距。該方法適用于盒子寬高已知的情況
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px; /* 自身 height 的一半 */
margin-left: -50px; /* 自身 width 的一半 */
}
//使用 flex 布局返咱,通過 align-items:center 和 justify-content:center 設(shè)置容器的垂直和水平方向上為居中對齊钥庇,然后它的子元素也可以實(shí)現(xiàn)垂直和水平的居中牍鞠。該方法要**考慮兼容的問題**,該方法在移動(dòng)端用的較多:
.parent {
display: flex;
justify-content:center;
align-items:center;
}
//另外评姨,如果父元素設(shè)置了flex布局难述,只需要給子元素加上`margin:auto;`就可以實(shí)現(xiàn)垂直居中布局
.parent{
display:flex;
}
.child{
margin: auto;
}
----問題知識點(diǎn)分割線----
代碼輸出結(jié)果
const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("timerStart");
resolve("success");
console.log("timerEnd");
}, 0);
console.log(2);
});
promise.then((res) => {
console.log(res);
});
console.log(4);
輸出結(jié)果如下:
1
2
4
timerStart
timerEnd
success
代碼執(zhí)行過程如下:
- 首先遇到Promise構(gòu)造函數(shù),會先執(zhí)行里面的內(nèi)容吐句,打印
1
胁后; - 遇到定時(shí)器
steTimeout
,它是一個(gè)宏任務(wù)嗦枢,放入宏任務(wù)隊(duì)列攀芯; - 繼續(xù)向下執(zhí)行,打印出2文虏;
- 由于
Promise
的狀態(tài)此時(shí)還是pending
侣诺,所以promise.then
先不執(zhí)行; - 繼續(xù)執(zhí)行下面的同步任務(wù)氧秘,打印出4年鸳;
- 此時(shí)微任務(wù)隊(duì)列沒有任務(wù),繼續(xù)執(zhí)行下一輪宏任務(wù)丸相,執(zhí)行
steTimeout
搔确; - 首先執(zhí)行
timerStart
,然后遇到了resolve
,將promise
的狀態(tài)改為resolved
且保存結(jié)果并將之前的promise.then
推入微任務(wù)隊(duì)列膳算,再執(zhí)行timerEnd
座硕; - 執(zhí)行完這個(gè)宏任務(wù),就去執(zhí)行微任務(wù)
promise.then
畦幢,打印出resolve
的結(jié)果坎吻。
----問題知識點(diǎn)分割線----
函數(shù)柯里化
柯里化(currying) 指的是將一個(gè)多參數(shù)的函數(shù)拆分成一系列函數(shù),每個(gè)拆分后的函數(shù)都只接受一個(gè)參數(shù)宇葱。
對于已經(jīng)柯里化后的函數(shù)來說瘦真,當(dāng)接收的參數(shù)數(shù)量與原函數(shù)的形參數(shù)量相同時(shí),執(zhí)行原函數(shù)黍瞧; 當(dāng)接收的參數(shù)數(shù)量小于原函數(shù)的形參數(shù)量時(shí)诸尽,返回一個(gè)函數(shù)用于接收剩余的參數(shù),直至接收的參數(shù)數(shù)量與形參數(shù)量一致印颤,執(zhí)行原函數(shù)您机。
----問題知識點(diǎn)分割線----
對瀏覽器的緩存機(jī)制的理解
瀏覽器緩存的全過程:
瀏覽器第一次加載資源,服務(wù)器返回 200年局,瀏覽器從服務(wù)器下載資源文件际看,并緩存資源文件與 response header,以供下次加載時(shí)對比使用矢否;
下一次加載資源時(shí)仲闽,由于強(qiáng)制緩存優(yōu)先級較高,先比較當(dāng)前時(shí)間與上一次返回 200 時(shí)的時(shí)間差僵朗,如果沒有超過 cache-control 設(shè)置的 max-age赖欣,則沒有過期,并命中強(qiáng)緩存验庙,直接從本地讀取資源顶吮。如果瀏覽器不支持HTTP1.1,則使用 expires 頭判斷是否過期粪薛;
如果資源已過期悴了,則表明強(qiáng)制緩存沒有被命中,則開始協(xié)商緩存违寿,向服務(wù)器發(fā)送帶有 If-None-Match 和 If-Modified-Since 的請求湃交;
服務(wù)器收到請求后,優(yōu)先根據(jù) Etag 的值判斷被請求的文件有沒有做修改陨界,Etag 值一致則沒有修改巡揍,命中協(xié)商緩存,返回 304菌瘪;如果不一致則有改動(dòng)腮敌,直接返回新的資源文件帶上新的 Etag 值并返回 200阱当;
-
如果服務(wù)器收到的請求沒有 Etag 值,則將 If-Modified-Since 和被請求文件的最后修改時(shí)間做比對糜工,一致則命中協(xié)商緩存弊添,返回 304;不一致則返回新的 last-modified 和文件并返回 200捌木;
很多網(wǎng)站的資源后面都加了版本號油坝,這樣做的目的是:每次升級了 JS 或 CSS 文件后,為了防止瀏覽器進(jìn)行緩存刨裆,強(qiáng)制改變版本號澈圈,客戶端瀏覽器就會重新下載新的 JS 或 CSS 文件 ,以保證用戶能夠及時(shí)獲得網(wǎng)站的最新更新帆啃。
----問題知識點(diǎn)分割線----
如何避免ajax數(shù)據(jù)請求重新獲取
一般而言瞬女,ajax請求的數(shù)據(jù)都放在redux中存取。
----問題知識點(diǎn)分割線----
Promise.resolve
Promise.resolve = function(value) {
// 1.如果 value 參數(shù)是一個(gè) Promise 對象努潘,則原封不動(dòng)返回該對象
if(value instanceof Promise) return value;
// 2.如果 value 參數(shù)是一個(gè)具有 then 方法的對象诽偷,則將這個(gè)對象轉(zhuǎn)為 Promise 對象,并立即執(zhí)行它的then方法
if(typeof value === "object" && 'then' in value) {
return new Promise((resolve, reject) => {
value.then(resolve, reject);
});
}
// 3.否則返回一個(gè)新的 Promise 對象疯坤,狀態(tài)為 fulfilled
return new Promise(resolve => resolve(value));
}
----問題知識點(diǎn)分割線----
數(shù)組去重
使用 indexOf/includes 實(shí)現(xiàn)
function unique(arr) {
var res = [];
for(var i = 0; i < arr.length; i++) {
if(res.indexOf(arr[i]) === -1) res.push(arr[i]);
// if(!res.includes(arr[i])) res.push(arr[i]);
}
return res;
}
使用 filter(forEach) + indexOf/includes 實(shí)現(xiàn)
// filter
function unique(arr) {
var res = arr.filter((value, index) => {
// 只存第一個(gè)出現(xiàn)的元素
return arr.indexOf(value) === index;
});
return res;
}
// forEach
function unique(arr) {
var res = [];
arr.forEach((value) => {
if(!res.includes(value)) res.push(value);
});
return res;
}
非 API 版本(原生)實(shí)現(xiàn)
function unique(arr) {
var res = [];
for(var i = 0; i < arr.length; i++) {
var flag = false;
for(var j = 0; j < res.length; j++) {
if(arr[i] === res[j]) {
flag = true;
break;
}
}
if(flag === false) res.push(arr[i]);
}
return res;
}
ES6 使用 Set + 擴(kuò)展運(yùn)算符(...)/Array.from() 實(shí)現(xiàn)
function unique(arr) {
// return [...new Set(arr)];
return Array.from(new Set(arr));
}
----問題知識點(diǎn)分割線----
documentFragment 是什么报慕?用它跟直接操作 DOM 的區(qū)別是什么?
MDN中對documentFragment
的解釋:
DocumentFragment压怠,文檔片段接口眠冈,一個(gè)沒有父對象的最小文檔對象。它被作為一個(gè)輕量版的 Document使用刑峡,就像標(biāo)準(zhǔn)的document一樣洋闽,存儲由節(jié)點(diǎn)(nodes)組成的文檔結(jié)構(gòu)玄柠。與document相比突梦,最大的區(qū)別是DocumentFragment不是真實(shí) DOM 樹的一部分,它的變化不會觸發(fā) DOM 樹的重新渲染羽利,且不會導(dǎo)致性能等問題宫患。
當(dāng)我們把一個(gè) DocumentFragment 節(jié)點(diǎn)插入文檔樹時(shí),插入的不是 DocumentFragment 自身这弧,而是它的所有子孫節(jié)點(diǎn)娃闲。在頻繁的DOM操作時(shí),我們就可以將DOM元素插入DocumentFragment匾浪,之后一次性的將所有的子孫節(jié)點(diǎn)插入文檔中皇帮。和直接操作DOM相比,將DocumentFragment 節(jié)點(diǎn)插入DOM樹時(shí)蛋辈,不會觸發(fā)頁面的重繪属拾,這樣就大大提高了頁面的性能将谊。
----問題知識點(diǎn)分割線----
寫版本號排序的方法
題目描述:有一組版本號如下['0.1.1', '2.3.3', '0.302.1', '4.2', '4.3.5', '4.3.4.5']。現(xiàn)在需要對其進(jìn)行排序渐白,排序的結(jié)果為 ['4.3.5','4.3.4.5','2.3.3','0.302.1','0.1.1']
實(shí)現(xiàn)代碼如下:
arr.sort((a, b) => {
let i = 0;
const arr1 = a.split(".");
const arr2 = b.split(".");
while (true) {
const s1 = arr1[i];
const s2 = arr2[i];
i++;
if (s1 === undefined || s2 === undefined) {
return arr2.length - arr1.length;
}
if (s1 === s2) continue;
return s2 - s1;
}
});
console.log(arr);
----問題知識點(diǎn)分割線----
談一談隊(duì)頭阻塞問題
什么是隊(duì)頭阻塞尊浓?
對于每一個(gè)HTTP請求而言,這些任務(wù)是會被放入一個(gè)任務(wù)隊(duì)列中串行執(zhí)行的纯衍,一旦隊(duì)首任務(wù)請求太慢時(shí)栋齿,就會阻塞后面的請求處理,這就是HTTP隊(duì)頭阻塞
問題襟诸。
有什么解決辦法嗎??
并發(fā)連接
我們知道對于一個(gè)域名而言瓦堵,是允許分配多個(gè)長連接的,那么可以理解成增加了任務(wù)隊(duì)列歌亲,也就是說不會導(dǎo)致一個(gè)任務(wù)阻塞了該任務(wù)隊(duì)列的其他任務(wù)谷丸,在
RFC規(guī)范
中規(guī)定客戶端最多并發(fā)2個(gè)連接,不過實(shí)際情況就是要比這個(gè)還要多应结,舉個(gè)例子刨疼,Chrome中是6個(gè)。
域名分片
- 顧名思義鹅龄,我們可以在一個(gè)域名下分出多個(gè)二級域名出來揩慕,而它們最終指向的還是同一個(gè)服務(wù)器,這樣子的話就可以并發(fā)處理的任務(wù)隊(duì)列更多扮休,也更好的解決了隊(duì)頭阻塞的問題迎卤。
- 舉個(gè)例子,比如
TianTian.com
玷坠,可以分出很多二級域名蜗搔,比如Day1.TianTian.com
,Day2.TianTian.com
,Day3.TianTian.com
,這樣子就可以有效解決隊(duì)頭阻塞問題八堡。
----問題知識點(diǎn)分割線----
對原型樟凄、原型鏈的理解
在JavaScript中是使用構(gòu)造函數(shù)來新建一個(gè)對象的酸些,每一個(gè)構(gòu)造函數(shù)的內(nèi)部都有一個(gè) prototype 屬性迈倍,它的屬性值是一個(gè)對象,這個(gè)對象包含了可以由該構(gòu)造函數(shù)的所有實(shí)例共享的屬性和方法胶坠。當(dāng)使用構(gòu)造函數(shù)新建一個(gè)對象后挂谍,在這個(gè)對象的內(nèi)部將包含一個(gè)指針叔壤,這個(gè)指針指向構(gòu)造函數(shù)的 prototype 屬性對應(yīng)的值,在 ES5 中這個(gè)指針被稱為對象的原型口叙。一般來說不應(yīng)該能夠獲取到這個(gè)值的炼绘,但是現(xiàn)在瀏覽器中都實(shí)現(xiàn)了 proto 屬性來訪問這個(gè)屬性,但是最好不要使用這個(gè)屬性妄田,因?yàn)樗皇且?guī)范中規(guī)定的俺亮。ES5 中新增了一個(gè) Object.getPrototypeOf() 方法仗哨,可以通過這個(gè)方法來獲取對象的原型。
當(dāng)訪問一個(gè)對象的屬性時(shí)铅辞,如果這個(gè)對象內(nèi)部不存在這個(gè)屬性厌漂,那么它就會去它的原型對象里找這個(gè)屬性,這個(gè)原型對象又會有自己的原型斟珊,于是就這樣一直找下去苇倡,也就是原型鏈的概念。原型鏈的盡頭一般來說都是 Object.prototype 所以這就是新建的對象為什么能夠使用 toString() 等方法的原因囤踩。
特點(diǎn): JavaScript 對象是通過引用來傳遞的旨椒,創(chuàng)建的每個(gè)新對象實(shí)體中并沒有一份屬于自己的原型副本。當(dāng)修改原型時(shí)堵漱,與之相關(guān)的對象也會繼承這一改變综慎。
----問題知識點(diǎn)分割線----
函數(shù)柯里化
什么叫函數(shù)柯里化?其實(shí)就是將使用多個(gè)參數(shù)的函數(shù)轉(zhuǎn)換成一系列使用一個(gè)參數(shù)的函數(shù)的技術(shù)勤庐。還不懂示惊?來舉個(gè)例子。
function add(a, b, c) {
return a + b + c
}
add(1, 2, 3)
let addCurry = curry(add)
addCurry(1)(2)(3)
現(xiàn)在就是要實(shí)現(xiàn) curry 這個(gè)函數(shù)愉镰,使函數(shù)從一次調(diào)用傳入多個(gè)參數(shù)變成多次調(diào)用每次傳一個(gè)參數(shù)米罚。
function curry(fn) {
let judge = (...args) => {
if (args.length == fn.length) return fn(...args)
return (...arg) => judge(...args, ...arg)
}
return judge
}
----問題知識點(diǎn)分割線----
如何判斷數(shù)組類型
Array.isArray
----問題知識點(diǎn)分割線----
數(shù)組能夠調(diào)用的函數(shù)有那些?
- push
- pop
- splice
- slice
- shift
- unshift
- sort
- find
- findIndex
- map/filter/reduce 等函數(shù)式編程方法
- 還有一些原型鏈上的方法:toString/valudOf
----問題知識點(diǎn)分割線----
單行丈探、多行文本溢出隱藏
- 單行文本溢出
overflow: hidden; // 溢出隱藏
text-overflow: ellipsis; // 溢出用省略號顯示
white-space: nowrap; // 規(guī)定段落中的文本不進(jìn)行換行
- 多行文本溢出
overflow: hidden; // 溢出隱藏
text-overflow: ellipsis; // 溢出用省略號顯示
display:-webkit-box; // 作為彈性伸縮盒子模型顯示录择。
-webkit-box-orient:vertical; // 設(shè)置伸縮盒子的子元素排列方式:從上到下垂直排列
-webkit-line-clamp:3; // 顯示的行數(shù)
注意:由于上面的三個(gè)屬性都是 CSS3 的屬性,沒有瀏覽器可以兼容碗降,所以要在前面加一個(gè)-webkit-
來兼容一部分瀏覽器隘竭。
----問題知識點(diǎn)分割線----
介紹一下HTTPS和HTTP區(qū)別
HTTPS 要比 HTTPS 多了 secure 安全性這個(gè)概念,實(shí)際上讼渊, HTTPS 并不是一個(gè)新的應(yīng)用層協(xié)議动看,它其實(shí)就是 HTTP + TLS/SSL 協(xié)議組合而成,而安全性的保證正是 SSL/TLS 所做的工作精偿。
SSL
安全套接層(Secure Sockets Layer)
TLS
(傳輸層安全弧圆,Transport Layer Security)
現(xiàn)在主流的版本是 TLS/1.2, 之前的 TLS1.0赋兵、TLS1.1 都被認(rèn)為是不安全的笔咽,在不久的將來會被完全淘汰。
HTTPS 就是身披了一層 SSL 的 HTTP 霹期。
[圖片上傳失敗...(image-c15684-1662526631598)]
那么區(qū)別有哪些呢??
- HTTP 是明文傳輸協(xié)議叶组,HTTPS 協(xié)議是由 SSL+HTTP 協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議历造,比 HTTP 協(xié)議安全甩十。
- HTTPS比HTTP更加安全船庇,對搜索引擎更友好,利于SEO,谷歌侣监、百度優(yōu)先索引HTTPS網(wǎng)頁鸭轮。
- HTTPS標(biāo)準(zhǔn)端口443,HTTP標(biāo)準(zhǔn)端口80橄霉。
- HTTPS需要用到SSL證書窃爷,而HTTP不用。
我覺得記住以下兩點(diǎn)HTTPS主要作用就行??
- 對數(shù)據(jù)進(jìn)行加密姓蜂,并建立一個(gè)信息安全通道按厘,來保證傳輸過程中的數(shù)據(jù)安全;
- 對網(wǎng)站服務(wù)器進(jìn)行真實(shí)身份認(rèn)證。
HTTPS的缺點(diǎn)
- 證書費(fèi)用以及更新維護(hù)钱慢。
- HTTPS 降低一定用戶訪問速度(實(shí)際上優(yōu)化好就不是缺點(diǎn)了)逮京。
- HTTPS 消耗 CPU 資源,需要增加大量機(jī)器束莫。
----問題知識點(diǎn)分割線----
請實(shí)現(xiàn) DOM2JSON 一個(gè)函數(shù)懒棉,可以把一個(gè) DOM 節(jié)點(diǎn)輸出 JSON 的格式
題目描述:
<div>
<span>
<a></a>
</span>
<span>
<a></a>
<a></a>
</span>
</div>
把上訴dom結(jié)構(gòu)轉(zhuǎn)成下面的JSON格式
{
tag: 'DIV',
children: [
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] }
]
},
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] },
{ tag: 'A', children: [] }
]
}
]
}
實(shí)現(xiàn)代碼如下:
function dom2Json(domtree) {
let obj = {};
obj.name = domtree.tagName;
obj.children = [];
domtree.childNodes.forEach((child) => obj.children.push(dom2Json(child)));
return obj;
}
擴(kuò)展思考:如果給定的不是一個(gè) Dom 樹結(jié)構(gòu) 而是一段 html 字符串 該如何解析?
那么這個(gè)問題就類似 Vue 的模板編譯原理 我們可以利用正則 匹配 html 字符串 遇到開始標(biāo)簽 結(jié)束標(biāo)簽和文本 解析完畢之后生成對應(yīng)的 ast 并建立相應(yīng)的父子關(guān)聯(lián) 不斷的 advance 截取剩余的字符串 直到 html 全部解析完畢
----問題知識點(diǎn)分割線----
對執(zhí)行上下文的理解
1. 執(zhí)行上下文類型
(1)全局執(zhí)行上下文
任何不在函數(shù)內(nèi)部的都是全局執(zhí)行上下文,它首先會創(chuàng)建一個(gè)全局的window對象览绿,并且設(shè)置this的值等于這個(gè)全局對象漓藕,一個(gè)程序中只有一個(gè)全局執(zhí)行上下文。
(2)函數(shù)執(zhí)行上下文
當(dāng)一個(gè)函數(shù)被調(diào)用時(shí)挟裂,就會為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文享钞,函數(shù)的上下文可以有任意多個(gè)。
(3)eval
函數(shù)執(zhí)行上下文
執(zhí)行在eval函數(shù)中的代碼會有屬于他自己的執(zhí)行上下文诀蓉,不過eval函數(shù)不常使用栗竖,不做介紹。
2. 執(zhí)行上下文棧
- JavaScript引擎使用執(zhí)行上下文棧來管理執(zhí)行上下文
- 當(dāng)JavaScript執(zhí)行代碼時(shí)渠啤,首先遇到全局代碼狐肢,會創(chuàng)建一個(gè)全局執(zhí)行上下文并且壓入執(zhí)行棧中,每當(dāng)遇到一個(gè)函數(shù)調(diào)用沥曹,就會為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文并壓入棧頂份名,引擎會執(zhí)行位于執(zhí)行上下文棧頂?shù)暮瘮?shù),當(dāng)函數(shù)執(zhí)行完成之后妓美,執(zhí)行上下文從棧中彈出僵腺,繼續(xù)執(zhí)行下一個(gè)上下文。當(dāng)所有的代碼都執(zhí)行完畢之后壶栋,從棧中彈出全局執(zhí)行上下文辰如。
let a = 'Hello World!';
function first() {
console.log('Inside first function');
second();
console.log('Again inside first function');
}
function second() {
console.log('Inside second function');
}
first();
//執(zhí)行順序
//先執(zhí)行second(),在執(zhí)行first()
3. 創(chuàng)建執(zhí)行上下文
創(chuàng)建執(zhí)行上下文有兩個(gè)階段:創(chuàng)建階段和執(zhí)行階段
1)創(chuàng)建階段
(1)this綁定
- 在全局執(zhí)行上下文中,this指向全局對象(window對象)
- 在函數(shù)執(zhí)行上下文中贵试,this指向取決于函數(shù)如何調(diào)用琉兜。如果它被一個(gè)引用對象調(diào)用凯正,那么 this 會被設(shè)置成那個(gè)對象,否則 this 的值被設(shè)置為全局對象或者 undefined
(2)創(chuàng)建詞法環(huán)境組件
- 詞法環(huán)境是一種有標(biāo)識符——變量映射的數(shù)據(jù)結(jié)構(gòu)豌蟋,標(biāo)識符是指變量/函數(shù)名廊散,變量是對實(shí)際對象或原始數(shù)據(jù)的引用。
- 詞法環(huán)境的內(nèi)部有兩個(gè)組件:加粗樣式:環(huán)境記錄器:用來儲存變量個(gè)函數(shù)聲明的實(shí)際位置外部環(huán)境的引用:可以訪問父級作用域
(3)創(chuàng)建變量環(huán)境組件
- 變量環(huán)境也是一個(gè)詞法環(huán)境梧疲,其環(huán)境記錄器持有變量聲明語句在執(zhí)行上下文中創(chuàng)建的綁定關(guān)系奸汇。
2)執(zhí)行階段 此階段會完成對變量的分配,最后執(zhí)行完代碼往声。
簡單來說執(zhí)行上下文就是指:
在執(zhí)行一點(diǎn)JS代碼之前擂找,需要先解析代碼。解析的時(shí)候會先創(chuàng)建一個(gè)全局執(zhí)行上下文環(huán)境浩销,先把代碼中即將執(zhí)行的變量贯涎、函數(shù)聲明都拿出來,變量先賦值為undefined慢洋,函數(shù)先聲明好可使用塘雳。這一步執(zhí)行完了,才開始正式的執(zhí)行程序普筹。
在一個(gè)函數(shù)執(zhí)行之前败明,也會創(chuàng)建一個(gè)函數(shù)執(zhí)行上下文環(huán)境,跟全局執(zhí)行上下文類似太防,不過函數(shù)執(zhí)行上下文會多出this妻顶、arguments和函數(shù)的參數(shù)。
- 全局上下文:變量定義蜒车,函數(shù)聲明
- 函數(shù)上下文:變量定義讳嘱,函數(shù)聲明,
this
酿愧,arguments
----問題知識點(diǎn)分割線----
對Promise的理解
Promise是異步編程的一種解決方案沥潭,它是一個(gè)對象,可以獲取異步操作的消息嬉挡,他的出現(xiàn)大大改善了異步編程的困境钝鸽,避免了地獄回調(diào),它比傳統(tǒng)的解決方案回調(diào)函數(shù)和事件更合理和更強(qiáng)大庞钢。
所謂Promise拔恰,簡單說就是一個(gè)容器,里面保存著某個(gè)未來才會結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果焊夸。從語法上說仁连,Promise 是一個(gè)對象,從它可以獲取異步操作的消息阱穗。Promise 提供統(tǒng)一的 API饭冬,各種異步操作都可以用同樣的方法進(jìn)行處理。
(1)Promise的實(shí)例有三個(gè)狀態(tài):
- Pending(進(jìn)行中)
- Resolved(已完成)
- Rejected(已拒絕)
當(dāng)把一件事情交給promise時(shí)揪阶,它的狀態(tài)就是Pending昌抠,任務(wù)完成了狀態(tài)就變成了Resolved、沒有完成失敗了就變成了Rejected鲁僚。
(2)Promise的實(shí)例有兩個(gè)過程:
- pending -> fulfilled : Resolved(已完成)
- pending -> rejected:Rejected(已拒絕)
注意:一旦從進(jìn)行狀態(tài)變成為其他狀態(tài)就永遠(yuǎn)不能更改狀態(tài)了炊苫。
Promise的特點(diǎn):
- 對象的狀態(tài)不受外界影響。promise對象代表一個(gè)異步操作冰沙,有三種狀態(tài)侨艾,
pending
(進(jìn)行中)、fulfilled
(已成功)拓挥、rejected
(已失斶肜妗)。只有異步操作的結(jié)果侥啤,可以決定當(dāng)前是哪一種狀態(tài)当叭,任何其他操作都無法改變這個(gè)狀態(tài),這也是promise這個(gè)名字的由來——“承諾”盖灸; - 一旦狀態(tài)改變就不會再變蚁鳖,任何時(shí)候都可以得到這個(gè)結(jié)果。promise對象的狀態(tài)改變赁炎,只有兩種可能:從
pending
變?yōu)?code>fulfilled醉箕,從pending
變?yōu)?code>rejected。這時(shí)就稱為resolved
(已定型)徙垫。如果改變已經(jīng)發(fā)生了琅攘,你再對promise對象添加回調(diào)函數(shù),也會立即得到這個(gè)結(jié)果松邪。這與事件(event)完全不同坞琴,事件的特點(diǎn)是:如果你錯(cuò)過了它,再去監(jiān)聽是得不到結(jié)果的逗抑。
Promise的缺點(diǎn):
- 無法取消Promise剧辐,一旦新建它就會立即執(zhí)行,無法中途取消邮府。
- 如果不設(shè)置回調(diào)函數(shù)荧关,Promise內(nèi)部拋出的錯(cuò)誤,不會反應(yīng)到外部褂傀。
- 當(dāng)處于pending狀態(tài)時(shí)忍啤,無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。
總結(jié): Promise 對象是異步編程的一種解決方案,最早由社區(qū)提出同波。Promise 是一個(gè)構(gòu)造函數(shù)鳄梅,接收一個(gè)函數(shù)作為參數(shù),返回一個(gè) Promise 實(shí)例未檩。一個(gè) Promise 實(shí)例有三種狀態(tài)戴尸,分別是pending、resolved 和 rejected冤狡,分別代表了進(jìn)行中孙蒙、已成功和已失敗。實(shí)例的狀態(tài)只能由 pending 轉(zhuǎn)變 resolved 或者rejected 狀態(tài)悲雳,并且狀態(tài)一經(jīng)改變挎峦,就凝固了,無法再被改變了合瓢。
狀態(tài)的改變是通過 resolve() 和 reject() 函數(shù)來實(shí)現(xiàn)的坦胶,可以在異步操作結(jié)束后調(diào)用這兩個(gè)函數(shù)改變 Promise 實(shí)例的狀態(tài),它的原型上定義了一個(gè) then 方法歪玲,使用這個(gè) then 方法可以為兩個(gè)狀態(tài)的改變注冊回調(diào)函數(shù)迁央。這個(gè)回調(diào)函數(shù)屬于微任務(wù),會在本輪事件循環(huán)的末尾執(zhí)行滥崩。
注意: 在構(gòu)造 Promise
的時(shí)候岖圈,構(gòu)造函數(shù)內(nèi)部的代碼是立即執(zhí)行的