本文章所以知識(shí)點(diǎn)都來(lái)自于https://yuchengkai.cn/docs/frontend/#typeof
JS基本類型
- js有七大內(nèi)置類型分別是:
object
number
string
symbol
boolean
null
undefined
-
NAN
屬于number辅柴,且NAN
不等于本身 -
typeof
對(duì)于基本類型除了null
都顯示其類型
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof variable // variable 沒(méi)有生命栅哀,但是還是會(huì)顯示'undefined'
-
typeof
對(duì)于對(duì)象,除了函數(shù)都會(huì)顯示object
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
typeof null // 'object'
關(guān)于
typeof null // 'object'
甥桂,為什么會(huì)出現(xiàn)這種情況呢?因?yàn)樵?JS 的最初版本中懂酱,使用的是 32 位系統(tǒng)肥印,為了性能考慮使用低位存儲(chǔ)了變量的類型信息性锭,000
開(kāi)頭代表是對(duì)象,然而null
表示為全零涉兽,所以將它錯(cuò)誤的判斷為object
招驴。雖然現(xiàn)在的內(nèi)部類型判斷代碼已經(jīng)改變了,但是對(duì)于這個(gè) Bug 卻是一直流傳下來(lái)枷畏。如果我們想獲得一個(gè)變量的正確類型别厘,可以通過(guò)Object.prototype.toString.call(xx)
這樣我們就可以獲得類似 [object Type] 的字符串。
-
轉(zhuǎn)Boolean
-
undefined
null
false
NAN
''
0
-0
轉(zhuǎn)化成boolean值得時(shí)候?yàn)?code>false其他都為true
-
-
對(duì)象轉(zhuǎn)基本類型
- 對(duì)象轉(zhuǎn)基本類型的時(shí)候拥诡,首先會(huì)調(diào)用
valueOf
然后再調(diào)用toString
雙等號(hào)轉(zhuǎn)化優(yōu)先級(jí): string => boolean => numbernull == undefined // true
- 對(duì)象轉(zhuǎn)基本類型的時(shí)候拥诡,首先會(huì)調(diào)用
原型
Q:簡(jiǎn)單介紹原型和原型鏈
A:js的對(duì)象都有它的原型對(duì)象触趴,通過(guò)構(gòu)造函數(shù)構(gòu)造出來(lái)的對(duì)象,其原型就是該構(gòu)造函數(shù)的protoType屬性渴肉。訪問(wèn)對(duì)象的屬性或方法時(shí)若不存在冗懦,則會(huì)從對(duì)象的原型上尋找,若在原型上也找不到仇祭,則會(huì)繼續(xù)造原型對(duì)象的原型上找披蕉,以此類推。
new運(yùn)算符優(yōu)先級(jí)
new Foo.getName()
new Foo().getName()
相當(dāng)于
new (Foo.getName());
(new Foo()).getName();
前者是先計(jì)算Foo.getName
后者是先使用new Foo 產(chǎn)生了一個(gè)示例乌奇,然后再調(diào)用原型鏈上的getName方法
instanceof
instanceof 有兩個(gè)操作函數(shù) cat instanceof Animal
cat是某個(gè)實(shí)例對(duì)象没讲, Animal是某個(gè)構(gòu)造函數(shù)
instanceof實(shí)際上就是判斷對(duì)象的原型是否綁定在該構(gòu)造函數(shù)的prototype屬性上
this
- 取決于當(dāng)前調(diào)用的對(duì)象。如果當(dāng)前沒(méi)有調(diào)用對(duì)象礁苗,那么在非嚴(yán)格模式下爬凑,調(diào)用該方法的
this
是windows
。在嚴(yán)格模式下會(huì)報(bào)錯(cuò)试伙。 - 其次嘁信,
call
、apply
疏叨、bind
等方法改變的this就是你在調(diào)用時(shí)傳入的this
-
new
運(yùn)算符產(chǎn)生的示例吱抚,this
指向示例本身。
執(zhí)行上下文
- 變量提升: 聲明的代碼移動(dòng)到頂部考廉。執(zhí)行上下文時(shí)秘豹,會(huì)有兩個(gè)階段:
- 第一個(gè)階段是創(chuàng)建的階段,js解釋器會(huì)找到需要提升的變量和函數(shù)昌粤,并且給他們提前再內(nèi)存中開(kāi)辟好空間既绕,函數(shù)的話會(huì)將整個(gè)函數(shù)存入內(nèi)存中啄刹,變量只聲明并且賦值為undefined。
- 第二個(gè)階段是代碼執(zhí)行階段凄贩,可以直接提前使用
- 提升的過(guò)程中誓军,相同函數(shù)會(huì)覆蓋上一個(gè)函數(shù),并且函數(shù)優(yōu)先于變量提升疲扎,也就是同名的變量和函數(shù)名昵时,以函數(shù)名為準(zhǔn)。
- 非匿名立即執(zhí)行函數(shù)
var foo = 1
(function foo() {
foo = 10
console.log(foo)
}()) // -> ? foo() { foo = 10 ; console.log(foo) }
因?yàn)楫?dāng) JS 解釋器在遇到非匿名的立即執(zhí)行函數(shù)時(shí)椒丧,會(huì)創(chuàng)建一個(gè)輔助的特定對(duì)象壹甥,然后將函數(shù)名稱作為這個(gè)對(duì)象的屬性,因此函數(shù)內(nèi)部才可以訪問(wèn)到 foo壶熏,但是這個(gè)值又是只讀的句柠,所以對(duì)它的賦值并不生效,所以打印的結(jié)果還是這個(gè)函數(shù)棒假,并且外部的值也沒(méi)有發(fā)生更改溯职。
閉包
- 什么是閉包?假設(shè)函數(shù)A返回了一個(gè)函數(shù)B帽哑,函數(shù)B用到了函數(shù)A里面的變量谜酒。那么函數(shù)B就是一個(gè)閉包。
function A() {
let a = 1
function B() {
console.log(a)
}
return B
}
- 運(yùn)行時(shí)妻枕,函數(shù)A作為聲明僻族,會(huì)進(jìn)入到調(diào)用棧,執(zhí)行結(jié)束后佳头,理應(yīng)函數(shù)A里面的內(nèi)容會(huì)彈出調(diào)用棧。因此函數(shù)B里面的
a
應(yīng)該是無(wú)法訪問(wèn)到的晴氨。但是康嘉,由于閉包的特性,閉包里面的變量會(huì)被存放在堆里面籽前。所以亭珍,在a
被訪問(wèn)的場(chǎng)景下,仍然能取到正確的值枝哄。
深淺拷貝
- 為什么要拷貝肄梨?
const a = {
age: 1
}
const b = a;
b.age = 2;
console.log(a.age) // 2
因?yàn)閖s的對(duì)象都是引用值,如果直接去用對(duì)象a去初始化一個(gè)變量b挠锥,那么相當(dāng)于直接把a(bǔ)的引用值賦值給了變量b众羡,因此,a和b是完全等價(jià)的蓖租。在需要改變b而不改變a的前提下粱侣,我們需要用到深淺拷貝羊壹。
- 淺拷貝的方式:
const a = {
age: 1,
name: 'gatsby',
sex: 1
}
// 方式一:用Object.assign()
const b = Object.assign({}, a);
// 方式二: 擴(kuò)展運(yùn)算符 '...'
const c = {...a}
- 深拷貝的方式:
- 在對(duì)象有多層嵌套的時(shí)候。用淺拷貝的方式無(wú)法達(dá)到我們想要的效果齐婴,比如對(duì)象內(nèi)部還有對(duì)象油猫。那么用淺拷貝,這個(gè)內(nèi)部對(duì)象復(fù)制的還是引用值柠偶。比如下文的
jobs
方法一:JSON.parse(JSON.stringify(obj))
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
const b = JSON.parse(JSON.stringify(a));
- 大部分情況下使用上述方法是效率最快的最有效的情妖。但是存在以下bug
- 會(huì)忽略 undefined
- 會(huì)忽略 symbol
- 不能序列化函數(shù)
- 不能解決循環(huán)引用的對(duì)象
方法二:使用lodash函數(shù)進(jìn)行深拷貝
防抖和節(jié)流
在業(yè)務(wù)開(kāi)發(fā)中常常遇到類似這種問(wèn)題:在滾動(dòng)事件中需要做個(gè)復(fù)雜計(jì)算或者實(shí)現(xiàn)一個(gè)按鈕的防二次點(diǎn)擊操作。
這些需求都可以通過(guò)函數(shù)防抖動(dòng)來(lái)實(shí)現(xiàn)诱担。尤其是第一個(gè)需求毡证,如果在頻繁的事件回調(diào)中做復(fù)雜計(jì)算,很有可能導(dǎo)致> > 頁(yè)面卡頓该肴,不如將多次計(jì)算合并為一次計(jì)算情竹,只在一個(gè)精確點(diǎn)做操作。
- 防抖和節(jié)流的作用都是防止函數(shù)多次調(diào)用匀哄。
- 區(qū)別在于秦效,假設(shè)一個(gè)用戶一直觸發(fā)這個(gè)函數(shù),且每次觸發(fā)函數(shù)的間隔小于wait涎嚼,防抖的情況下只會(huì)調(diào)用一次阱州,而節(jié)流的 情況會(huì)每隔一定時(shí)間(參數(shù)wait)調(diào)用函數(shù)。