web前端面試

web前端面試題總結

1 HTML

1.1 常見元素

塊級元素css

  • h1-h6 標題
  • table cation tbody thead tfoot tr 表格的元素
  • ul ol li dt dd dl
  • form
  • p
  • div

行內元素html

  • a
  • b em i 廢棄標籤
  • code
  • label
  • span
  • th td

行內塊級元素前端

  • img
  • input
  • textarea

h5java

  • header
  • footer
  • nav
  • article
  • aside
  • datalist
  • section
  • video
  • audio

2 CSS

2.1 @import 和 link的區別

  • @import 引入的樣式會面頁面加載完成後纔會加載,而link會和頁面同時加載
  • link是標籤,能夠經過DOM去操做,而@import不能夠

2.2 實現一個左側固定寬度200px,右邊自適應佈局

// html
<div class="left"></div>
<div class="right"></div>

第一種方法:浮動css3

.left {
    float: left;
    width: 200px;
    height: 500px;
    background: darkcyan;
}

.right {
    height: 500px;
    background: deepskyblue;
}

第二種方法:絕對定位git

body {
    position: relative;
}

.left {
    position: absolute;
    left: 0;
    top: 0;
    width: 200px;
    height: 500px;
    background: darkcyan;
}

.right {
    height: 500px;
    background: deepskyblue;
}

第三種方法:flexes6

.parent {
    display: flex;
}

.left {
    width: 200px;
    height: 500px;
    background: darkcyan;
}

.right {
    height: 500px;
    background: deepskyblue;
    flex-grow: 1;
}

2.3 less定義一個圓角函數

.radius(@r:50%) {
    -webkit-border-radius: @r;
    -moz-border-radius: @r;
    border-radius: @r;
}

2.4 w3c標準盒模型佔位寬度是如何計算的? 它與IE盒模型有什麼不一樣?

IE67的混雜模式,寬度是算上了border + paddingweb

width = border-left + padding-left + con_width + padding-right + border-right

標準盒模型是分開來計算的面試

2.5 box-sizing的屬性值content-box 和 border-box的計算方式?

content-box 是w3c標準盒模型,其中的margin border padding width都是分別計算的,其中的width屬性是隻針對content的寬度。而border-box是IE67的混雜模型的盒模型計算方式,其中的width屬性是盒模型的border + padding + content

2.6 常見移動端適配不一樣屏幕

  • REM佈局
  • 流式佈局
  • flex佈局

2.7 引入css的方式

  • 行內式
  • 內嵌式
  • 外鏈式,使用link標籤
  • 使用@import引入css

2.8 寫出position的屬性值

  • static
  • relative
  • absolute
  • fixed

2.9 用box-shadow 寫出單邊上陰影效果(陰影半徑與模糊半徑不限)

div {
    -webkit-box-shadow: inset 5px 0 3px deepskyblue;
    -moz-box-shadow: inset 5px 0 3px deepskyblue;
    box-shadow: inset 5px 0 3px deepskyblue;
}

box-shadow: inset h v blur spreed color
內陰影 豎直 水平 模糊 半徑 顏色

2.10 常見清除浮動的方式

  • 給父級指定高度
  • 父級最後加空元素
  • 父級overflow: hidden
  • 父級也一塊兒浮動

2.11 css3新增特性

  • border-radius
  • text-shadow
  • box-shadow
  • linear-gradient
  • box-sizing
  • word-warp
  • column-count
  • display: box

2.12 a標籤僞類的順序

link -> visited -> hover -> active
緣由以下:link和visited是常態,hover和active是即時狀態,即時狀態想要覆蓋常態就必需要放到後面,不然無效。
一樣,在常態裏,visited是訪問後的狀態,想要覆蓋未訪問狀態就要寫到其後面;
即時態裏,active想要覆蓋hover就要寫到後面

2.13 樣式權重的排序

  • !import 1000
  • id 100
  • class 10
  • tag 1

2.14 display有哪些屬性值,有什麼做用

  • none:元素不會顯示,並且改元素現實的空間也不會保留
  • inline: 將元素顯示爲內聯元素,元素先後沒有換行符
  • block:將元素顯示爲塊級元素,元素先後會帶有換行符
  • inline-block:行內塊級元素
  • list-item:此元素會做爲列表顯示
  • table:此元素會做爲塊級表格來顯示,表格先後帶有換行符
  • inherit:規定從父元素繼承display屬性的值
  • box:彈性盒模型,c3新增

2.15 Flex

