自己總結了一些JS面試題

希望能夠幫助正在找工作的程序猿

1,.解釋下原型繼承的原理

以下代碼展示了JS引擎如何查找屬性

function getProperty(obj,prop) {

if (obj.hasOwnProperty(prop)) {

return obj[prop];

} else if (obj.__proto__!==null) {

return getProperty(obj.__proto__,prop);

} else {

return undefined;

}

}

2,什麼是閉包,如何使用它,為什麼要使用它?

閉包就是能夠讀取其他函數內部變數的函數。由於在Javascript語言中,只有函數內部的子函數才能讀取局部變數,因此可以把閉包簡單理解成「定義在一個函數內部的函數」。

所以,在本質上,閉包就是將函數內部和函數外部連接起來的一座橋樑。閉包可以用在許多地方。它的最大用處有兩個,一個是前面提到的可以讀取函數內部的變數,另一個就是讓這些變數的值始終保持在內存中。

使用閉包的注意點:

  • 由於閉包會使得函數中的變數都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變數全部刪除。
  • 閉包會在父函數外部,改變父函數內部變數的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變數的值。

3,實現 repeatStr

function strrepeat(str,num){

return new Array(num + 1).join(str);

}

strrepeat("hello",3)

4,寫一個function,清除字元串前後的空格。(兼容所有瀏覽器)

function trim(str) {
if (str & typeof str === "string") {
return str.replace(/(^s*)|(s*)$/g,""); //去除前後空白符
}
}

5, 降維數據(鋪平數組)

var arr=[[1,2],[3,4]];
function Jw(obj){
return Array.prototype.concat.apply([],obj);
}
Jw(arr);

看一下鋪平多維數組的方法

數組扁平化
數組扁平化有很多方法但最終最好的方法就是遞歸實現一個指定深度的扁平化方法這樣基本的套路都會了解

function flattenDepth(array, depth = 1) {
let result = []
array.forEach(item => {
let d = depth
if (Array.isArray(item) && d > 0) {
result.push(...(flattenDepth(item, --d)))
} else {
result.push(item)
}
})
return result
}

console.log(flattenDepth([1, [2, [3, [4]], 5]])) // [ 1, 2, [ 3, [ 4 ] ], 5 ]
console.log(flattenDepth([1, [2, [3, [4]], 5]], 2)) // [ 1, 2, 3, [ 4 ], 5 ]
console.log(flattenDepth([1, [2, [3, [4]], 5]], 3)) // [ 1, 2, 3, 4, 5 ]

6,對象轉數組

var data={a:1,b:2,c:3};
function toArr(obj){
var arr1=[];
for(var i in obj){
arr1.push(obj[i]);
}
return arr1;
// arr1.fitter(function(x){console.log(arr1(x))});
}
console.log(toArr(data));

7,將url的查詢參數解析成字典對象

function getQueryObject(url) {
url = url == null ? window.location.href : url;
var search = url.substring(url.lastIndexOf("?") + 1);
var obj = {};
var reg = /([^?&=]+)=([^?&=]*)/g;
search.replace(reg, function (rs, $1, $2) {
var name = decodeURIComponent($1);
var val = decodeURIComponent($2);
val = String(val);
obj[name] = val;
return rs;
});
return obj;
}

8,請用js計算1-10000中出現的0 的次數

new Array(10000).fill().map((_, index) => index + 1).filter(item => /0/.test(item)).reduce((count, item) => { return count + (String(item).match(/0/g) || []).length}, 0)

9,js 實現一個函數對javascript中json 對象進行克隆

var oldObject ="sdf";
var newObject = JSON.parse(JSON.stringify(oldObject));
console.log(newObject);
或者
var a = dddd;
function cp(a){return JSON.parse(JSON.stringify(a))}
console.log(cp(a));

10, 柯里化

函數的柯里化都被講爛了,每個人都有自己的理解和實現方法,一句話解釋就是參數夠了就執行,參數不夠就返回一個函數,之前的參數存起來,直到夠了為止

function curry(func) {
var l = func.length
return function curried() {
var args = [].slice.call(arguments)
if(args.length < l) {
return function() {
var argsInner = [].slice.call(arguments)
return curried.apply(this, args.concat(argsInner))
}
} else {
return func.apply(this, args)
}
}
}

var f = function(a, b, c) {
return console.log([a, b, c])
};

var curried = curry(f)
curried(1)(2)(3) // => [1, 2, 3]
curried(1, 2)(3) // => [1, 2, 3]
curried(1, 2, 3) // => [1, 2, 3]

11,對象深拷貝

JSON.parse(JSON.stringify({a:{b:{c:1}}}))

還有個方法就是使用遞歸了

