1.說出并解釋下列代碼的輸出結(jié)果:
function Foo() {
getName = function () {
console.log(1);
};
return this;
}
Foo.getName = function () {
console.log(2);
};
Foo.prototype.getName = function () {
console.log(3);
};
var getName = function () {
console.log(4);
};
function getName() {
console.log(5);
}
Foo.getName(); //2
Foo().getName(); //1
getName(); //1
new Foo.getName(); //2
new Foo().getName(); //3
new new Foo().getName(); //3
解析
(1) . Foo.getName()
直接調(diào)用 Foo 的靜態(tài)方法 ,Foo.getName被重新復制,所以打印2
(2). Foo().getName()
Foo() 就是普通函數(shù),返回的this是window,后面調(diào)用window.getName(),而winsow下的getName在第一步調(diào)用的時候被重新復制,所以打印1
(3). getName()
調(diào)用window中的getName,由于window中的getName在(2)中執(zhí)行的時候被重新賦值,所以打印1.
(如果將(3)放在(2)前面執(zhí)行,打印結(jié)果就為4)
(4). new Foo.getName()
同(1)效果一樣,直接調(diào)用 Foo 的靜態(tài)方法 ,Foo.getName被重新復制,所以打印2
(5). new Foo().getName()
通過實例訪問 Foo原型鏈上的方法,所以打印3
(6) . new new Foo().getName()
首先 new Foo() 得到一個空對象 {}
第二步向空對象中添加一個屬性 getName,值為一個函數(shù)
第三步 new {}.getName()
等價于 var bar = new (new Foo().getName)(); console.log(bar) 先 new Foo 得到的實例對象上的 getName 方法,再將這個原型上 getName 方法當做構(gòu)造函數(shù)繼續(xù) new ,所以執(zhí)行原型上的方法,打印 3
2.寫出打印結(jié)果,并分析出原因
var a = 10
var obj = {
a: 100,
pro: {
getPro: () => {
console.log(this.a)
},
},
}
obj.pro.getPro() //10
解析
getPro是一個箭頭函數(shù)的方法,在箭頭函數(shù)中不會創(chuàng)建自己的this,只會集成作用于鏈上一層的this,所以這里的this指向為window,打印結(jié)果為10
3.寫出打印結(jié)果,并分析出原因
var a = { n: 1 }
var b = a
a.x = a = { n: 2 }
console.log(a.x) // undefined
console.log(b.x) // {n:2}
解析
首先,雙等號的執(zhí)行順序是從左到右
那么a.x = a = {n:2} 就等價于 a.x = a ; a={n:2}
由于b = a 屬于淺拷貝,那么再對a賦值時也會傳遞給b, 經(jīng)過a.x處理過后b.x = {n:1},然后將{n:2}賦值給a同時會傳遞給b.x
此時的a={n:2} , b={n: 1,x: {n: 2}}
所以打印結(jié)果依次為 undefined , {n: 2}
4.寫出打印結(jié)果,并分析出原因
var length = 10
function fn(){
console.log(this.length)
}
var obj = {
length : 5 ,
method :function (fn){
fn();
arguments[0]()
}
}
obj.method(fn,1)
解析
首先,我在全局定義了一個變量length,一個對象obj和一個函數(shù)fn . length賦值為10。
接下來是fn函數(shù),輸出this.length,對象obj中obj.length是5,obj.method是一個函數(shù),這個函數(shù)里面調(diào)用了fn函數(shù),arguments是一個偽數(shù)組,代表method函數(shù)的實參
method函數(shù)當中調(diào)用的fn函數(shù)是全局當中的函數(shù),所以this指向的是window,this.length就是10,arguments0代表的就是調(diào)用arguments里面的第一項,也就是傳參進來的fn,所以這個this指向的就是arguments,arguments.length的值為2
所以最后的打印結(jié)果為10 ,2
5.寫出打印結(jié)果,并分析出原因
function a(xx){
this.x = xx
return this
}
var x = a(5)
var y = a(6)
console.log(x.x)
console.log(y.x)
解析
首先,我們在全局定義了一個變量x,一個變量y,和一個函數(shù)a,函數(shù)a當中的this.x等于接受到的參數(shù),返回this,.這里要注意,返回的是this,不是this.x 接下來我們給X賦值 值為a(5) ,又給y賦值,值為a(6).最后我們輸出x.x 和y.x
分析完代碼的定義, 我們來看輸出結(jié)果, a(5) 執(zhí)行的時候傳遞一個參數(shù)為5,調(diào)用函數(shù)a, 返回this 此時的this指向window, 所以 x = window , 但是后面又執(zhí)行了y=a(6), 再次調(diào)用fn 將 this.x修改為6, 所以此時window中的 x 為6, 返回結(jié)果為window, 所以y=window,
由于 x =6 所以x.x = undefined, y=window, window中的x為6 , 所以y.x 為 6
打印結(jié)果依次為 undefined 和 6
6.閱讀下面代碼,寫出打印結(jié)果的先后順序
new Promise(function (resolve, reject) {
console.log('A')
resolve()
}) //A J B H K C I L D G E F
.then(function (resolve, reject) {
new Promise(function (resolve, reject) {
console.log('B')
resolve()
})
.then(function () {
console.log('c')
})
.then(function () {
new Promise(function (resolve, reject) {
console.log('D')
resolve()
})
.then(function () {
console.log('E')
})
.then(function () {
console.log('F')
})
console.log('G')
})
console.log('H')
})
.then(function () {
console.log('I')
})
new Promise(function (resolve, reject) {
console.log('J')
resolve()
})
.then(function () {
console.log('K')
})
.then(function () {
console.log('L')
})
打印結(jié)果
A J B H K C I L D G E F
解析:
注:下文中的輪次只是為了方便理解
首先,我們來看最外層的兩個newPromise,里面同步語句會先執(zhí)行,所以最先打印出來的是A和J
因為每個Promise都會產(chǎn)生一個微任務(wù),所以到第一輪的微任務(wù)中Promise的第一個then會進入到第一輪的微任務(wù)中,下面我們來單獨看這兩個then. 第一個Promise的第一個then里面又new了一個新的Promise,這個新的Promise產(chǎn)生一個微任務(wù),本輪的微任務(wù)已經(jīng)在執(zhí)行中了,所以這個微任務(wù)會排到下一個微任務(wù)隊列的第一位,還是先執(zhí)行里面的同步語句,打印B和H ,之后運行低二個Promise的第一個then,打印K
第一輪的微任務(wù)執(zhí)行完畢,開始第二輪微任務(wù),先執(zhí)行第三個Promise的第一個then,打印C,繼續(xù)執(zhí)行第一個Promise的第二個then,打印I,最后執(zhí)行第二個Promise的第二個then,打印K
第三輪微任務(wù)開始,執(zhí)行第三個Promise的第二個then,這個then里面又new了一個新的Promise,同理,新的Promise(第四個)產(chǎn)生的微任務(wù)放入下一輪第一個執(zhí)行,此時執(zhí)行同步語句,打印D和G
第四輪微任務(wù)開始執(zhí)行第四個Promise的第一個then,打印E
第五輪微任務(wù)開始執(zhí)行第四個Promise的第二個then,打印F
綜上,我們最后得到的結(jié)果就是:
A
J
B
H
K
C
I
L
D
G
E
F
7.閱讀下面代碼,寫出他們的打印順序
new Promise((resolve,reject)=>{
console.log('A')
setTimeout(() => {
console.log('B')
}, 0);
console.log('C')
resolve()
console.log('D')
}).then((resolve,reject)=>{
console.log('E')
new Promise((resolve,reject)=>{
console.log("F")
resolve()
console.log('G')
}).then(()=>{
setTimeout(()=>{
console.log('H')
})
console.log('I')
}).then(()=>{
console.log('J')
})
}).then(()=>{
console.log('K')
})
setTimeout(() => {
console.log('L')
}, 0);
new Promise((resolve,reject)=>{
console.log('M')
resolve()
}).then(()=>{
setTimeout(() => {
new Promise((resolve,reject)=>{
console.log('N')
resolve()
}).then(()=>{
setTimeout(()=>{
console.log('O')
},0)
}).then(()=>{
console.log('p')
})
}, 0);
})
console.log('Q')
打印結(jié)果
ACDMQEFGKJBLNPHO
解析
首先,我們要知道微任務(wù)會先于宏任務(wù)執(zhí)行,知道了這一點,我們來看下面的代碼.
現(xiàn)在,我們將微任務(wù)列表和宏任務(wù)列表分開梳理,最后再合并結(jié)果
先看微任務(wù),第一層為Promise--promise--console.log,第一個Promise中的setTimeOut創(chuàng)建宏任務(wù)1,最外層的setTimeOut創(chuàng)建宏任務(wù)2
所以第一輪按從上到下順序打印 A,C,D,M,Q
然后看第二輪微任務(wù),分別為第一個Promise中的then,和第二個Promise中的then,由于第二個Promise中的then中執(zhí)行setTimeOut,創(chuàng)建宏任務(wù)3,所以第二輪先打印 E,然后創(chuàng)建Promsie,打印F和G,目前的及結(jié)果為A,C,D,M,Q,E,F,G
然后看第三輪,由于第二個Promise中的then中創(chuàng)建了宏任務(wù),所以第三輪微任務(wù)只在第一個promise中的第二個then中,從代碼中可以看出,第一個Promise中的第一個then執(zhí)行后,有兩個then,前者創(chuàng)建宏任務(wù)4,打印I,后者打印K,所以目前打印順序為A,C,D,M,Q,E,F,G,I,K
然后第四輪微任務(wù)只剩下第三輪中的第二個then所調(diào)用的then了,打印結(jié)果為J,至此,微任務(wù)已經(jīng)執(zhí)行完畢,結(jié)果順序為:
A,C,D,M,Q,E,F,G,I,K,J
開始執(zhí)行宏任務(wù),第一輪按上方創(chuàng)建順序為宏任務(wù)1,2,3,4
宏任務(wù)1打印B,宏任務(wù)2打印L,宏任務(wù)3 第一輪微任務(wù)打印N,然后第二輪創(chuàng)建宏任務(wù)5,第三輪打印P, 宏任務(wù)4打印H
第一輪宏任務(wù) 打印順序為B,L,N,P,H
第二輪宏任務(wù)執(zhí)行宏任務(wù)3創(chuàng)建的宏任務(wù)5,打印O
至此,宏任務(wù)執(zhí)行完畢,結(jié)果為B,L,N,P,H
由于宏任務(wù)是在微任務(wù)執(zhí)行完成后執(zhí)行,所以需要將宏任務(wù)的打印結(jié)果連接在微任務(wù)后方,結(jié)果為
A
C
D
M
Q
E
F
G
I
K
J
B
L
N
P
H
O
8.力扣 - 檸檬水找零
在檸檬水攤上,每一杯檸檬水的售價為5美元
顧客排隊購買你的產(chǎn)品,(按賬單bills支付的順序)一次購買一杯
每位顧客只買一杯檸檬水,然后向你付5美元、10美元或者20美元。你必須給每個顧客正確找零,也就是說凈交易是每位顧客向你支付5美元
注意,一開始你手頭沒有任何零錢
如果你能給每位顧客正確找零,返回true,否則返回false
function func(bills) {
let a = 0 //5元
let b = 0 //10元
//循環(huán)所有數(shù)據(jù)
for (let i = 0; i < bills.length; i++) {
//如果顧客給的是5元
if (bills[i] === 5) {
// 手中的5元加一
a += 1
} else if (bills[i] === 10) {
//顧客給的是10元
//手中的5元減一,10元加一
b += 1
a -= 1
} else {
//顧客給的是20元,有兩種找零方式
// 找3個5元, 或者找1個10元1個5元
if (b >= 1) {
//10元足夠的時候優(yōu)先找一個10元一個5元
//10元減一,5元減一
a -= 1
b -= 1
} else {
//10元不夠是找三個5元, 5元減3
a -= 3
}
}
//當5元也不夠時說明沒有零錢了,返回false
if (a < 0) {
return false
}
}
//循環(huán)完成,說明零錢足夠,返回true
return true
}
let result = func([5, 5, 5, 10, 20])
console.log(result)