2.15.1 做用在父元素上的屬性

  • display: flex
    設置這個屬性後就會成爲flex怪異盒模型

  • flex-direction
    設置flex主軸的方向,屬性值有:row/row-reverse/colum/colum-reverse

  • flex-wrap
    設置換行的方式,屬性值有:nowrap/wrap/wrap-reverse

  • justify-content
    設置項目在主軸上的排列方式:屬性值有
  1. flex-start
  2. flex-end
  3. center
  4. space-between 兩端對齊,中間均分
  5. space-around 兩側有間隙,這個間隙是項目之間間隙的一半
  • align-items
    項目在交叉軸上的對齊方式:屬性值有
  1. flex-start
  2. flex-end
  3. center
  4. baseline
  5. stretch 默認值,佔滿空間
  • align-content多根軸的對齊方式,若是隻有一根軸就不生效

2.15.2 做用在項目上的屬性

  • order 數值越小越靠前,默認爲0
  • flex-grow 放大比例,如何去分配默認空間,0不放大,1均分,若是按其餘比例,能夠單獨給項目設置
  • flex-shrink 縮小比例,0不縮小,1等比例縮小,默認值是1

複合寫法是flex

  • align-self 單獨設置對齊方式

3 JavaScript

3.1 AJAX

相關知識點:

  • 跨域(80%以上會問到)
  • fetch(替代xhr對象的東西)
  • socket

3.1.1 JSONP

跨域是瀏覽器的行爲
跨域須要服務端的配合,若是不能修改服務端,能夠本身後臺轉發一下請求,畢竟後臺請求是沒有跨域限制的

跨域的方式有幾種,面試官要是問跨域的方式的話,通常就是在問JSONP。和麪試官講請JSONP的原理也算一點加分項。

相關知識點:

  • 瀏覽器的同源,協議、域名和端口號
  • script標籤的src屬性沒有跨域的限制
  • 須要服務端配合,前端須要給後臺傳回調名稱

總而言之,就是使用script標籤把數據請求回來。

通常印象中,script標籤就是外鏈一段js代碼。如今寫一個服務,當瀏覽器訪問/js時,就send('alert("js")'),發送一段js代碼。如今看是否會執行
Alt text

Alt text

Alt text

能夠看到js代碼正常執行了。這個就等於直接往全局做用域裏直接寫了一行alert('js')

這個時候咱們再返回一個JSON串回去
Alt text
能夠看到,直接報錯了。這個就比如,直接往全局做用域裏直接赤裸裸的扔了一個對象,沒有任務操做。

假如咱們在全局做用域裏已經定義好了一個函數

function handle(data) {
    console.log(data);
}

若是用script標籤請求回來的數據,能直接用這個函數處理多好。因此後臺給咱們處理的時候

res.send('handle({name: "chang"})')

這個返回的數據和上面同樣,也至關於直接在全局做用域裏寫了個

handle({name: "chang"});

這個時候咱們早已經定義好了處理函數,那麼這個函數就能夠直接處理數據了

因此無論哪一個工具封裝的JSONP都是這個操做,也就是爲何要和後臺定義回調函數的名稱,由於後臺不知道你在JS定義什麼名稱的函數來處理數據,通常這個回調函數名稱是須要放在queryString中的。後臺須要截取,再拼接

如下就是簡單的JSONP代碼

function xxxx(content) {
    console.log(content);
}
let script = document.createElement('script');
script.src = 'http://127.0.0.1:8000?cb=xxxx';
document.body.appendChild(script);

因此綜上,jsonp只能是get請求

3.1.2 fetch

fetch是以前瀏覽器的xhr對象的替代方案,如今使用的話,有瀏覽器兼容問題,畢竟有些瀏覽器是不支持的,可使用whatwg-fetch這個包來解決一下。

和原生的xhr同樣,都不會直接使用原生,而是使用封裝好的庫。

和原生的xhr相比,優勢:

  • 使用promise
  • 進而可使用async/await,寫的就像同步代碼同樣爽
try {
  let response = await fetch(url);
  let data = await response.json();
  console.log(data);
} catch(e) {
  console.log("error:", e);
}

使用的坑:

  • 默認請求是不帶cookie的,須要設置
    • fetch(url, {credentials: 'same-origin'})同域下發送cookie
    • fetch(url, {credentials: 'include'})跨域下發送cookie
  • 服務返回的400和500錯誤,是不會觸發reject的,只有網絡錯誤致使請求不能完成時,fetch纔會觸發reject

