1. Js的基本數(shù)據(jù)類型
- null
- undefined
- string
- symbol
- bigint
- boolean
- number
- object
Es6 新增了symbol和bigint兩種類型,symbol一般常用可以結(jié)合redux的action的type進(jìn)行使用;bigint是大數(shù)處理,一般除非項(xiàng)目中涉及到很大的數(shù)才會(huì)用到。
2. 數(shù)據(jù)類型檢測的方式有哪些
- typeof , 但是在判斷Array null為object
- instanceof , 通過prototype 判斷構(gòu)造函數(shù)
- construct,通過構(gòu)造函數(shù)來判斷
- Object.prototype.toString()
一般項(xiàng)目中常用的判斷方式可能是使用typeof,typeof null === "object" 是一個(gè)歷史遺留問題.
3 null 和 undefined 區(qū)別
兩者都是基本數(shù)據(jù)類型
undefined 在 JavaScript 中不是一個(gè)保留字,這意味著可以使用 undefined 來作為一個(gè)變量名,但是這樣的做法是非常危險(xiǎn)的,它會(huì) 影響對(duì) undefined 值的判斷。我們可以通過一些方法獲得安全的 undefined 值,比如說 void 0。
但是現(xiàn)在大多數(shù)瀏覽器應(yīng)該是都無法使用undefined作為一個(gè)變量名。
5 intanceof 操作符的實(shí)現(xiàn)原理及實(shí)現(xiàn)
intanceof 是判斷構(gòu)造函數(shù)的prototype是否存在于對(duì)象的原型鏈上,一直找到Object.prototype.
知道了原理,實(shí)現(xiàn)就很簡單了,就是無限循環(huán)遞歸
function myInstanceOf(left:object, right:object) {
// Object.getPrototypeOf() 返回對(duì)象的原型
const leftPrototype = Object.getPrototypeOf(left);
const rightPrototype = right.prototype;
while(leftPrototype) {
if(leftPrototype === rightPrototype) return true;
if(!rightPrototype) return false;
leftPrototype = Object.getPrototypeOf(leftPrototype);
}
return fasle;
}
6 Object.is() 與比較操作符 “===”、“==” 的區(qū)別?
=== 判斷兩邊類型和值都相等才返回true
== 會(huì)進(jìn)行隱士類型轉(zhuǎn)換,轉(zhuǎn)換之后才判斷,項(xiàng)目中不推薦==進(jìn)行判斷
Object.is() 基本上和===使用類似,這兩者的區(qū)別在于如何判斷+0和-0,以及NaN的處理
console.log(+0 === -0); //true
console.log(Object.is(+0, -0)); //false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); //true
console.log(Number.NaN === Number.NaN); // false
console.log(Object.is(Number.NaN, Number.NaN)); // true
console.log(NaN === Number.NaN); // false
console.log(Object.is(NaN, Number.NaN)); // true
7 什么是BigInt
JavaScript 中 Number.MAX_SAFE_INTEGER 表示最大安全數(shù)字,計(jì)算 結(jié)果是 9007199254740991,即在這個(gè)數(shù)范圍內(nèi)不會(huì)出現(xiàn)精度丟失(小 數(shù)除外)。
8 如何判斷一個(gè)對(duì)象是一個(gè)空對(duì)象
function isEmptyObject(obj={}) {
return Object.keys(obj).length > 0;
}
console.log(isEmptyObject({}));
console.log(isEmptyObject({'a':1}));
9 new 一個(gè)類的時(shí)候發(fā)生了什么?
- 創(chuàng)建一個(gè)對(duì)象
- 把該對(duì)象的proto指向類的原型
- 使用apply執(zhí)行構(gòu)造函數(shù),如果返回是一個(gè)對(duì)象就返回,如果不是就返回剛才創(chuàng)建的對(duì)象。
10 Proxy 可以實(shí)現(xiàn)什么功能
在 Vue3.0 中通過 Proxy 來替換原本的 Object.defineProperty 來實(shí)現(xiàn)數(shù)據(jù)響應(yīng)式。
之所以 Vue3.0 要使用 Proxy 替換原本的 API 原因在于 Proxy 無需一層層遞歸為每個(gè)屬性添加代理,一次即可完成以上操作,性能上更好,并且原本的實(shí)現(xiàn) 有一些數(shù)據(jù)更新不能監(jiān)聽到,比如數(shù)組的push和pop等,但是 Proxy 可以完美監(jiān)聽到任何方式的數(shù)據(jù)改變,唯一缺陷就是瀏覽器的兼容性不好。
Proxy是Es6中添加的,基本使用如下:
const target1 = {
message1: "hello",
message2: "everyone"
};
const handler2 = {
// target 原始對(duì)象,這里是指target1,prop傳入的屬性,receiv // er表示是接受的對(duì)象,這里是handle2
get(target, prop, receiver) {
return "world";
}
};
const proxy2 = new Proxy(target1, handler2);
11 Js 文件延遲加載方法有哪些?
- defer:js文件下載會(huì)和瀏覽器的解析同時(shí)執(zhí)行,當(dāng)瀏覽器解析完畢后,然后再執(zhí)行js文件。
- async:js文件下載會(huì)和瀏覽器的解析同時(shí)執(zhí)行,當(dāng)js文件下載完畢后,會(huì)立即執(zhí)行js文件。
- 如果沒有defer和async,文件會(huì)立即下載和立即執(zhí)行,并且會(huì)阻塞瀏覽器的解析。
12 ES6 模塊與 CommonJS 模塊的區(qū)別
相同點(diǎn):
ES6和CommonJS都可以對(duì)引入的對(duì)象內(nèi)部重新賦值
不同點(diǎn):
CommonJS模塊輸出的是一個(gè)值的拷貝,ES6 模塊輸出的是值的引用;
也就是說ComonnJS是引用的一個(gè)值的拷貝,如果當(dāng)我們引入之后,修改了原來文件的內(nèi)容,我們引用的值不會(huì)改變,比如下面的例子,test.js中輸出的值都是3,3
// lib.js
let counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};
// test.js
const mod = require("./lib");
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3
ES6是導(dǎo)入的引用,有點(diǎn)類似指針,所以當(dāng)引入的文件內(nèi)容改變后,會(huì)跟著改變。
可以看下下面的例子
// lib.js
export let counter = 3;
export function incCounter() {
counter++;
}
// test.js
export let counter = 3;
export function incCounter() {
counter++;
}
13 for...in 和 for...of 的區(qū)別
for...of 是 ES6 新增的遍歷方式,允許遍歷一個(gè)含有 iterator 接口 的數(shù)據(jù)結(jié)構(gòu)(數(shù)組、對(duì)象等)并且返回各項(xiàng)的值
for...in 主要是遍歷對(duì)象,并且會(huì)沿著原型鏈向上查找
for... in 遍歷數(shù)組的時(shí)候,返回的是數(shù)組下標(biāo)
for... of 遍歷數(shù)組的時(shí)候,返回的是數(shù)組的值
例子如下:
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
const iterable = [3, 5, 7];
iterable.foo = 'hello';
for (const i in iterable) {
// logs "0", "1", "2", "foo", "arrCust om", "objCustom"
console.log(i);
}
for (const i in iterable) {
if (Object.hasOwn(iterable, i)) {
// logs "0", "1", "2", "foo"
console.log(i);
}
}
for (const i of iterable) {
// logs 3, 5, 7
console.log(i);
}
for...of 不能遍歷對(duì)象,如果想要遍歷對(duì)象,可以使用如下代碼
const obj = {
a: 1,
b: 2,
};
for (let [key, value] of Object.entries(obj)) {
console.log(key, value);
}
14 原型和原型鏈的經(jīng)典圖

