基本數據類型:String,Boolean,Number,Undefined,Null
引用數據類型:Object(Array,Date,RegExp,Function)
javascript中==和===的區別是什麼?==會自動進行類型轉換,===不會
例舉3種強制類型轉換和2種隱式類型轉換?強制(parseInt,parseFloat,Number())
隱式(==)1==」1」//true
null==undefined//true
原生 JS 中 call()、apply()、bind() 方法有什麼區別?三個方法都可以改變函數運行時的 this 指向。
三個方法第一個參數都是函數調用執行時this 指向的對象。
call() 方法第二個參數是個可變參數,是函數調用執行時本身所需要的參數。
apply() 方法第二個參數是數組或arguments。call()與apply()都是立即調用函數執行,在運行時修改this指向。
bind()是返回一個新的函數,新函數的函數主體與原函數的函數主體一致,當新函數被調用時,函數體中 this 指向的是 bind() 方法第一個參數傳遞的對象,而bind() 方法不會影響原函數本身的 this 指向。
什麼是閉包?特點是?閉包,官方對閉包的解釋是:一個擁有許多變量和綁定了這些變量的環境的表達式(通常是一個函數),因而這些變量也是該表達式的一部分。
閉包的特點:
(1)作為一個函數變量的一個引用,當函數返回時,其處於激活狀態。
(2) 一個閉包就是當一個函數返回時,一個沒有釋放資源的棧區。
簡單的說,Javascript允許使用內部函數---即函數定義和函數表達式位於另一個函數的函數體內。而且,這些內部函數可以訪問它們所在的外部函數中聲明的所有局部變量、參數和聲明的其他內部函數。當其中一個這樣的內部函數在包含它們的外部函數之外被調用時,就會形成閉包。
事件委託是什麼?符合W3C標準的事件綁定addEventLisntener /attachEvent
讓利用事件冒泡的原理,讓自己的所觸發的事件,讓他的父元素代替執行!
如何阻止事件冒泡和默認事件e. stopPropagation();//標準瀏覽器
event.canceBubble=true;//ie9之前
阻止默認事件:
為了不讓a點擊之後跳轉,我們就要給他的點擊事件進行阻止
return false
e.preventDefault();
document load 和document ready的區別?Document.onload 是在結構和樣式加載完才執行js
window.onload:不僅僅要在結構和樣式加載完,還要執行完所有的樣式、圖片這些資源文件,全部加載完才會觸發window.onload事件
Document.ready原生種沒有這個方法,jquery中有 $().ready(function)
為了保證頁面輸出安全,我們經常需要對一些特殊的字符進行轉義,請寫一個函數escapeHtml,將<, >, &, 「進行轉義return str.replace(/[<>」&]/g, function(match) {
switch (match) {
case 「<」:
return 「<」;
case 「>」:
return 「>」;
case 「&」:
return 「&」;
case 「\」」:
return 「"」;
}
});
}
簡述創建函數的幾種方式第一種(函數聲明):function sum1(num1,num2){return num1+num2;}
第二種(函數表達式):var sum2 = function(num1,num2){return num1+num2;}
第三種(函數對象方式):var sum3 = new Function("num1","num2","return num1+num2");
把 Script 標籤 放在頁面的最底部的body封閉之前 和封閉之後有什麼區別?瀏覽器會如何解析它們?如果說放在body的封閉之前,將會阻塞其他資源的加載
如果放在body封閉之後,不會影響body內元素的加載
iframe的優缺點?優點:
缺點:
Javascript如何實現繼承?原型鏈繼承,借用構造函數繼承,組合繼承,寄生式繼承,寄生組合繼承
請你談談Cookie的弊端?缺點:
1.Cookie數量和長度的限制。部分瀏覽器每個domain最多只能有50條cookie,基本所有瀏覽器中每個cookie長度不能超過4KB,否則會被截掉。
2.安全性問題。如果cookie被人攔截了,那人就可以取得所有的session信息。即使加密也與事無補,因為攔截者並不需要知道cookie的意義,他只要原樣轉發cookie就可以達到目的了。
3.有些狀態不可能保存在客戶端。例如,為了防止重複提交表單,我們需要在伺服器端保存一個計數器。如果我們把這個計數器保存在客戶端,那麼它起不到任何作用。
4.佔用網絡上傳帶寬。每次請求伺服器資源時,都會攜帶 cookie 信息向伺服器傳遞。
如何解決跨域問題?理解跨域的概念:URL的協議、域名、埠都相同才是同域,否則都是跨域
出於安全考慮,瀏覽器不允許跨域獲取數據,這是瀏覽器同源策略的限制,但實際開發過程中會遇到非常多的跨域問題,具體解決跨域的方式可以參考我的另一篇文章:
項目實戰之跨域處理~一文搞所有跨域需求
DOM操作——怎樣添加、移除、移動、複製、創建和查找節點?創建新節點createDocumentFragment() // 創建一個DOM片段createElement() // 創建一個具體的元素createTextNode() // 創建一個文本節點添加、移除、替換、插入insertBefore() // 在已有的子節點前插入一個新的子節點查找getElementsByTagName() // 通過標籤名稱getElementsByName() // 通過元素的Name屬性的值(IE容錯能力較強,會得到一個數組,其中包括id等於name值的)getElementById() // 通過元素Id,唯一性js延遲加載的方式有哪些?動態創建DOM方式(創建script,插入到DOM中,加載完畢後callBack)documen.write和 innerHTML 的區別?document.write 只能重繪整個頁面
innerHTML 可以重繪頁面的一部分
哪些操作會造成內存洩漏?內存洩漏指任何對象在您不再擁有或需要它之後仍然存在。垃圾回收器定期掃描對象,並計算引用了每個對象的其他對象的數量。如果一個對象的引用數量為 0(沒有其他對象引用過該對象),或對該對象的惟一引用是循環的,那麼該對象的內存即可回收。
setTimeout 的第一個參數使用字符串而非函數的話,會引發內存洩漏。循環(在兩個對象彼此引用且彼此保留時,就會產生一個循環)判斷一個字符串中出現次數最多的字符,統計這個次數?var str = 'asdfssaaasasasasaa';
var json = {};
for (var i = 0; i < str.length; i++) {
if(!json[str.charAt(i)]){
json[str.charAt(i)] = 1;
}else{
json[str.charAt(i)]++;
}
};
var iMax = 0;
var iIndex = '';
for(var i in json){
if(json[i]>iMax){
iMax = json[i];
iIndex = i;
}
}
alert('出現次數最多的是:'+iIndex+'出現'+iMax+'次');
數組扁平化數組扁平化是指將一個多維數組變為一個一維數組
const arr = [1, [2, [3, [4, 5]]], 6];
// => [1, 2, 3, 4, 5, 6]
方法一:使用flat()const res1 = arr.flat(Infinity);
方法二:利用正則const res2 = JSON.stringify(arr).replace(/\[|\]/g, '').split(',');但數據類型都會變為字符串
方法三:正則改良版本const res3 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']');
方法四:使用reduceconst flatten = arr => {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
}, [])
}
const res4 = flatten(arr);
方法五:函數遞歸const res5 = [];
const fn = arr => {
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
fn(arr[i]);
} else {
res5.push(arr[i]);
}
}
}
fn(arr);
數組去重const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];
// => [1, '1', 17, true, false, 'true', 'a', {}, {}]
方法一:利用Setconst res1 = Array.from(new Set(arr));
方法二:兩層for循環+spliceconst unique1 = arr => {
let len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
// 每刪除一個樹,j--保證j的值經過自加後不變。同時,len--,減少循環次數提升性能
len--;
j--;
}
}
}
return arr;
}
方法三:利用indexOfconst unique2 = arr => {
const res = [];
for (let i = 0; i < arr.length; i++) {
if (res.indexOf(arr[i]) === -1) res.push(arr[i]);
}
return res;
}
方法四:利用includeconst unique3 = arr => {
const res = [];
for (let i = 0; i < arr.length; i++) {
if (!res.includes(arr[i])) res.push(arr[i]);
}
return res;
}
方法五:利用filterconst unique4 = arr => {
return arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
}
方法六:利用Mapconst unique5 = arr => {
const map = new Map();
const res = [];
for (let i = 0; i < arr.length; i++) {
if (!map.has(arr[i])) {
map.set(arr[i], true)
res.push(arr[i]);
}
}
return res;
}
類數組轉化為數組類數組是具有length屬性,但不具有數組原型上的方法。常見的類數組有arguments、DOM操作方法返回的結果。
方法一:Array.fromArray.from(document.querySelectorAll('div'))
方法二:Array.prototype.slice.call()Array.prototype.slice.call(document.querySelectorAll('div'))
方法三:擴展運算符[...document.querySelectorAll('div')]
方法四:利用concatArray.prototype.concat.apply([], document.querySelectorAll('div'));
debounce(防抖)觸發高頻時間後n秒內函數只會執行一次,如果n秒內高頻時間再次觸發,則重新計算時間。
const debounce = (fn, time) => {
let timeout = null;
return function() {
clearTimeout(timeout)
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, time);
}
};防抖常應用於用戶進行搜索輸入節約請求資源,window觸發resize事件時進行防抖只觸發一次。
throttle(節流)高頻時間觸發,但n秒內只會執行一次,所以節流會稀釋函數的執行頻率。
const throttle = (fn, time) => {
let flag = true;
return function() {
if (!flag) return;
flag = false;
setTimeout(() => {
fn.apply(this, arguments);
flag = true;
}, time);
}
}節流常應用於滑鼠不斷點擊觸發、監聽滾動事件。
函數珂裡化指的是將一個接受多個參數的函數 變為 接受一個參數返回一個函數的固定形式,這樣便於再次調用,例如f(1)(2)
經典面試題:實現add(1)(2)(3)(4)=10; 、 add(1)(1,2,3)(2)=9;
function add() {
const _args = [...arguments];
function fn() {
_args.push(...arguments);
return fn;
}
fn.toString = function() {
return _args.reduce((sum, cur) => sum + cur);
}
return fn;
}
深拷貝遞歸的完整版本(考慮到了Symbol屬性):
const cloneDeep1 = (target, hash = new WeakMap()) => {
// 對於傳入參數處理
if (typeof target !== 'object' || target === null) {
return target;
}
// 哈希表中存在直接返回
if (hash.has(target)) return hash.get(target);
const cloneTarget = Array.isArray(target) ? [] : {};
hash.set(target, cloneTarget);
// 針對Symbol屬性
const symKeys = Object.getOwnPropertySymbols(target);
if (symKeys.length) {
symKeys.forEach(symKey => {
if (typeof target[symKey] === 'object' && target[symKey] !== null) {
cloneTarget[symKey] = cloneDeep1(target[symKey]);
} else {
cloneTarget[symKey] = target[symKey];
}
})
}
for (const i in target) {
if (Object.prototype.hasOwnProperty.call(target, i)) {
cloneTarget[i] =
typeof target[i] === 'object' && target[i] !== null
? cloneDeep1(target[i], hash)
: target[i];
}
}
return cloneTarget;
}