3.1.3 socket

一種先後臺通訊的方案,後臺能夠主動給前臺推送消息,而取代以前的短輪循和長輪循

3.2 JS輸出問題

3.2.1 對JS異步的理解

說出下面數字的輸出順序:

console.time('setTimeout');
console.time('setImmediate');

setImmediate(() => {
    console.log(1);
    console.timeEnd('setImmediate');
});
setTimeout(() => {
    console.log(2);
    console.timeEnd('setTimeout');
}, 0);

process.nextTick(() => console.log(3));

new Promise(function(resolve){
    console.log(4);
    resolve();
    console.log(5);
}).then(function(){
    console.log(6);
});

(() => console.log(7))();

答案:

4 5 7 3 6 2 1

解析:同步代碼先順序執行,而後是本輪循環的異步任務和次輪循環的異步任務。
process.nextTickPromise就屬於本輪循環的,並且process.nextTick最早執行
其餘兩個屬性次輪循環的異步任務,在setTimeout的延遲時間爲4ms及如下時,setTimeout會先執行

3.2.2 JS的逗號語句

var k;
for (var i = 0, j = 0; i < 7, j < 10; i++, j++) {
    k = i + j;
}
console.log(k);

var l;
for (var i = 0, j = 0; i < 10, j < 7; i++, j++) {
    l = i + j;
}
console.log(l);

3.2.3 alert()

alert的時候會自動調用toString()方法

alert([1, 3]); // -> 1, 3
alert({name: 'chang'}); // -> [object Object]

3.2.4 異步

for (var i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000*i);
}

結果是連續輸出5個5。setTimeout執行時,i已是5了,所有輸出5很正常,如今的問題是時間間隔是多少。正確的姿式是,間隔時間是不相同的。(實驗得知)

3.2.5 一些和預解釋相關的東西

var obj = {name: 'Joo', age: 30};
~function (n) {
    console.log(n);
    n.name = '中國';
    n = {};
    n.age = 5000;
    console.log(n);
}(obj);
console.log(obj);// {name: 'Joo', age: 30}


// 形參 形式上的一個表明值
// 解耦
function add(a, b) {
    console.log(arguments.callee.caller);
}

// 實參 實際傳入的參數
function a() {
    add(1, 4);
}
a();

3.3 數組

3.3.1 數組的方法

方法 參數 返回值 是否影響原數組 發佈版本
push length y
pop item y
shift item y
unshift length y
splice
slice
concat
sort
toString
join
reverse
indexOf/lastIndexOf
forEach
every
some
filter
map
reduce/reduceRight
find/findIndex
includes
fill
entries/keys
Array.from
Array.of

3.3.2 多維數組轉一維數組

第一種方法:使用遞歸

var arr = [1, 2, [3, 4, [5, 6], 7], 8, [9, 10, [11]], 12];
var spreadArr = [];

function spread(arr) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] instanceof Array) {
            spread(arr[i]);
        } else {
            spreadArr.push(arr[i]);
        }
    }
}

spread(arr);
console.log(spreadArr);

3.3.3 數組相關的算法

  • 冒泡排序
  • 快速排序
  • 插入排序
  • 去重
function bubbleSort(arr) {
    let isCompleted = true;
    for (let i = 0; i < arr.length - 1; i++) {
        for (let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
                isCompleted = false;
            }
        }
        if (isCompleted) {
            console.log('提早完成');
            return arr;
        } else {
            isCompleted = true;
        }
    }
    isCompleted = null;
    return arr;
}
function insertSort(arr) {
    let newArr = [arr[0]];
    for (let i = 1; i < arr.length; i++) {
        let cur = arr[i];
        for (let j = 0; j < newArr.length;) {
            if (cur > newArr[j]) {
                j++;
                if (j === newArr.length) {
                    newArr.push(cur);
                    break;
                }
            } else {
                newArr.splice(j, 0, cur);
                break;
            }
        }
    }
    return newArr;
}
function quickSort(arr) {
    if (arr.length <= 1) {
        return arr;
    }
    let midIndex = Math.ceil(arr.length / 2);
    let midVal = arr.splice(midIndex, 1)[0];
    let left = [], right = [];
    for (let i = 0; i < arr.length; i++) {
        let cur = arr[i];
        cur < midVal ? left.push(cur) : right.push(cur);
    }
    return quickSort(left).concat(midVal, quickSort(right));
}
function unique2(arr) {
    let obj = {};
    for (let i = 0; i < arr.length; i++) {
        let cur = arr[i];
        if (obj[cur] === cur) {
            arr.splice(i, 1);
            i--;
        } else {
            obj[cur] = cur;
        }
    }
    return arr;
}