15 this的理解
- 當(dāng)一個(gè)函數(shù)不是一個(gè)對(duì)象的屬性時(shí),直接作為函數(shù)來調(diào)用時(shí),this 指向全局對(duì)象。
- 如果一個(gè)函數(shù)作為一個(gè)對(duì)象的方法來調(diào)用時(shí), this 指向這個(gè)對(duì)象。
- 如果一個(gè)函數(shù)用 new 調(diào)用時(shí),函數(shù)執(zhí)行 前會(huì)新創(chuàng)建一個(gè)對(duì)象,this 指向這個(gè)新創(chuàng)建的對(duì)象。
- apply 、 call 和 bind 調(diào)用模式, 這三個(gè)方法都可以顯示的指定調(diào)用函數(shù)的 this 指向。其中 apply 方法接收兩個(gè)參數(shù): 一個(gè)是 this 綁定的對(duì)象,一個(gè)是參數(shù)數(shù)組。call 方法接收的參數(shù), 第一個(gè)是 this 綁定的對(duì)象,后面的其余參數(shù)是傳入函數(shù)執(zhí)行的參數(shù)。 也就是說,在使用 call() 方法時(shí),傳遞給函數(shù)的參數(shù)必須逐個(gè)列舉出來。bind 方法通過傳入一個(gè)對(duì)象,返回一個(gè) this 綁定了傳入對(duì) 象的新函數(shù)。這個(gè)函數(shù)的 this 指向除了使用 new 時(shí)會(huì)被改變,其 他情況下都不會(huì)改變。
- 箭頭函數(shù)的this指向定義的時(shí)候,最外層的this
16 內(nèi)存泄露的情況
- 全局變量
- 閉包
- dom元素的引用,當(dāng)dom被刪除后,引用沒有清空。
本文由mdnice多平臺(tái)發(fā)布