function clone(value, isDeep) {
if (value === null) return null
if (typeof value !== object) return value
if (Array.isArray(value)) {
if (isDeep) {
return value.map(item => clone(item, true))
}
return [].concat(value)
} else {
if (isDeep) {
var obj = {}
Object.keys(value).forEach(item => {
obj[item] = clone(value[item], true)
})
return obj
}
return { ...value }
}
}

var objects = { c: { a: 1, e: [1, {f: 2}] }, d: { b: 2 } }
var shallow = clone(objects, true)

12, websocket長連接原理是什麼

含義

Websocket是一個持久化的協議,相對於HTTP這種非持久的協議來說。

原理

類似長輪循長連接 ; 發送一次請求 ; 源源不斷的得到信息

13, js垃圾回收機制知道哪些,v8引擎使用的哪一種

js的兩種回收機制

1 標記清除(mark and sweep)

2 引用計數(reference counting)

javascript與V8引擎

垃圾回收機制的好處和壞處

好處:大幅簡化程序的內存管理代碼,減輕程序猿負擔,並且減少因為長時間運轉而帶來的內存泄露問題。

壞處:自動回收意味著程序猿無法掌控內存。ECMAScript中沒有暴露垃圾回收的借口,我們無法強迫其進行垃圾回收,更加無法干預內存管理。

14, http協議屬於七層協議中的哪一層,下一層是什麼

七層結構:物理層、數據鏈路層、網路層、傳輸層、會話層、表示層、應用層

tcp屬於傳輸層;http屬於應用層。表現層

15,不用循環語句(包括map、forEach方法)實現一個100長度的數組,索引值和值相同的數組[0,1,2,3,4,5........99]

var arr = new Array(100);
//方法1
[...arr.keys()];
//方法二
Array.from(arr.keys());

//方法三
Array.from({length: 100});

// 方法四 藉助string
var arr1 = new Array(101);
var str = arr1.join(1,);
str = str.replace(/(1,)/g, function ($0, $1, index) {
var start = + Math.ceil(index/2);
if(index < str.length - 2) {
start += ,
}
return start;
});
return str.split(,);

// 方法五(函數式變成,參考網路)
function reduce(arr, val) {
if(Object.prototype.toString.apply(val)){
return;
}
if(val >= 100) {
return arr;
}
arr.push(val);
return reduce(arr, val+1);
}
var res = reduce([], 0)

16, 如何獲取匿名函數中的u

var R = (function() {
var u = {a:1,b:2};
var r = {
fn: function(k) {
return u[k];
}
}
return r;
}());
R.fn(a); // 1

17, 網頁布局有哪幾種,有什麼區別

靜態、自適應、流式、響應式四種網頁布局

靜態布局:意思就是不管瀏覽器尺寸具體是多少,網頁布局就按照當時寫代碼的布局來布置;自適應布局:就是說你看到的頁面,裡面元素的位置會變化而大小不會變化;流式布局:你看到的頁面,元素的大小會變化而位置不會變化——這就導致如果屏幕太大或者太小都會導致元素無法正常顯示。自適應布局:每個屏幕解析度下面會有一個布局樣式,同時位置會變而且大小也會變。

18, git使用過程中,如果你在開發著業務,突然另一個分支有一個bug要改,你怎麼辦

git stash //將本次修改存到暫存區(緊急切換分支時)
git stash pop //將所有暫存區的內容取出來

19, 什麼是虛擬dom

React為啥這麼大?因為它實現了一個虛擬DOM(Virtual DOM)。虛擬DOM是幹什麼的?這就要從瀏覽器本身講起

如我們所知,在瀏覽器渲染網頁的過程中,載入到HTML文檔後,會將文檔解析並構建DOM樹,然後將其與解析CSS生成的CSSOM樹一起結合產生愛的結晶——RenderObject樹,然後將RenderObject樹渲染成頁面(當然中間可能會有一些優化,比如RenderLayer樹)。這些過程都存在與渲染引擎之中,渲染引擎在瀏覽器中是於JavaScript引擎(JavaScriptCore也好V8也好)分離開的,但為了方便JS操作DOM結構,渲染引擎會暴露一些介面供JavaScript調用。由於這兩塊相互分離,通信是需要付出代價的,因此JavaScript調用DOM提供的介面性能不咋地。各種性能優化的最佳實踐也都在儘可能的減少DOM操作次數。

而虛擬DOM幹了什麼?它直接用JavaScript實現了DOM樹(大致上)。組件的HTML結構並不會直接生成DOM,而是映射生成虛擬的JavaScript DOM結構,React又通過在這個虛擬DOM上實現了一個 diff 演算法找出最小變更,再把這些變更寫入實際的DOM中。這個虛擬DOM以JS結構的形式存在,計算性能會比較好,而且由於減少了實際DOM操作次數,性能會有較大提升

