不按期收集的面試題

Part1

1.判斷數據類型的函數
function type_fn(a){
    let result;
    if(typeof a == 'object'){
    result = (a instanceof Array)?'Array':'object'
    }else{
    result = typeof a
    }
    return result
}

說明:鑑於 數組和對象和null的typeof都是object 因此基於typeof 另外須要instanceof判斷區分

//補充 也能夠用:Object.prototype.toString.call(a).slice(8,-1)
2.原型鏈繼承的例子
function Class(){
    this.slogan = function(){
        console.log('我來自班級1');
    }
}

function Classmate(name){
    this.name = function(){
        console.log('我是'+name)
    }
}

Classmate.prototype = new Class();

//實例化
var peo1 = new Classmate('jerry');

peo1.name();    //我是jerry
peo1.slogan();  //我來自班級1
3.描述new一個對象的過程
建立一個新的對象
this指向新的對象
對this賦值 執行代碼
返回this
4.zepto(或其餘框架下如何使用原型鏈)
/**
 * 原型鏈繼承的例子
 * 功能: 1.獲取元素改變或者獲取他的innerhtml。
 *       2.添加事件。
 */

//構造函數
function Elem(id){
    this.elem = document.getElementById(id);
};
//在其原型上添加方法
Elem.prototype.html = function(val){
    var elem=this.elem;
    if(val){
        elem.innerHTML = val;
        return this;  //鏈式調用
    }else{
        return elem.innerHTML;
    }
}

Elem.prototype.on = function(type,fn){
    var elem=this.elem;
    elem.addEventListener(type,fn);
    return this;
}


var div=new Elem('app');
div.html(`<h1>你好javascript</h1>`).on('click',function(){
    alert('我是天使')
})

原文連接:https://blog.csdn.net/qq_24675001/article/details/82054443
5.說一下對變量提高的理解

當JavaScript執行過程進入新函數時,這個函數內被聲明的全部變量都會被移動導到函數最開始的地方。這種現象叫作提高。且被提高的只有變量的聲明。javascript

函數執行時會先建立當前的上下文環境,其中這兩點會產生「變量提高」的效果php

  • 變量定義
  • 函數聲明(注意和函數表達式的區別)
6.說明this幾種不一樣的使用場景

做爲構造函數時的執行 指向構造函數的對象css

做爲對象屬性時的執行 指向對象html

做爲普通函數時的執行 指向window前端

call  bind apply 從新把this指向新對象java

7.建立10個li,點擊的時候彈出對應的序號
var i
for (i = 0; i < 10; i++) {
    (function (i) {
        var a = document.createElement('a')
        a.innerHTML = i + '<br>'
        a.addEventListener('click', function (e) {
            e.preventDefault()
            alert(i)
        })
        document.body.appendChild(a)
    })(i)
}
8.如何理解做用域
*   自由變量
*   做用域鏈,即自由變量的查找
*   閉包的兩個場景
9.實際開發中閉包的應用
// 閉包實際應用中主要用於封裝變量,收斂權限
// 即把變量隱藏起來,不讓外面拿到和修改
function isFirstLoad() {
    var _list = []

    return function (id) {
        if (_list.indexOf(id) >= 0) {
            return false
        } else {
            _list.push(id)
            return true
        }
    }
}

// 使用
var firstLoad = isFirstLoad()
firstLoad(10) // true          
firstLoad(10) // false
firstLoad(20) // true

// 在 isFirstLoad 函數外面,根本不可能修改掉 _list 的值
10.同步異步的區別是什麼?分別舉一個例子
同步會阻塞代碼 而異步不會

alert 是同步 
setTimeout 是異步

eg:
console.log('1');
setTimeout(function(){
    console.log('2');
},200)
console.log('3');
-------------

console.log('1')
alert('2')
console.log('3');
11.一個關於setTimeout的筆試題
jq源碼裏面利用了js程序的單線程 寫了setTimeout(function(){})來解決 等頁面加載完;
------------------
console.log(1);
setTimeout(function(){
    console.log(2)
},0)
console.log(3)
setTimeout(function(){
    console.log(4)
},1000)
console.log(5)

