1、JavaScript有幾種資料型別?
number:數字型別
string:字串型別
boolean:布林值型別
undefined:未定義型別
null:空型別
object:物件型別
symbol:symbol型別
bigint:大數字型別
2、JavaScript最大安全數字與最小安全數字?
console.log(Number.MAX_SAFE_INTEGER)
// 9007199254740991
console.log(Number.MIN_SAFE_INTEGER)
// -9007199254740991
3、深拷貝與淺拷貝的區別?
淺拷貝:只拷貝第一層,深層的依然是引用,改變深層會影響原物件
深拷貝:每一層都拷貝了,改變資料不會影響原物件
4、閉包是什麼?
閉包是一個函式,是一個能讓外部訪問到函式內部的函式
優點:使外部能訪問內部,延長內部變數壽命
缺點:濫用閉包造成記憶體洩漏
例子:
function a () {
let num = 0
// 這是個閉包
return function () {
return ++num
}
}
const b = a()
console.log(b()) // 1
console.log(b()) // 2
5、原型鏈是什麼
原型鏈是一條引用的鏈,例項的隱式原型指向建構函式的顯式原型,可以使用A instanceof B來判斷B是否在A的原型鏈上。
6、什麼是變數提升?函式提升?
變數提升
console.log(name) // undefined
var name = 'Sunshine_Lin'
if (false) {
var age = 23
}
console.log(age) // undefined 不會報錯
函式提升
console.log(fun) // function fun() {}
function fun() {}
if (false) {
function fun2(){}
}
console.log(fun2) // undefined 不會報錯
函式提升優先順序 > 變數提升優先順序
console.log(fun) // function fun() {}
var fun = 'Sunshie_Lin'
function fun() {}
console.log(fun) // 'Sunshie_Lin'
7、isNaN 與 Number.isNaN的區別?
isNaN:除了判斷NaN為true外,還會把不能轉成數字判斷為true,例如'dasd'
Number.isNaN:只會判斷NaN為true
8、解決遍歷物件時,把原型上的屬性遍歷出來了咋辦?
使用hasOwnProperty判斷
function Person(name) {
this.name = name
}
Person.prototype.age = 23
const person = new Person('Sunshine_lin')
for (const key in person) { console.log(key) } // name age
// 使用 hasOwnProperty
for (const key in person) {
person.hasOwnProperty(key) && console.log(key)
} // name
9、valueOf 與 toString?
valueOf比較偏向於計算,toString偏向於顯示
物件轉換時,優先呼叫toString
強轉字串時優先呼叫toString,強轉數字時優先呼叫valueOf
正常情況下,優先呼叫toString
運算操作符情況下優先呼叫valueOf
10、JavaScript變數在記憶體中具體儲存形式?
基本資料型別:存在棧記憶體裡
引用資料型別:指標存棧記憶體,指向堆記憶體中一塊地址,內容存在堆記憶體中
11、講一講JavaScript的裝箱和拆箱?
裝箱:把基本資料型別轉化為對應的引用資料型別的操作
看以下程式碼,s1只是一個基本資料型別,他是怎麼能呼叫indexOf的呢?
const s1 = 'Sunshine_Lin'
const index = s1.indexOf('_')
console.log(index) // 8
原來是JavaScript內部進行了裝箱操作
1、建立String型別的一個例項;
2、在例項上呼叫指定的方法;
3、銷燬這個例項;
var temp = new String('Sunshine_Lin')
const index = temp.indexOf('_')
temp = null
console.log(index) // 8
拆箱:將引用資料型別轉化為對應的基本資料型別的操作
通過valueOf或者toString方法實現拆箱操作
var objNum = new Number(123);
var objStr =new String("123");
console.log( typeof objNum ); //object
console.log( typeof objStr ); //object
console.log( typeof objNum.valueOf() ); //number
console.log( typeof objStr.valueOf() ); //string
console.log( typeof objNum.toString() ); // string
console.log( typeof objStr.toString() ); // string
12、null和undefined的異同點有哪些?
相同點
1、都是空型別
2、轉布林值都是false,都是假值
3、null == undefined 為 true
不同點
1、typeof,前者為object,後者為undefined
2、null轉數字為0,undefined轉數字為NaN
3、null === undefined 為 false
13、如何判斷資料型別?
typeof:能判斷string、number、undefined、boolean、function、object(null是object)
Object.prototype.toString.call():能判斷大部分資料型別
instanceOf
14、為什麼typeof null 是object?
不同資料型別底層都是用二進位制來表示的,二進位制前三位為000則會被判斷為object,而null二進位制全是0,所以被判斷成object
15、== 與 === 的區別?
==:比較過程會進行隱式轉換
===:值相同,型別相同才會為true
16、JavaScript的隱式轉換規則?
轉string型別:+(字串連線符)
轉number型別:++/--(自增自減運算子) + - * / %(算術運算子) > < >= <= == != === !== (關係運算子)
轉boolean:!(邏輯非運算子)
17、雙等號左右兩邊的轉換規則?
1、null == undefined 為 true
2、如果有一個運算元是布林值,則在比較相等性之前先將其轉換為數值——false轉換為0,而true轉換為1;
3、如果一個運算元是字串,另一個運算元是數值,在比較相等性之前先將字串轉換為數值
4、如果一個運算元是物件,另一個運算元不是,則呼叫物件的toString()方法,用得到的基本型別值按照前面的規則進行比較
18、undefined >= undefined 為什麼是 false ?
隱式轉換,變成NaN >= NaN,NaN不等於自身也不大於自身
19、null >= null 為什麼是 true?
隱式轉換,變成0 >= 0,為true
20、[] == ![] 為什麼是 true ?
第一步:轉為[] == false
第二步:轉為[] == 0
第三步:轉為'' == 0
第四步:轉為0 == 0
21、0.1 + 0.2 === 0.3,對嗎?
不對,JavaScript存在精度丟失問題,由於有些小數無法用二進位制表示,所以只能取近似值,解決方法有:
先轉大數,再變小數
使用toFixed
22、什麼是匿名函式?
匿名函式,就是沒有名字的函式,比如:
(function(x, y){
alert(x + y);
})(2, 3)
23、繫結點選事件有幾種方式?
三種
xxx.onclick = function (){}
<xxx onclick=""></xxx>
xxx.addEventListener('click', function(){}, false)
24、addEventListener的第三個引數是幹嘛的?
決定事件是捕獲階段執行還是冒泡階段執行
true:捕獲
false:預設,冒泡
25、函式宣告和函式表示式的區別?
函式宣告:享受函式提升
函式表示式:歸類於變數宣告,享受變數提升
函式提升優先順序 > 變數提升優先順序
console.log(fun) // fun () {}
// 函式表示式
var fun = function(name) {}
// 函式宣告
function fun () {}
console.log(fun) // fun (name) {}
26、JavaScript的事件流模型有哪些?
事件冒泡:由最具體的元素接收,並往上傳播
事件捕獲:由最不具體的元素接收,並往下傳播
DOM事件流:事件捕獲 -> 目標階段 -> 事件冒泡
27、Ajax、Axios、Fetch有啥區別?
Ajax:是對XMLHttpRequest(XHR)的封裝
Axios:是基於Promise對XHR物件的封裝
Fetch:是window的一個方法,基於Promise,與XHR無關,不相容IE
28、load、$(document).ready、DOMContentLoaded的區別?
$(document).ready、DOMContentLoaded:DOM樹構建完畢,但還沒有請求靜態資源
load:靜態資源請求完畢
29、如何阻止事件冒泡?
function stopBubble(e) {
if (e.stopPropagation) {
e.stopPropagation()
} else {
window.event.cancelBubble = true;
}
}
30、如何阻止事件預設行為?
function stopDefault(e) {
if (e.preventDefault) {
e.preventDefault();
} else {
window.event.returnValue = false;
}
}
31、什麼是事件委託?
當子元素都需要繫結相同事件時,可以將事件綁在父元素上,優點有:
繫結在父元素,則只需繫結一次,節省效能
後續新增的子元素也可以觸發父元素繫結的事件
32、如何實現陣列去重?
// 使用 Map 去重
function quchong1(arr) {
const newArr = []
arr.reduce((pre, next) => {
if (!pre.get(next)) {
pre.set(next, 1)
newArr.push(next)
}
return pre
}, new Map())
return newArr
}
// 使用 Set 去重
function quchong (arr) {
return [...new Set(arr)]
}
33、Set與Array的區別是什麼?
Set使用has判斷有無元素,陣列使用索引
Set新增元素使用方法add,陣列用push、unshift
Set長度為size,陣列為length
Set會自動把同樣的基礎資料型別去重,陣列不能
Set刪除元素用delete,陣列用splice、pop、shift
Set可以使用clear清空,陣列需要重新賦值[]
陣列可以傳入new Set(array),實現陣列轉Set
Set可以使用keys、value方法,轉陣列
Set自帶forEach方法進行遍歷
34、Map與Object的區別是什麼?
Map使用set設定屬性,物件使用obj[key] = value
Map使用get獲取屬性值,物件使用obj[key]
Map使用has判斷屬性存在與否,物件只能obj[key]
Map刪除元素使用delete方法,物件使用delete關鍵字
Map使用clear進行情空,物件需要重新賦值{}
Map和物件都可以使用entries方法轉陣列鍵值對
Map自帶forEach方法進行遍歷
35、NaN是什麼?有什麼特點?
typeof NaN 為 number
NaN不等於自身,不大於自身,不小於自身
NaN可以使用Number.isNaN判斷
NaN是假值,轉布林值為false
36、處理非同步的方法有哪些?
回撥函式
Promise
事件監聽
釋出訂閱
async/await
37、JavaScript繼承方式有幾種?
前置工作
// 定義一個動物類
function Animal (name) {
// 屬性
this.name = name || 'Animal';
// 例項方法
this.sleep = function(){
console.log(this.name + '正在睡覺!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
1、原型鏈繼承
核心:將父類的例項作為子類的原型
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
var cat = new Cat();
console.log(cat.name); // cat
cat.eat('fish') // cat正在吃:fish
cat.sleep() // cat正在睡覺!
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
優點:
1、非常純粹的繼承關係,例項是子類的例項,也是父類的例項
2、父類新增原型方法/屬性,子類都能訪問到
3、簡單,易於實現
缺點:
1、要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之後執行,不能放構造器中
2、來自原型物件的所有屬性被所有例項共享
3、建立子例項時,無法向父類建構函式傳參
4、不支援多繼承
2、構造繼承
核心:使用父類的構造器來增強子類例項,等於是複製父類的例項屬性給子類(沒用到原型)
function Cat(name) {
Animal.call(this);
this.name = name || 'Tom';
}
var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
優點:
1、解決了原型鏈繼承中,子類例項共享父類引用屬性的問題
2、建立子類例項時,可以向父類傳遞引數
3、可以實現多繼承(call多個父類物件)
缺點:
1、例項並不是父類的例項,知識子類的例項
2、是能繼承父類的例項屬性和方法,不能繼承原型屬性/方法
3、無法實現函式複用,每個子類都有父類例項函式的副本,影響效能
3、例項繼承
核心:為父類例項新增新特性,作為子類例項返回
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}
var cat = new Cat();
console.log(cat.name) // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
優點:
1、不限制呼叫方式,不管是new 子類()還是子類(),返回的物件具有相同效果
缺點:
1、例項是父類的例項,不是子類的例項
2、不支援多繼承
4、拷貝繼承
核心:就一個一個拷貝
function Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
this.name = name || 'Tom';
}
var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
優點:
1、支援多繼承
缺點:
1、效率低,記憶體佔用高(因為要拷貝父類的屬性)
2、無法獲取父類不可列舉方法(不可列舉方法,不能使用for in訪問到)
5、組合繼承
核心:通過父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類例項作為子類原型,實現函式複用
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
優點:
1、彌補了構造繼承的缺陷,可以繼承例項屬性/方法,也可繼承原型屬性/方法
2、既是子類的例項,也是父類的例項
3、不存在引用屬性共享問題
4、可傳參
5、函式可複用
缺點:
1、呼叫了兩次父類建構函式,生成了兩份例項(子類例項將子類原型上的那份遮蔽了)
6、寄生組合繼承
核心:通過寄生方式,砍掉父類的例項屬性,這樣,在呼叫兩次父類的構造時,就不會初始化兩次例項方法/屬性,避免繼承組合的缺點
function Cat(name) {
Animal.call(this);
this.name = name || 'Tom';
}
// 建立一個沒有例項方法的類
var Super = function () { };
Super.prototype = Animal.prototype;
//將例項作為子類的原型
Cat.prototype = new Super();
// Test Code
var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
優點:
1、堪稱完美
缺點:
1、實現複雜
38、建立一個物件的方式有哪幾種?
new Object
const obj = new Object()
obj.name = 'Sunshine_Lin'
字面量
const obj = { name: 'Sunshin_Lin' }
工廠模式
function createObj(name) {
const obj = new Object()
obj.name = name
return obj
}
const obj = createObj('Sunshine_Lin')
建構函式
function Person(name) {
this.name = name
}
const person = new Person('Sunshine_Lin')
39、this指向的四種情況?
new操作符
function Person(name) {
this.name = name
console.log(this)
}
// this指向當前person例項物件
const person = new Person('Sunshine_Lin')
指向window
function fn() {
console.log(this)
}
fn() // 瀏覽器window,node裡global
物件呼叫方法
const target = {
fn: function () { console.log(this) }
}
target.fn() // target
// 這種就是改變了this了
const fn = target.fn
fn() // 瀏覽器window,node裡global
箭頭函式
const obj = {
name: '林三心',
fn: () => {
console.log(this.name)
}
}
console.log(obj.fn()) // undefined
call、apply、bind改變this
const obj1 = {
name: '林三心',
sayName: function() {
console.log(this.name)
}
}
const obj2 = {
name: 'Sunshin_Lin'
}
// 改變sayName的this指向obj2
obj1.sayName.call(obj2) // Sunshin_Lin
// 改變sayName的this指向obj2
obj1.sayName.apply(obj2) // Sunshin_Lin
// 改變sayName的this指向obj2
const fn = obj1.sayName.bind(obj2)
fn() // Sunshin_Lin
40、陣列的常用方法有哪些?
方法 | 作用 | 是否影響原陣列 |
---|---|---|
push | 在陣列後新增元素,返回長度 | ✅ |
pop | 刪除陣列最後一項,返回被刪項 | ✅ |
shift | 刪除陣列第一項,返回被刪項 | ✅ |
unshift | 陣列開頭新增元素,返回長度 | ✅ |
reserve | 反轉陣列,返回陣列 | ✅ |
sort | 排序陣列,返回陣列 | ✅ |
splice | 擷取陣列,返回被擷取部分 | ✅ |
join | 將陣列變字串,返回字串 | ❌ |
concat | 連線陣列 | ❌ |
map | 相同規則處理陣列項,返回新陣列 | ❌ |
forEach | 遍歷陣列 | ❌ |
filter | 過濾陣列項,返回符合條件的陣列 | ❌ |
every | 每一項符合規則才返回true | ❌ |
some | 只要有一項符合規則就返回true | ❌ |
reduce | 接受上一個return和陣列下一項 | ❌ |
flat | 陣列扁平化 | ❌ |
slice | 擷取陣列,返回被擷取區間 | ❌ |
41、Math的常用方法有哪些?
方法 | 作用 |
---|---|
Math.max(...arr) | 取arr中的最大值 |
Math.min(...arr) | 取arr中的最小值 |
Math.ceil(小數) | 小數向上取整 |
Math.floor(小數) | 小數向下取整 |
Math.round(小數) | 小數四捨五入 |
Math.sqrt(num) | 對num進行開方 |
Math.pow(num, m) | 對num取m次冪 |
Math.random() * num | 取0-num的隨機數 |
42、JS中有哪些不同型別的彈出框?
在JS中有三種型別的彈出框可用,分別是:
Alert、Confirm、Prompt
43、如何將 JS 日期轉換為ISO標準
var date = new Date();
var n = date.toISOString();
console.log(n);
// YYYY-MM-DDTHH:mm:ss.sssZ
44、如何在JS中編碼和解碼 URL
編碼:encodeURI()
解碼:decodeURI()
45、什麼是BOM?有哪些api?
BOM就是browser object model,瀏覽器物件模型
api | 作用 | 代表方法或屬性 |
---|---|---|
window.history | 操縱瀏覽器的記錄 | history.back() 、history.go(-1) |
window.innerHeight | 獲取瀏覽器視窗的高度 | |
window.innerWidth | 獲取瀏覽器視窗的寬度 | |
window.location | 操作重新整理按鈕和位址列 | location.host:獲取域名和埠 |
window.location | 操作重新整理按鈕和位址列 | location.hostname:獲取主機名 |
window.location | 操作重新整理按鈕和位址列 | location.port:獲取埠號 |
window.location | 操作重新整理按鈕和位址列 | location.pathname:獲取url的路徑 |
window.location | 操作重新整理按鈕和位址列 | location.search:獲取?開始的部分 |
window.location | 操作重新整理按鈕和位址列 | location.href:獲取整個url |
window.location | 操作重新整理按鈕和位址列 | location.hash:獲取#開始的部分 |
window.location | 操作重新整理按鈕和位址列 | location.origin:獲取當前域名 |
window.location | 操作重新整理按鈕和位址列 | location.navigator:獲取當前瀏覽器資訊 |
46、BOM 和 DOM 的關係
BOM全稱Browser Object Model,即瀏覽器物件模型,主要處理瀏覽器視窗和框架。
DOM全稱Document Object Model,即文件物件模型,是 HTML 和XML 的應用程式介面(API),遵循W3C 的標準,所有瀏覽器公共遵守的標準。
JS是通過訪問BOM(Browser Object Model)物件來訪問、控制、修改客戶端(瀏覽器),由於BOM的window包含了document,window物件的屬性和方法是直接可以使用而且被感知的,因此可以直接使用window物件的document屬性,通過document屬性就可以訪問、檢索、修改XHTML文件內容與結構。因為document物件又是DOM的根節點。
可以說,BOM包含了DOM(物件),瀏覽器提供出來給予訪問的是BOM物件,從BOM物件再訪問到DOM物件,從而js可以操作瀏覽器以及瀏覽器讀取到的文件。
47、JS中的substr()和substring()函式有什麼區別
substr() 函式的形式為substr(startIndex,length)。它從startIndex返回子字串並返回'length'個字元數。
var s = "hello";
( s.substr(1,4) == "ello" ) // true
substring() 函式的形式為substring(startIndex,endIndex)。它返回從startIndex到endIndex - 1的子字串。
var s = "hello";
( s.substring(1,4) == "ell" ) // true
48、解釋一下 "use strict" ?
“use strict”是Es5中引入的js指令。使用“use strict”指令的目的是強制執行嚴格模式下的程式碼。在嚴格模式下,我們們不能在不宣告變數的情況下使用變數。早期版本的js忽略了“use strict”。