隱式類型轉(zhuǎn)換相關(guān)
字符串連接符與算數(shù)運算符
- 字符串連接符+:會把其他數(shù)據(jù)類型調(diào)用String()方法轉(zhuǎn)換成字符串然后拼接
- 算數(shù)運算符+:會把其他數(shù)據(jù)類型調(diào)用Number()方法轉(zhuǎn)換成數(shù)字然后做加法計算
關(guān)系運算符
關(guān)系運算符會把其他數(shù)據(jù)轉(zhuǎn)換成number之后再比較
- 一個為字符串另一個為數(shù)字惋鹅,則將字符串轉(zhuǎn)換成數(shù)字比較
- 兩個都為字符串則依次比較兩個的charCodeAt()值
- undefined與null互相比較為相等,與其他類型比較為不等
- NaN與任何數(shù)據(jù)都不等
- 復雜數(shù)據(jù)類型會先調(diào)用valueOf()再調(diào)用toString()轉(zhuǎn)換成字符串殉簸,然后再轉(zhuǎn)換成number
邏輯非運算符
- 有邏輯非運算符的會將數(shù)據(jù)轉(zhuǎn)換成布爾類型
- 除了0闰集、-0返十、NaN洞坑、undefined迟杂、null侧漓、""监氢、false以外都為true
各類型隱式轉(zhuǎn)換規(guī)則
- String:變量 + 字符串
- Number:變量 + 自增自減運算符纵揍,算術(shù)運算符泽谨,關(guān)系運算符
- Boolean:變量 + 邏輯非運算符
字符串類型轉(zhuǎn)為數(shù)值類型:
- 字符串任意位置出現(xiàn)任意非數(shù)字吧雹、非空格的字符雄卷,均轉(zhuǎn)為NaN
- 數(shù)字中間存在空格,轉(zhuǎn)為NaN
閉包相關(guān)
什么是閉包
閉包就是一個函數(shù)鳄炉,這個函數(shù)能夠訪問其他函數(shù)的作用域中的變量拂盯。
優(yōu)點
- 封裝變量谈竿,模仿塊級作用域
缺點
- this指向問題
- 內(nèi)存泄漏問題
- 變量發(fā)生變化問題
作用域和變量提升相關(guān)
作用域
作用域分為全局作用域、函數(shù)作用域及塊級作用域
變量提升
js在執(zhí)行一個作用域的代碼之前呀洲,會先將變量聲明及函數(shù)聲明提到整個作用域頂部兵罢,隨后依次執(zhí)行代碼卖词,其中若變量與函數(shù)同名此蜈,函數(shù)優(yōu)先級要高于變量。
即:
- 將變量聲明與函數(shù)聲明提到作用域頂部
- 函數(shù)聲明優(yōu)先級高于變量聲明
- 依次執(zhí)行代碼
作用域鏈
如果當前作用域中找不到變量,則會想上層作用域查找抛蚁,依次往上查找瞧甩,形成作用域鏈
NaN是什么肚逸?有什么特別之處朦促?
NaN 是 not a number 的縮寫务冕,代表非數(shù)字值的特殊值,該屬性用于指示某個值不是數(shù)字箩退,是一個全局對象的屬性
特別之處:
- NaN 屬性的初始值就是 NaN,和 Number.NaN 的值一樣
- 在現(xiàn)代瀏覽器中(ES5)喊括,NaN是一個不可配置(non-configurable)府喳,不可寫(non-writable)的屬性.但是在ES3中,這個屬性的值是可以更改的申窘,但是也應該避免覆蓋
- 編碼中很少直接用到 NaN 碎捺,通常都是計算失敗的時候,作為Math的某個方法的返回值出現(xiàn)(例如:Math.sqrt(-1))诵叁,或者嘗試將一個字符串解析成為數(shù)字拧额,但是失敗了的時候(parseInt("blabla"))
- NaN和任何值比較,都不相等捎拯,包括它自己NaN是number類型 typeof NaN //'number'
== 和 === 的區(qū)別
兩等是值判斷,會調(diào)用隱式類型轉(zhuǎn)換建芙,不判斷類型
三等是值判斷加類型判斷右蒲,判斷兩個值是否嚴格相等
typeof和instanceof的區(qū)別
typeof
用于判斷數(shù)據(jù)類型瑰妄,返回值為6個字符串,分別為string竹宋、Boolean莫矗、number、function、object、undefined。其中null會返回object結(jié)果。
instanceof
instanceof用來判斷對象搂橙,判斷方法是根據(jù)對象的原型鏈依次向下查詢
js的數(shù)據(jù)類型有哪些
JS原生有5種簡單數(shù)據(jù)類型:Undefined
版扩,Null
悼尾,Boolean
,Number
和 String
。還有一個復雜數(shù)據(jù)類型Object
烹骨。 函數(shù)在JS中是對象拉宗,而不是一種數(shù)據(jù)類型。
undefined和null的區(qū)別
Undefined類型為變量聲明了但是沒有初始化(var box)
,而Null表示一個空對象引用(var box = null)
肾扰。注意:未初始化的變量和賦值為 null 的 變量會相等偷拔,可通過typeof
或者使用三等
進行判斷
call、apply、bind的區(qū)別
call 和 apply 是為了改變函數(shù)體內(nèi)部 this 的指向踏枣。對于 apply躬厌、call 二者而言,作用完全一樣匙奴,只是接受參數(shù)的方式不太一樣啦租。bind()最簡單的用法是創(chuàng)建一個函數(shù),使這個函數(shù)不論怎么調(diào)用都有同樣的this值。
示例:
function func(arg1, arg2) {};
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
var obj = {
a: 123,
};
var foo = {
getV: function(k) {
return this.a + k;
}
}
console.log(foo.getV.bind(obj, 1)()); //124
console.log(foo.getV.call(obj, 1)); //124
console.log(foo.getV.apply(obj, [1])); //124
區(qū)別:
- 傳參不同举农,調(diào)用不同。bind 是返回對應函數(shù),便于稍后調(diào)用勺像;apply 涩维、call 則是立即調(diào)用 。
js的假值有哪些
0
、-0
、NaN
、undefined
蚕泽、null
荒吏、""
锡宋、false
js面向?qū)ο笈c原型、原型鏈相關(guān)
原型(對象屬性)
Javascript規(guī)定显拜,每個函數(shù)都有一個prototype對象屬性矮台。只有函數(shù)才有prototype屬性蛤迎。指向另一個對象(原型鏈上面的)。prototype(對象屬性)的所有屬性和方法,都會被構(gòu)造的實例繼承。這意味著,我們可以把那些不變的屬性和方法,直接定義在prototype對象屬性上。
prototype就是調(diào)用構(gòu)造函數(shù)所創(chuàng)建的那個實例對象的原型(proto)侦高。
prototype可以讓所有對象實例共享它所包含的屬性和方法。也就是說匙握,不必在構(gòu)造函數(shù)中定義對象信息蛾娶,而是可以直接將這些信息添加到原型中蛔琅。
原型鏈 (JS原型與原型鏈繼承)
實例對象與原型之間的連接,叫做原型鏈。proto( 隱式連接 )
JS在創(chuàng)建對象的時候切距,都有一個叫做proto的內(nèi)置屬性话肖,用于指向創(chuàng)建它的函數(shù)對象的原型對象prototype最筒。
內(nèi)部原型(proto)和構(gòu)造器的原型(prototype)
1蔚叨、每個對象都有一個proto屬性,原型鏈上的對象正是依靠這個屬性連結(jié)在一起
2、作為一個對象丹擎,當你訪問其中的一個屬性或方法的時候,如果這個對象中沒有這個 方法或?qū)傩贼岢澹敲碕avascript引擎將會訪問這個對象的proto屬性所指向上一個對 象,并在那個對象中查找指定的方法或?qū)傩耘迸绻荒苷业皆等Γ蔷蜁^續(xù)通過那個對象 的proto屬性指向的對象進行向上查找袜蚕,直到這個鏈表結(jié)束糟把。
淺談constructor
在 Javascript 語言中,constructor 屬性是專門為 function 而設(shè)計的牲剃,它存在于每一個 function 的prototype 屬性中遣疯。這個 constructor 保存了指向 function 的一個引用。
__proto__
JS 在創(chuàng)建對象(不論是普通對象還是函數(shù)對象)的時候凿傅,都有一個叫做 __proto__
的內(nèi)置屬性缠犀,用于指向創(chuàng)建它的構(gòu)造函數(shù)的原型對象。
var obj = []
console.log(obj.__proto__ === Array.prototype) //true
示例題
function Foo() {}
var f1 = new Foo()
請回答以下問題:
- f1.
__proto__
=== - f1.constructor ===
- f1.prototype ===
- Foo.
__proto__
=== - Foo.prototype ===
- Foo.constructor ===
- Foo.prototype.constructor ===
- Foo.prototype.
__proto__
===
繼承的幾種寫法及優(yōu)缺點
this指向相關(guān)
- this 永遠指向函數(shù)運行時所在的對象聪舒,而不是函數(shù)被創(chuàng)建時所在的對象辨液。
- this的指向在函數(shù)定義的時候是確定不了的,只有函數(shù)執(zhí)行的時候才能確定this到底指向誰箱残,實際上this的最終指向的是那個調(diào)用它的對象
js new一個對象都經(jīng)過了什么
new對象:
function Person(name, age) {
this.name = name;
this.age = age;
}
var person = new Person("Alice", 23);
new一個對象的四個過程:1滔迈、創(chuàng)建一個空對象?
var obj = new Object();
2、讓Person中的this指向obj,并執(zhí)行Person的函數(shù)體?
var result = Person.call(obj);
3亡鼠、設(shè)置原型鏈,將obj的proto成員指向了Person函數(shù)對象的prototype成員對象?
obj.__proto__ = Person.prototype;
4敷待、判斷Person的返回值類型间涵,如果是值類型,返回obj榜揖。如果是引用類型勾哩,就返回這個引用類型的對象。
if (typeof(result) == "object")
person = result;
else
person = obj;
宏任務和微任務
- 宿主環(huán)境提供的叫宏任務举哟,宿主環(huán)境包括瀏覽器和node
- 宏任務有:
- script
- setTimeout
- setInterval
- setImmediate
- requestAnimationFrame
- I/O
- UI渲染
- 由語言標準提供的叫微任務思劳,即由語言標準(ECMA)提供的就是微任務,比如ES6提供的promise妨猩。
- 微任務有
- process.nextTick
- MutationObserver
- Promise
執(zhí)行過程
- js引擎將代碼按照類別分到宏任務和微任務隊列中
- 執(zhí)行宏任務潜叛,執(zhí)行完成,清空微任務隊列
- 執(zhí)行下一個宏任務壶硅,執(zhí)行完成后威兜,清空微任務隊列
- 依次執(zhí)行宏任務隊列的下一個宏任務,執(zhí)行完成后庐椒,清空微任務隊列
怎樣理解setTimeout 執(zhí)行誤差
如果當前 執(zhí)行棧 所花費的時間大于 定時器 時間椒舵,那么定時器的回調(diào)在 宏任務(macrotask) 里,來不及去調(diào)用约谈,所以這個時間會有誤差笔宿。
如何實現(xiàn)深淺拷貝
淺拷貝
// 1. ...實現(xiàn)
let copy1 = {...{x:1}}
// 2. Object.assign實現(xiàn)
let copy2 = Object.assign({}, {x:1})
// 數(shù)組采用slice、concat方法
深拷貝
// 1. JOSN.stringify()/JSON.parse()
let obj = {a: 1, b: {x: 3}}
JSON.parse(JSON.stringify(obj))
// 2. 遞歸拷貝
function deepClone(obj) {
let copy = obj instanceof Array ? [] : {}
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
copy[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
}
}
return copy
}
JSON.stringify()的缺點
- 會忽略 undefined
- 會忽略 symbol
- 不能序列化函數(shù)
- 不能解決循環(huán)引用的對象
- 不能正確處理new Date()
- 不能處理正則
數(shù)組去重的幾種寫法
let list = [1, 2, 3, 4, 5, 2, 2, 2, 7, 6, 4, 8, 1];
// 創(chuàng)建新數(shù)組棱诱,判斷數(shù)據(jù)是否在新數(shù)組中
function arrToRepeat1(arr) {
let repeatList = [];
list.forEach(value => {
if (!repeatList.includes(value)) repeatList.push(value);
})
return repeatList;
}
console.log(arrToRepeat1(list));
// 創(chuàng)建新數(shù)組泼橘,通過下標判斷是否是重復的值
function arrToRepeat2(arr) {
let repeatList = [];
list.forEach((value, index) => {
// 左側(cè)的為第一個值的索引,右側(cè)為重復的當前的值的索引
if (arr.indexOf(value) === index) repeatList.push(value);
})
return repeatList;
}
console.log(arrToRepeat2(list));
// 使用set集合
console.log([...new Set(list)]);
數(shù)組排序的問題
默認數(shù)組排數(shù)函數(shù)sort有問題军俊,不指定排序方法時侥加,元素會按照轉(zhuǎn)換為的字符串的諸個字符的Unicode位點進行排序
常用解決方法
list.sort((a, b) => a - b) // 從小到大
list.sort((a, b) => b - a) // 從大到小
數(shù)組降維
array = array.reduce((acc, val) => acc.concat(val), []); // 一層扁平化
array = [].concat(...array); // 一層扁平化
array = array.flat(); // 一層扁平化
手寫防抖和節(jié)流
js垃圾回收機制,怎么理解js中的內(nèi)存泄露
垃圾回收機制
垃圾回收是釋放已經(jīng)不再需要的變量等,來減少系統(tǒng)所占用的內(nèi)存。
標記清除法
工作原理:
當變量進入環(huán)境時(例如在函數(shù)中聲明一個變量)腥光,將這個變量標記為“進入環(huán)境”砾省,當變量離開環(huán)境時,則將其標記為“離開環(huán)境”伏蚊。標記“離開環(huán)境”的就回收內(nèi)存。
工作流程:
- 垃圾收集器會在運行的時候會給存儲在內(nèi)存中的所有變量都加上標記。
- 去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標記狈网。
- 那些還存在標記的變量被視為準備刪除的變量。
- 最后垃圾收集器會執(zhí)行最后一步內(nèi)存清除的工作,銷毀那些帶標記的值并回收它們所占用的內(nèi)存空間拓哺。
引用計數(shù)法
跟蹤記錄每個值的引用次數(shù)(值)
流程:
- 聲明一個變量勇垛,并給這個變量賦值,這個值的引用次數(shù)就是1
- 同一個值被賦給另一個變量士鸥,這個值的引用次數(shù)+1
- 變量的值被更改了 那原本那個值的引用次數(shù)-1
- 引用次數(shù)為0時闲孤,說明沒辦法訪問這個值了
- 垃圾收集器下一次運行時,會釋放引用次數(shù)為0的值所占的內(nèi)存
缺點:循環(huán)引用將不能被自動回收烤礁。
內(nèi)存泄漏
內(nèi)存泄漏是由于疏忽或錯誤造成程序未能釋放那些已經(jīng)不再使用的內(nèi)存讼积,造成內(nèi)存的浪費。
引起內(nèi)存泄漏的情況
- 意外的全局變量
- 被遺忘的定時器和定時器的回調(diào)函數(shù)
- 閉包
- 循環(huán)引用問題
- 沒有清理的DOM元素引用