3.4 繼承

3.4.1 原型式繼承

function A(name) {
    this.name = name;
    this.sex = 1;
}

A.prototype.say = function () {
    console.log('hello world');
};

function B(age) {
    this.age = age;
}

let a = new A();

B.prototype = a;

let b = new B(18);

console.log(b);//{ age: 18 }
console.log(b.name, b.sex);//undefined 1
b.say();//hello world


/*
 * 原型鏈繼承:子類的原型指定父類的實例
 *
 * extend:繼承了父類的私有和公有屬性,在此處name和sex是私有屬性,say是公有屬性
 * - 私有屬性是從父類的實例上獲得的
 * - 公的屬性是沿着做用域鏈b.__proto__ --> a (沒有) --> a.__proto__ --> A.prototype (保存在此處)
 *
 * 原型鏈繼承的問題:
 * - 繼承父類的私有屬性時,沒法向父類型中傳參,因此在輸出b.name的時候是undefined
 * - 在繼承引用數據類型的值時,就會有問題,請看下例
 * */

function SuperType() {
    this.color = ['red', 'blue', 'yellow'];
}

function SubType() {

}

SubType.prototype = new SuperType();

let instance1 = new SubType();
let instance2 = new SubType();

instance1.color.push('black');
console.log(instance2.color);//[ 'red', 'blue', 'yellow', 'black' ]

//修改了instance1的屬性的時候instance2的屬性也會跟着變化,由於這個屬性都是來自於它們的原型

3.4.2 call繼承

function SuperType(age) {
    this.age = age;
}

SuperType.prototype.say = function () {
    console.log('hello world');
};

function SubType(age) {
    SuperType.call(this, age);
}

let sub = new SubType(18);

console.log(sub);//SubType { age: 18 }
console.log(sub.say);//undefined

/*
 * call繼承:讓父類的構造函數在子類的構造函數裏執行,並使用call改變裏面的this
 *
 * extend:由於只是讓父類的構造函數在子類裏執行,因此只繼承了私有屬性。
 *
 * 優勢:和原型鏈繼承相比,解決了沒法傳參的問題,這個參數能夠寫在call的第二個參數位置
 *
 * 缺點:
 * - 由於只有私有屬性繼承,定義在父類原型上的方法對子類的實例都是不可見的
 * */

3.4.3 組合繼承

function SuperType() {
    this.name = 'chang';
}

SuperType.prototype.say = function () {
    console.log('hello');
};

function SubType() {
    SuperType.call(this);
}

SubType.prototype = new SuperType();

let sub = new SubType();

console.log(sub);//{ name: 'chang' }
sub.say();//hello

/*
 * 組合式繼承:將原型繼承和call繼承組合使用
 *
 * extend:使用call繼承私有屬性,使用原型鏈繼承繼承公有屬性
 *
 * 優勢:解決了原型繼承和call繼承的問題
 *
 * 缺點:父類的構造函數調用了兩次
 *
 * */

3.4.4 原型式繼承

/*
 * 這種方法並無使用嚴格意義上的構造函數,藉助原型能夠基於已有的對象創新新的對象,同時還沒必要建立自定義的類型
 * */

function object(o) {
    function F() {
    }

    F.prototype = o;
    return new F();
}

let obj1 = {name: 'chang', friend: ['a', 'b', 'c']};

let obj2 = object(obj1);

console.log(obj2.__proto__);//{ name: 'chang', friend: [ 'a', 'b', 'c' ] }

/*
 * 在es5中規範了這個繼承的方法:Object.create(),這個方法接收兩個參數,一個用做新對象原型的對象和(可選的)一個爲新對象定義額外屬性的對象
 * */

let obj3 = Object.create(obj1);

console.log(obj3.__proto__);//{ name: 'chang', friend: [ 'a', 'b', 'c' ] }

//添加額外屬性時,必須使用這種格式
let obj4 = Object.create(obj1, {
    like: {
        value: 'code'
    }
});

console.log(obj4.like);//code

3.4.5 __proto__

function SuperType() {
    this.name = 'chang';
}

SuperType.prototype.say = function () {
    console.log('ok');
};

function SubType() {

}

SubType.prototype.__proto__ = SuperType.prototype;

let sub = new SubType();

console.log(sub.name);//undefined
sub.say();//ok