20,http的cache機制,以及200狀態下怎麼實現 from cache(表示接觸最多的就是304的from cache)(用於優化,沒有接觸過,需要理解)

含義

定義:瀏覽器緩存(Browser Caching)是為了加速瀏覽,瀏覽器在用戶磁碟上對最近請求過的文檔進行存儲,當訪問者再次請求這個頁面時,瀏覽器就可以從本地磁碟顯示文檔,這樣就可以加速頁面的閱覽。

作用

cache的作用:

1、減少延遲,讓你的網站更快,提高用戶體驗。2、避免網路擁塞,減少請求量,減少輸出帶寬。

實現手段

Cache-Control中的max-age是實現內容cache的主要手段,共有3種常用策略:max-age和Last-Modified(If-Modified-Since)的組合、僅max-age、max-age和ETag的組合。

對於強制緩存,伺服器通知瀏覽器一個緩存時間,在緩存時間內,下次請求,直接用緩存,不在時間內,執行比較緩存策略。

對於比較緩存,將緩存信息中的Etag和Last-Modified通過請求發送給伺服器,由伺服器校驗,返回304狀態碼時,瀏覽器直接使用緩存。

21,var和function的預解析問題,以及變數和function的先後順序的問題

// 以下代碼執行輸出結果是什麼 function b () {
console.log(a);
var a = 10;
function a() {};
a = 100;
console.log(a);
}
b();

function c () {
console.log(a);
function a() {};
var a = 10;
a = 100;
console.log(a);
}
c();

(function d (num) {
console.log(num);
var num = 10;
}(100))

(function e (num) {
console.log(num);
var num = 10;
function num () {};
}(100))

(function f (num) {
function num () {};
console.log(num);
var num =10 console.log(num);
}(100))

//仍然是預解析(在與解析過程中還要考慮一下當前變數的作用於) function m () {
console.log(a1); // underfined console.log(a2); // underfined console.log(b1); // underfined console.log(b2); // underfined if(false) {
function b1 (){};
var a1 = 10;
}
if(true) {
function b2 (){};
var a2 = 10;
}
console.log(a1); // underfined console.log(a2); // 10 console.log(b1); // underfined console.log(b2); // function }
m();

function n() {
if(2>1) {
arr = 10;
brr = 10;
let arr;
var brr;
console.log(arr);
console.log(brr);
}
}
n(); // ReferenceError

此階段瀏覽器只是對var、function、函數形參進行一個解析的準備過程。而且在這個「預解析」過程中,有一個預解析先後順序,即函數的形參 -> function -> var。而且重名時預留函數、後來者覆蓋前者。預解析結果形參如果有值則解析到值,沒有則為underfined,函數則解析到整個函數體,變數都為underfined;這道題目中沒有參數出現,所以先不討論。所以這道題在「預解析」時,函數聲明權重優先會被提升

22, 一道this的問題

var num = 10;
var obj = {
num:8,
inner: 23,
num: 6,
print: function () {
console.log(this.num);
}
}
}
num = 888;
obj.inner.print(); // 6 var fn = obj.inner.print;
fn(); //888 (obj.inner.print)(); //6 (obj.inner.print = obj.inner.print)(); //888 這個點沒有太理解,雖然答對了

23,

11 * 2
b200 * 2

24,根據age屬性從大到小排列

var array1 = [{name:12,age:7},{name:13,age:1},{name:5,age:25},{name:11,age:17}];

function sortObj(arr){
var r = []
arr.map((v,i)=>{

r.push(v)
})
r.sort(function(a,b){
return b.name-a.name
})
console.log(r)
}
sortObj(array1)

25,斐波那契數列

function fn(n){
if(n==1|n==2){
return 1;
}

return fn(n-1)+fn(n-2);
}

26

var x =0;
function MyClass(){
this.x =1;
}
MyClass.x = 2;
MyClass.prototype.x =3;
MyClass.prototype.method = function(){
console.log(this.x);
}
const prototype = MyClass.prototype;
const method = prototype.method;
//new MyClass().method();//1
//prototype.method();//3
method()//0

27,

var num =10;
var obj = {
num:8,
inner:{
num:6,
print:function(){
console.log(num:+num+ , this.num: + this.num)
}
}

}
num =888;
//1.
obj.inner.print();//888 6
//2.
var fn = obj.inner.print; fn();//888 888
//3.
(obj.inner.print)();//888 6
//4.
(obj.inner.print = obj.inner.print)()//888 888

//-------------------
function b(){
console.log(a);// function a(){}
function a(){}
a =100;
console.log(a)//100
}
b()

推薦閱讀:

相关文章