>> 1 3 5 2 4
12.前端使用異步的場景
定時任務: setTimeout setInverval 
網絡請求: ajax請求  動態<img>加載
事件綁定
13.Date 獲取 2020-01-21格式的日期
function time(){
    var date = new Date();
    var year = date.getFullYear();
    var month = date.getMonth()+1;
    var day = date.getDate();
    return year+'-'+num_fn(month)+'-'+num_fn(day);
}
function num_fn(num){
    return num>=10? num : '0'+num
}
14.Math 獲取隨機字符串要求是長度一致的字符串格式
function randomAtr(){
         return Math.floor(Math.random()*1000000000)
         
         //或者
         //var num = Math.random()+'';
         //return num.slice(2,13)
}
15.能寫一個能遍歷對象和數組的的forEach函數
function forEach_fn(obj,fn){
var key;
if(obj instanceof Array){
    arr.forEach(function(item, index){
        fn(index, item)//遍歷數組全部的元素
    })
}else{
    for(key in obj){
        fn(key, obj[key])
    }
}

}ajax

16.DOM是哪一種的基本數據結構

DOM樹形結構json

17.DOM操做的經常使用API有哪些

建立型api:createElementcreateTextNodecloneNodecreateDocumentFragment後端

頁面修改型API
修改頁面內容的api主要包括:appendChildinsertBeforeremoveChildreplaceChildapi

節點查詢型API
document.getElementById
document.getElementsByTagName
document.getElementsByName
document.getElementsByClassName
document.querySelector和document.querySelectorAll:經過css選擇器來查找元素,注意選擇器要符合CSS選擇器的規則,使用的深度優先搜索來獲取元素

節點關係型api

1.父關係型api

  • parentNode:Element的父節點多是Element,Document或DocumentFragment。
  • parentElement:與parentNode的區別在於,其父節點必須是一個Element,若是不是,則返回null

2.子關係型api

  • childNodes:返回一個即時的NodeList,表示元素的子節點列表,子節點可能會包含文本節點,註釋節點等。
  • children:一個即時的HTMLCollection,子節點都是Element,IE9如下瀏覽器不支持。
  • firstNode:第一個子節點
  • lastNode:最後一個子節點
  • hasChildNodes方法:能夠用來判斷是否包含子節點。

3.兄弟關係型api

  • previousSibling:節點的前節點,若是該節點是第一個節點,則爲null。
  • previousElementSibling:返回前元素節點,前一個節點必須是Element。
  • nextSibling:節點的後節點,若是該節點是最後一個節點,則爲null。。
  • nextElementSibling:返回後元素節點,後一個節點必須是Element。

元素屬性型api
setAttribute:根據名稱和值修改元素的特性eg:element.setAttribute(name, value);
getAttribute:返回指定的特性名相應的特性值,若是不存在,則返回null或空字符串.

18.DOM節點的attr和property有何區別

property 只是一個JS對象的屬性的修改
Attribute 是對html標籤屬性的修改

19.如何檢測瀏覽器的類型

navigator.userAgent 加正則匹配

20.拆解url的各部分
href        完整的 URL。

protocol    當前 URL 的協議。
host        主機名和當前 URL 的端口號。
hostname    當前 URL 的主機名。
pathname    當前 URL 的路徑部分。
port        當前 URL 的端口號。

