- 數(shù)據(jù)類(lèi)型
- 原型鏈
- this
- new
- 立即執(zhí)行函數(shù)
- 閉包
1山上、JS數(shù)據(jù)類(lèi)型
- 字符串string景图、數(shù)字number固蛾、布爾Boolean
- undefined、null(JS兩個(gè)空)分
別什么時(shí)候用:對(duì)象為空null 非對(duì)象為空undefined(只是一種約定而已) - 大整數(shù)bigint次氨、符號(hào)symbol(es6新加的)
為什么需要bigint之前的number難道不能用嘛?
因?yàn)镴Snumber默認(rèn)是一個(gè)雙精度浮點(diǎn)數(shù)(1--1.0)蔽介,精度有限。bigint,精度無(wú)限煮寡。(如果你的數(shù)字特別大本身的number無(wú)法支持在后面加個(gè)n虹蓄,僅支持整數(shù)).
symbol(自己做庫(kù)用的),比較高級(jí)初級(jí)一般不用洲押。 - 對(duì)象object(數(shù)組武花、函數(shù)圆凰、日期等這些是對(duì)象中的類(lèi)class不是類(lèi)型type)
2杈帐、原型鏈?zhǔn)鞘裁矗?/h3>
答:
1、原型鏈涉及到的概念比較多专钉,我先舉例說(shuō)明一下吧挑童。
- 原型:
假設(shè)有一個(gè)普通的對(duì)象 x = {}, 這個(gè)x會(huì)有一個(gè)隱藏屬性 proto,這個(gè)屬性會(huì)指向Object.prototype.
x.proto === Object.prototype.
此時(shí)我們說(shuō)x的原型是Object.prototype,或者說(shuō)Object.prototype是x的原型跃须。
proto 屬性的唯一作用就是用來(lái)指向x的原型的站叼。 - 原型鏈:
假設(shè)我們有一個(gè)數(shù)組對(duì)象 a = [],這個(gè)a也有一個(gè)隱藏屬性proto.這個(gè)屬性會(huì)指向Array.prototype.
a.proto === Array.prototype. 同時(shí)Array.prototype也有這樣一個(gè)隱藏屬性菇民,Array.prototype.proto指向Object.prototype尽楔,這樣一來(lái) a就有兩層原型,通過(guò)隱藏屬性proto形成了一個(gè)鏈條第练。函數(shù)Function阔馋、Date、Reg(正則)等同理娇掏。
這就是原型鏈呕寝。
極簡(jiǎn)回答:a的原型是b b的原型是c那么就形成了原型鏈。
2婴梧、如何實(shí)現(xiàn)一個(gè)原型鏈
之前都是JS引擎提供的 我自己寫(xiě)一個(gè)東西 它有原型鏈行不行下梢。
a = {} b = {}
a.proto = b
b.proto = Object
自己改一下即可,錯(cuò)的塞蹭,但是對(duì)知識(shí)點(diǎn)的理解是對(duì)的孽江。
1、要用create不可以直接賦值(ES6的方法)
a = Object.create(b),把a(bǔ)的原型置為b
2番电、new(ES5的方法)
a = new f() f必須是一個(gè)構(gòu)造函數(shù) 竟坛,此時(shí)a.proto = f.prototype
//詳見(jiàn)下面題
3、原型鏈解決了什么問(wèn)題?
在沒(méi)有Class的情況下實(shí)現(xiàn)繼承担汤。(ES5沒(méi)有class,ES6之前繼承都是通過(guò)原型鏈涎跨,繼承詳見(jiàn)后面)
以a ===> Array.prototype ===>Object.prototype為例
- a是Array的實(shí)例,a擁有Array.prototype里的屬性
- Arrya繼承了Object
- a是Object的間接實(shí)例崭歧,a擁有Object.prototype里的屬性
這樣一來(lái)隅很,a既擁有Array.prototype里的屬性,又擁有Object.prototype里的屬性率碾。
原型鏈優(yōu)點(diǎn):簡(jiǎn)單叔营、優(yōu)雅
跟class相比不支持私有屬性。
如何解決,使用class即可
私有屬性:
比如你a.prpto = b
b中有一個(gè)函數(shù)所宰,c
那就可以a.c
我沒(méi)有辦法讓b擁有自己的屬性而能不被a使用绒尊。
class可以
繼承 是什么?
calssB
classA extends B 這就是A繼承了B
所以說(shuō)在技術(shù)層面上 繼承是兩個(gè)類(lèi)的關(guān)系仔粥。沒(méi)有對(duì)象
var a = new Array(1,2,3)
a.length不是從Array上面繼承到的
一個(gè)對(duì)象擁有其構(gòu)造函數(shù)或類(lèi)的屬性不叫繼承婴谱,這叫實(shí)例化
只能說(shuō)a是Array實(shí)例
a.valueof 是繼承 它不是Array提供的而是Object.prototype
Array是a的類(lèi) Object.prototype是它的父類(lèi),如果這個(gè)屬性是從它父類(lèi)那里得到的就是繼承躯泰。
數(shù)組繼承了對(duì)象谭羔。跟a沒(méi)關(guān)系。
https://www.zhihu.com/question/56770432/answer/315342130
3麦向、xxx這段代碼的this是什么瘟裸?
this是什么? this是call的第一個(gè)參數(shù)
- f1() 等價(jià)于f1.call(undefined)
- f1(‘hi’) 等價(jià)于f1.call(undefined,'hi')
瀏覽器一旦發(fā)現(xiàn)this是undefined就會(huì)把他轉(zhuǎn)成window
左邊只是語(yǔ)法糖,所有的調(diào)用都是call才是正常形式
就像a = [] 的真正寫(xiě)法是 a = new Array()
obj.child.say()這個(gè)函數(shù) 叫什么呢诵竭?
沒(méi)有名字话告,在內(nèi)存中是按照如下存儲(chǔ)的,505就是505只是say存著他的地址卵慰。
所以說(shuō)這個(gè)函數(shù)和這個(gè)對(duì)象沒(méi)有關(guān)系沙郭,就需要把這個(gè)對(duì)象傳給函數(shù),不然函數(shù)如何知道是哪個(gè)對(duì)象調(diào)用它呵燕。
假設(shè)我把505叫f,f只是存在了say屬性中棠绘,然后say所在的對(duì)象調(diào)用的這個(gè)函數(shù)要傳進(jìn)去。f.call(obj.child)再扭。
obj.child.say() 等價(jià)于 obj.child.say.call(obj.child,'hi')
不用看那么多就去找它最后一次執(zhí)行氧苍,看執(zhí)行的時(shí)候的this即可。
所以就是undefined泛范,所以變?yōu)閣indow
全局變量var出來(lái)的會(huì)自動(dòng)編程window上的屬性 所以window.length = 4
箭頭函數(shù)沒(méi)有this,看到this就先往外看让虐,沒(méi)有就是undefined
https://zhuanlan.zhihu.com/p/23804247
(題外話(huà)為什么有時(shí)候用 call 有時(shí)候用apply)
f.call(u,1,2) f.apply(u,[1,2])
假設(shè)我 var a = redListFromFile() 讀取一個(gè)文件 得到一個(gè)數(shù)組【1罢荡,2赡突,...】
如果我要把a(bǔ)傳進(jìn)一個(gè)函數(shù)
a.call(undefined,a[0],a[1],......)
ES6新語(yǔ)法 a.call(undefined,...a)
但是es6之前也要解決這個(gè)問(wèn)題 所以使用apply
a.apply(undefined,a)
4对扶、new做了什么(記憶題,一般我們不關(guān)心只需要知道new的時(shí)候創(chuàng)建了一個(gè)新的對(duì)象)
1惭缰、創(chuàng)建一個(gè)臨時(shí)對(duì)象
2浪南、綁定原型
3、指定this = 臨時(shí)對(duì)象(不然你訪(fǎng)問(wèn)不到臨時(shí)對(duì)象)
4漱受、執(zhí)行構(gòu)造函數(shù)(就是士兵添加id,生命)
5络凿、返回臨時(shí)對(duì)象
https://zhuanlan.zhihu.com/p/23987456
Object、Array等的prototype昂羡,是為了方便new去給他們創(chuàng)建出來(lái)的對(duì)象添加共有屬性絮记。
Object、Array是用來(lái) 給他賦值自身屬性的虐先。
就像士兵是用來(lái)添加自身屬性怨愤,士兵.prototype是添加共有屬性
5、立即執(zhí)行函數(shù)是什么蛹批?
概念題:
是什么撰洗?
聲明一個(gè)匿名函數(shù),然后立即執(zhí)行它般眉。這種做法就是立即執(zhí)行函數(shù)了赵。
怎么做潜支?
注意第一個(gè)例子立即執(zhí)行函數(shù)要加甸赃;不然返回值為undefined 會(huì)和后面的連起來(lái)
解決了什么?
在ES6之前只能通過(guò)它來(lái)創(chuàng)建局部作用域冗酿。
優(yōu)點(diǎn):兼容性好
缺點(diǎn):丑
如何解決丑埠对,使用ES6的block+let語(yǔ)法
!function(){
var a
}()
{
let a//這里不能用var 不然它還是一個(gè)全局變量
}
console.log(a)//undefined
6裁替、閉包是什么项玛,如何用?
概念題
是什么?
- 閉包是JS的一種語(yǔ)法特性
- 閉包 = 函數(shù)+自由變量
何為自由變量(非全局變量)弱判,與之對(duì)應(yīng)的是全局變量襟沮,函數(shù)本來(lái)就可以訪(fǎng)問(wèn)全局變量,如果函數(shù)訪(fǎng)問(wèn)全局變量的話(huà)昌腰,并不能稱(chēng)之為閉包开伏。
大部分語(yǔ)言都支持,語(yǔ)言可以選擇支持或不支持閉包遭商,不是什么對(duì)象固灵、函數(shù),是一種語(yǔ)法特性劫流。
JS所有函數(shù)都是閉包巫玻?
函數(shù)是對(duì)象丛忆,不是語(yǔ)法特性。
可以說(shuō)JS所有函數(shù)都支持閉包仍秤。
怎么做熄诡?
聲明一個(gè)變量,在函數(shù)中訪(fǎng)問(wèn)這個(gè)變量诗力。閉包形成了粮彤,
let a //全局變量
{
let count //自由變量
function add (){ //訪(fǎng)問(wèn)了外部變量的函數(shù)
let a //局部變量
count += 1
}
}
如果count 不是全局變量也不是add函數(shù)的局部變量則稱(chēng)之為自由變量。(對(duì)于這個(gè)函數(shù)來(lái)說(shuō)的)
此代碼放在非全局環(huán)境中姜骡,就是閉包导坟。
可以用我上面的寫(xiě)法或者立即執(zhí)行函數(shù)哦
解決了什么問(wèn)題?(應(yīng)用場(chǎng)景)
游戲中有一個(gè)生命值
{
let lives = 3
window.getLives = function(){return lives}
window.die = ()=>{lives -=1}
window.award = ()=>{lives +=1}
}
window.getLives()
- 隱藏變量(外部訪(fǎng)問(wèn)不到圈澈,通過(guò)訪(fǎng)問(wèn)器可以)
- 暴露訪(fǎng)問(wèn)器
專(zhuān)業(yè)點(diǎn)的說(shuō)法
- 避免污染全局環(huán)境惫周。(因?yàn)闆](méi)有用全局變量而是用的局部變量)
- 提供局部變量的間接訪(fǎng)問(wèn)。
- 維持變量康栈,使其不被垃圾回收
(但是這個(gè)變量我一直在用递递,本身就不會(huì)被回收,除非關(guān)閉游戲)
面試官如果問(wèn)就直接寫(xiě)這個(gè)最終版本就行了啥么。
立即執(zhí)行函數(shù)寫(xiě)法
var api = function(){
let lives = 3
return{
getLives :()=> lives
die : ()=>{lives -=1}
award : ()=>{lives +=1}
}
}()
api.getLives
api.die // lives -= 1
優(yōu)點(diǎn):簡(jiǎn)單登舞、好用
缺點(diǎn):閉包使用不當(dāng)可能造成內(nèi)存泄漏
(由于舊版本的IE導(dǎo)致的問(wèn)題)
重點(diǎn)是使用不當(dāng)而不是閉包,
function test() {
var x = {name: 'x'};
var y = {name: 'y', content: "-----這里很長(zhǎng),有一萬(wàn)三千五百個(gè)字符那么長(zhǎng)----" }
return function fn() {
return x;
//就是此處return執(zhí)行后悬荣,這個(gè)y是不是就應(yīng)該垃圾回收了菠秒,因?yàn)槲覜](méi)用。
//由于IE的bug 會(huì)導(dǎo)致 你在當(dāng)前自由變量中用到了x氯迂,y就不會(huì)被回收
//閉包間接造成的y的內(nèi)存泄露践叠,理論上應(yīng)該消失 但是它還占內(nèi)存
};
}
const myFn = test() // myFn 就是 fn 了
const myX = myFn() // myX 就是 x 了
// 請(qǐng)問(wèn),y 會(huì)消失嗎嚼蚀?
對(duì)于一個(gè)正常的瀏覽器來(lái)說(shuō)禁灼,y 會(huì)在一段時(shí)間后自動(dòng)消失(被垃圾回收器給回收掉)。
但舊版本的 IE 并不是正常的瀏覽器轿曙,所以是 IE 的問(wèn)題弄捕。
怎么解決缺點(diǎn):
慎用,少用导帝,不用守谓。(我偏要用)
如果問(wèn)到閉包建議用一下代碼和他說(shuō):因?yàn)檫@個(gè)概念已經(jīng)對(duì)他們根深蒂固了
答題重點(diǎn)是什么?+以下代碼舟扎,+解決了什么(三個(gè)優(yōu)點(diǎn))
const add2 = function (){
var count
return function add (){ // 訪(fǎng)問(wèn)了外部變量的函數(shù)
count += 1
}
}()
https://zhuanlan.zhihu.com/p/22486908