/*
 * 不知道名字的繼承:改變子類的原型的__proto__,指向父類的原型
 * 只繼承公有
 * */

3.4.6 setProtoOf

/*
 * Object.setPrototypeOf方法的做用與__proto__相同,用來設置一個對象的prototype對象,返回參數對象自己。它是 ES6 正式推薦的設置原型對象的方法。
 *
 *
 * */

let obj1 = {name: 'chang'};
let obj2 = {};
Object.setPrototypeOf(obj2, obj1);
console.log(obj2.__proto__ === obj1);

3.5 其餘

3.5.1 兩個頁面的通信方式

  • url
  • localStorage
  • cookie

3.5.2 統計頁面中類名的個數

var os = document.getElementsByTagName('*');
var cObj = {};
var max = 0;
function sta(cName) {
    var cNameArr = cName.split(/ +/);
    for (var i = 0; i < cNameArr.length; i++) {
        var cur = cNameArr[i];
        if (cObj[cur]) {
            cObj[cur]++;
        } else {
            cObj[cur] = 1;
        }
    }
}
for (var i = 0; i < os.length; i++) {
    if (os[i].className) {
        sta(os[i].className);
    }
}

for (var attr in cObj) {
    if (cObj.hasOwnProperty(attr)) {
        if (cObj[attr] > max) {
            max = cObj[attr];
        }
    }
}
console.log(max);

3.6 ES6 +

  • let/const
  • 解構賦值
  • 字符串
    • 模板字符串
    • includes/startsWith/endsWith
    • repeat
  • 函數
    • 箭頭函數
    • 參數默認值
    • 剩餘參數
    • 雙冒號
  • 數組
    • 擴展運算符
    • entries/keys/values
    • Array.from將類數組轉化成數組
    • Array.of將一級值轉成數組
    • includes
  • 對象的擴展
    • 簡潔表達形式
    • 屬性表達式
    • 函數的name
    • Object.assign合併對象,淺拷貝
    • Object.keys()/Object.values()/Object.entries()
    • 擴展運算符
    • 解構
  • Symbol第6種基本數據類型的值 let s = Symbol() // 不須要new
  • Set 可用於數組去重
var arr = [1, 1, 1, 1];
var s = new Set(arr);
var newArr = [...s];
  • MapObject相比,key值能夠是任何值
  • proxy作目標對象的讀寫操做的攔截
  • Promise
  • async/await
  • Class/extends
  • Module

4 代碼管理工具

4.1 GIT

經常使用命令(結合本身經常使用)

4.1.1 提交4部曲

  • git add
  • git commit
  • git pull
  • git push在多人協做開發的時候,若是不pull是絕對push不上去的

4.1.2 查看提交記錄

  • git log
    若是想查看簡單點就是
  • git log --pretty=oneline
    想看是某我的的提交歷史
  • git log --author=changzhn
    想查看某個文件的提交歷史
  • git log -- filename
    想在芒芒提交中搜索本身印象關鍵字
  • git log --grep=xxx
    終於找到那個提交的記錄了,想看看提交了啥子內容,提交的ID截取前幾位就能夠了
  • git show hash

4.1.3 分支管理

查看當前的分支

  • git branch
    新建個分支而且切換過去
  • git checkout -b develop
    切換分支
  • git checkout develop/release/master
    注意:切換分支的時候,在當前分支修改的內容也是帶過去,這一點很噁心,因此切換分支前,先使用下面這個命令,來看當前分支的狀態
  • git status
    若是有修改(紅色)或者添加(綠色)的內容,就要使用提交4部曲的addcommit來產生版本號後,才能切換分支
    或者,使用下面這個命令,將這個分支上的全部修改放入一個異次元...
  • git stash
    再切換回來想恢復修改的時候可使用
  • git stash list
    想看,往異次元中放入了幾回,若是隻想恢復最近的一次的話
  • git stash pop stash@{0}
    Alt text

好比切到release分支上想合併develop分支

  • git merge develop
    在合併的時候,很不幸運的是衝突了
    這個時候就須要解決衝突,在當前分支上,使用提交4部曲,爲此次解決衝突產生一個版本號

4.1.4 版本管理

找到版本號的時候想回退代碼

  • git reset --HARD hash
    好比如今將代碼推到過程,後來發現這真是一次垃圾的提交,在本地使用代碼回退上一個版本的時候,想再push上去,這個時候發現是推不上去的。
  • git push origin master -f
    可使用-f來暴力提交
相關文章
相關標籤/搜索