hash        hash。從井號(#)開始)。
search        參數。從問號(?)開始的。
21.編寫一個通用的事件監聽函數
function bindEvent(elem,type,selector,fn){
    if(fn == null){
        fn = selector;
        selector = null;
    }
    elem.addEventListener(type,function(e){
        var target;
        if(selector){//有代理
            target = e.target;
            if(target.macthes(target)){
                fn.call(target,e)//從新指定this 並傳參e
            }
        }else{//無代理
            fn(e);
        }
    })
    
}
22.描述事件冒泡的過程
沿着DOM樹形結構,一層層網上冒泡,
一直到 最頂端或者出現阻止冒泡命令
e.stopPropagation();
冒泡的應用 代理
23.對於一個無限下拉加載圖片的頁面,如何給每一個圖片綁定事件
事件委派

24.手動編寫一個ajax,不依賴第三方庫

1.建立ajax對象
2.接收服務器
3.發送請求
4.接收返回值

var oAjax = new XMLHttpRequest();
oAjax.open("GET","text.json",false);
oAjax.send();
oAjax.onreadystatechange(function(){
    if(oAjax.readyState == 4){
        if(oAjax.status == 200){
            console.log(oAjax.responseText)
        }
    }
})
25.狀態碼的說明;
  • 0開頭 未初始化 尚未調用open()方法;
  • 1開頭 載入 已調用open()方法,正在發送請求
  • 2開頭 載入完成 send()方法完成,已收到所有響應內容
  • 3開頭 解析 正在解析響應內容
  • 4開頭 完成 響應內容解析完成,能夠再客戶端調用
  • 5開頭 服務器錯誤
26.跨域的幾種實現方式
1. 服務器請求頭修改
2. 重定向代理
3. jsonp
jsonp跨域 原生實現:
 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 傳參並指定回調執行函數爲onBack
    script.src = 'http://www.....:8080/login?user=admin&callback=onBack';
    document.head.appendChild(script);

    // 回調執行函數
    function onBack(res) {
        alert(JSON.stringify(res));
    }
 </script>
26.GET POST區別;
get 安全性差 容量低 有緩存 經過url傳  通常用於獲取數據

post 安全性高 容量高 無緩存  通常用於用戶註冊

27.描述cookies、sessionStrorage localStrorage的區別;
  • cookies

    • 存儲量小 只有4K,
    • 全部http請求都帶着,會影響獲取資源的效率
    • 封裝才能用 document.cookies
    • 能夠設置過時時間;服務器也能訪問設置;
  • sessionStrorage

    • 存儲量大 最大5M;
    • 簡單易用
    • 不能設置過時時間,關閉瀏覽器會刪除
  • localStrorage

    • 存儲量大 最大5M;
    • 簡單易用
    • 須要手動刪除緩存
localStorage.setItem("saveData", JSON.stringify(setData) ); //存值 補充:存儲前先用JSON.stringify()將json對象轉字符串
    
localStorage.getItem("saveData」) //取值 補充:JSON.parse(ss) 將json字符串轉爲 json格式
    
localStorage.removeItem("saveData」);//刪值
28.從輸入url到html的詳細過程
瀏覽器根據DNS服務器獲得域名的IP地址

向這個IP的機器發送https/https請求

服務器收到、處理並返回請求

瀏覽器獲得返回內容
29.window.onload和DOMContentLoaded的區別
window.onload:頁面的所有資源加載完纔會執行,包括圖片、視頻等
DOMContentLoaded:DOM渲染完便可執行,此時圖片、視頻尚未加載完
30.性能優化
性能優化:
多使用內存、緩存或其餘方法   
減小cpu計算、減小網絡   

加載資源優化:
1靜態資源的合併壓縮 
2靜態資源緩存 
3使用CDN讓資源加載更快  
4使用SSR後端渲染,數據直接輸出到HTML中

渲染優化:
1.CSS放前面 JS放後面
2.懶加載(圖片懶加載、下拉加載更多)
3.減小DOM查詢,對DOM查詢作緩存  
4.減小DOM操做,多個操做盡可能合併在一塊兒執行
5.事件節流
6.儘早執行操做(如DOMContentLoaded)

Part2

1.移動端怎樣處理 移動端 1px 被 渲染成 2px 問題
1 局部處理
meta標籤中的 viewport屬性 ,initial-scale 設置爲 1 
rem 按照設計稿標準走,外加利用transfrome 的scale(0.5) 縮小一倍便可;
2 全局處理
meta標籤中的 viewport屬性 ,initial-scale 設置爲 0.5
    rem 按照設計稿標準走便可
2.let var const
名字 特性說明
var 變量; 能重複聲明; 函數級; 頂層對象的屬性; 不限制修改
let 變量; 不能重複聲明; 塊級; 不屬於頂層對象的屬性; 可修改
const 聲明和賦值必須是同時進行; 常量; 不能重複聲明; 塊級; 不屬於頂層對象的屬性; "不"可修改[ 實際上並不是徹底不可修改。const聲明建立一個值的只讀引用,對於基本類型不可修改,但若是是複合類型時,只要不修改引用,修改裏面的值是能夠的];
代碼演示:
console.log(k_name); //變量提高;輸出undefined
var k_name = "jerry";
console.log(k_name);//輸出jerry

console.log('1',k_age);//不會變量提高;在定義以前報錯不能用
let k_age = "12";
console.log('2',k_age);

//const基礎類型時
const may_class = 3;
may_class = 4;//基礎類型時 報錯

//const複雜類型時
const all_class = [1,2,3];
all_class[0] = 9; //不報錯
console.log(all_class);//修改爲功 》[9, 2, 3]
3.編寫個簡單的url解析和賦值替換
var url = "http://witmax.cn/index.php?key0=0&key1=1&key2=2";

// 返回url的拼接對象
function parseQueryString(argu) {
    var str = argu.split('?')[1];
    var result = {};
    var temp = str.split('&');
    for (vari = 0; i < temp.length; i++) {
        var temp2 = temp[i].split('=');
        result[temp2[0]] = temp2[1];
    }
    return result; //url上的所有參

}

// 拓展一下 對頁面url操做, 只有一個參 那麼查找url上的參數並返回值, 若是有兩個參數查找更新或刪除參數
function urlSearch(argu ,newValue) {
    var str = window.location.search.slice(1);
    var result = {};
    var temp = str.split('&');
    for (vari = 0; i < temp.length; i++) {
        var temp2 = temp[i].split('=');
        result[temp2[0]] = temp2[1];
    }
    return result; //url上的所有參

    if (newValue !== undefined) {
        if (newValue !== null) {
            result[argu] = newValue;//更新值
        }else {
            delete result[argu];//刪除值
        }
        // 更新參數後從新拼接 並替換url的連接
        var str = '';
        for(k in ee){
            str += (k + '=' + ee[k] + '&');
        }
        str = str.replace(/&$/,'');
        // var newUrl = window.decodeURIComponent(argu.split('?')[0]+'?'+str);
        var newUrl = window.location.href.split('?')[0]+'?'+str;
        window.history.pushState(null, document.title,newUrl);
        // return newUrl;
    }else{
        return result[argu];
    }
}
4.看看如下分別輸出什麼
if([] == false){ alert(1)} //在比較前false轉成0 [].toString()轉成了空字符串 空字符串轉成0, ;因此true
 if({} == false){ alert(2)}//在比較前false轉成0, {}.toString()轉成"[object Object]" 不等
 
 if([]){ alert(3)}
 
 //引用類型(數組 對象 函數)的比較並不是值的比較:兩個對象保含一樣的屬性及相同的值 它們是不相等的。 各個因此元素徹底相等的兩個數組也不相等。
 if([1] == [1]){ alert(4)}
 if({x:1} == {x:1} ){ alert(4)}

引用類型的比較均是引用的比較:當且僅當它們引用同一個基對象時,它們才相等 eg:

var a = [];
var b = a; //變量b引用同一個數組
b[0] = 1;
console.log(b); // [1]
console.log(a); // [1]

a === b; //true: a和b引用同一個數據,所以它們相等
 
 
###### 給定一個整數數組,找出其中兩個數相加等於目標值
5.給定數組及目標值 nums = [2,7,11,15] ,target = 9 由於nums[0] + nums[1] = 2 + 7 = 9 返回[0,1]
var twoSum = function(nums, target) {
var cbArr = [];
for(var i = 0; i< nums.length; i++){
    if(cbArr.indexOf(i) == -1){ //除去已經在結果裏面的 避免重複
        for(var k = 0; k< nums.length; k++){
            if((i !== k) && (nums[i]+ nums[k] == target)){
                cbArr.push(i,k);
            }
        }
    }
}
return cbArr;
};
6.字符串的左旋轉操做是把字符串前面的若干個字符轉移到字符串的尾部。請定義一個函數實現字符串左旋轉操做的功能。
eg:
輸入: s = "lrloseumgh", k = 6
輸出: "umghlrlose"

var reverseLeftWords = function(s, n) {     
    return s.slice(n).concat(s.slice(0,n))
};
8.給定一個分別輸出一下的值:
function Foo(){
    getName = function(){alert(1)};
    return this;
}

Foo.getName = function(){alert(2)};
Foo.prototype.getName = function(){alert(3)};
var getName = function(){alert(4)};
function getName(){alert(5)};


Foo.getName(); 
getName();   
Foo().getName();     
getName();             
new Foo().getName();   

答案----
//2 4 1 1 3
9.輸出一下值 並分析:
function fn(a) {

    console.log(a)  
    var a = 123;    
    console.log(a)  
    function a() {}
    console.log(a)  
    
    var b = function() {
        console.log('bb','1')
    }
    console.log(b)  
    b(); 
    function b() {
        console.log('bb','2')
    }
}
fn(1)


 --------------------------
a的分析:
進入fn 雖然帶參數a進去 可是 進到函數   
1 最開始a有聲明式函數,會直接掛載在函數下,因此第一個打印是function;
2 第一個打印後立刻就給a賦值了123, 因此第二個打印是123;
3 下一行 a的聲明式函數比2執行還早 因此不影響 第三個打印是123;

--------------------------
b的分析:
1 b無論屬於誰打印確定是function;
2 最開始b有聲明式函數,會直接掛載在函數下,而後var 從新賦值了b的函數 因此 輸出是

答案:function  123 123    function  bb 1
10. 輸出下面值
var i= 10;
function a(){
    i = 20;
    console.log(i); // 20;
    for(var i=0; i<6;i++){
        console.log(i) // 0-5
    }
    console.log(this.i); //10 :window.i  外部環境不能訪問內部環境中的任何變量和函數
    console.log(i);     //6  : 當前的局部變量在循環時被賦值爲6
}
a();
console.log(i) //10 :window.i  外部環境不能訪問內部環境中的任何變量和函數
11.js函數add(1)(2)(3)(4)的累加

想法:寫個閉包每次返回函數都帶參累加,知道參數沒有再也不執行函數 則返回累加的和。
先寫個暴力概念版 只要我寫得夠多就能'知足'題目要求:

function add(a){
    let sum = a;
    return function count_fn1(b){
        sum +=b;
        return function count_fn1(c){
            sum +=c;
                return function count_fn1(d){
                sum +=d;
                return sum;
            };
        };
    }
}
add(1)(2)(3)(4)//10
全然不顧靈活不靈活拓展不拓展~ 老子就是幹

不 咱們不能僅苟且的活着!要靈活要自由~

function add(a){
    let sum = a;
    return function count_fn(b){
        sum +=b;
        return count_fn(b);
    }
}
//改爲遞歸 是能夠靈活執行多少次函數達到累加。問題 輸出的也是函數 沒有把累計的值輸出出來呀!

這時咱們要了解一個知識點:當咱們直接對函數使用alert()console.log()時,函數的toString()方法會被調用。並且函數的toString()方法是能夠複寫的

最終版:

function add(x) {
    var sum = x;
    var tmp = function (y) {
        sum = sum + y;
        return tmp;
    };
    tmp.toString = function () {
        return sum;
    };
    return tmp;
}
console.log(add(1)(2)(3));  //6
12. 輸出是什麼?
(() => {
  let x, y
  try {
    throw new Error()
  } catch (x) {
    (x = 1), (y = 2)
    console.log(x)
  }
  console.log(x)
  console.log(y)
})()

答案:
1 undefined 2;
分析:
catch 代碼塊接收參數 x。當咱們傳遞參數時,這與以前定義的變量 x 不一樣 。這個 x 是屬於 catch 塊級做用域的且 默認了設置了等於1; 因此第一個打印1;
外面x依然沒賦值;因此第二個打印`undefined`;
y最開始let聲明瞭,後面賦值了2,因此第二個打印2;
13. 輸出是什麼?
let person = { name: "Lydia" };
const members = [person];
person = null;

console.log(members);


答案:[{ name: "Lydia" }];
分析:  
當設置兩個對象彼此相等時,它們會經過 引用進行交互。可是當將`引用從一個變量分配至另外一個變量時`,實際上是執行了 複製 操做。 因此它們的引用並不一樣
14. 輸出是什麼?
const settings = {
  username: "lydiahallie",
  level: 19,
  health: 90
};

const data = JSON.stringify(settings, ["level", "health"]);
console.log(data);

答案:"{"level":19, "health":90}"
分析:
[JSON.stringify(value[, replacer[, space]])](https://www.runoob.com/js/javascript-json-stringify.html)//老子還有第二第三個參數可傳哦。
// 參數一:轉換的值
// 參數二:替代者。用於轉換結果的函數或數組。
// 參數三:控制空格

JSON.stringify的第二個參數是 替代者(replacer). 替代者(replacer)能夠是個函數或數組,用以控制哪些值如何被轉換爲字符串。
若是替代者(replacer)是個 數組 ,那麼就只有包含在數組中的屬性將會被轉化爲字符串。在本例中,只有名爲"level" 和 "health" 的屬性被包括進來, "username"則被排除在外。 data 就等於 "{"level":19, "health":90}」.
15.懶加載預加載

懶加載: 圖片的懶加載作法 都是把連接存放在 data-src中,監聽onscroll時,一個個加載出來;

預加載:將全部所需的資源提早請求加載到本地,這樣後面在須要用到時就直接從緩存取資源。
實現預加載的幾種辦法:

//使用img標籤 
<img src="http://pic26.nipic.com/20121213/6168183 0044449030002.jpg" style="display:none」/> 

------------
//js 使用Image對象
<script src="./myPreload.js"></script>

//myPreload.js文件
var image= new Image()
image.src="http://pic26.nipic.com/20121213/6168183 004444903000 2.jpg"

-------------
//使用PreloadJS庫

-------------
//使用XMLHttpRequest對象,雖然存在跨域問題,但會精細控制預加載過程
var xmlhttprequest=new XMLHttpRequest();
xmlhttprequest.onreadystatechange=callback;
xmlhttprequest.onprogress=progressCallback;
xmlhttprequest.open("GET","http://image.baidu.com/mouse,jpg",true);
xmlhttprequest.send();
function callback(){
  if(xmlhttprequest.readyState==4&& xmlhttprequest.status==200){
    var responseText=xmlhttprequest.responseText;
  }else{
     console.log("Request was unsuccessful:"+xmlhttprequest.status);
  }
}
function progressCallback(e){
    e=e || event;
    if(e.lengthComputable){
    console.log("Received"+e.loaded+"of"+e.total+"bytes")
    }
}
16.break continue return throw分別是?
1.break 跳出循環
2.continue 跳出本次循環,進入下次循環
3.return 停止跳出當前函數
4.throw 異常信息;停止程序拋出異常,可用於停止程序
17.內存泄漏

定義:內存泄漏指任何對象在您再也不擁有或須要它以後仍然存在。
後果:變慢,崩潰,延遲大等:
哪些會形成:

  • 定時器未清除
  • 閉包、控制檯日誌、循環(在兩個對象彼此引用且彼此保留時,就會產生一個循環)
  • dom清空時,還存在引用

避免策略

  • 減小沒必要要的全局變量,或者生命週期較長的對象,及時對無用的數據進行垃圾回收;
  • 注意程序邏輯,避免「死循環」之類的 ;
  • 避免建立過多的對象 原則:不用了的東西要及時歸還。
  • 減小層級過多的引用
18.重繪和迴流(重排)是什麼,如何避免?

重繪:改變元素的樣式。例如寬高顏色。
迴流(重排):佈局和樣式都改變。

重排必定重繪,重繪不必定重排。

減小重繪和重排的方法

  • 不在佈局信息改變時作DOM查詢
  • 使用cssText或者className一次性改變屬性
  • 使用fragment
  • 對於屢次重排的元素,如動畫,使用絕對定位脫離文檔流,讓他的改變不影響到其餘元素
  • 使用translate替代top
相關文章
相關標籤/搜索