某大廠面試題與解析(歡迎糾錯,優化)

煙雨空靈發表於2018-11-07

簡答題

1.css3特性中的transform:translateZ(0)有什麼作用

答案: GPU加速,優化前端效能


2.列舉三種禁止瀏覽器快取的頭欄位,並寫出響應的設定值

Expires:告訴瀏覽器把回送的資源快取多長時間 -1或0則是不快取 簡要:新增Expires頭能有效的利用瀏覽器的快取能力來改善頁面的效能,能在後續的頁面中有效避免很多不必要的Http請求,WEB伺服器使用Expires頭來告訴Web客戶端它可以使用一個元件的當前副本,直到指定的時間為止。 例如:Expires:Thu,15 Apr 2010 20:00:00 GMT; 他告訴瀏覽器快取有效性持續到2010年4月15日為止,在這個時間之內相同的請求使用快取,這個時間之外使用http請求。

Cache-Control:no-cache Cathe-Control:max-age=315360000

Expires有一個非常大的缺陷,它使用一個固定的時間,要求伺服器與客戶端的時鐘保持嚴格的同步,並且這一天到來後,伺服器還得重新設定新的時間。 HTTP1.1引入了Cathe-Control,它使用max-age指定元件被快取多久,從請求開始在max-age時間內瀏覽器使用快取,之外的使用請求,這樣就可以消除Expires的限制, 如果對瀏覽器相容性要求很高的話,可以兩個都使用。

Pragma:no-cache


3.精確獲取頁面元素位置的方式有哪些

那就是使用getBoundingClientRect()方法。它返回一個物件,其中包含了left、right、top、bottom四個屬性,分別對應了該元素的左上角和右下角相對於瀏覽器視窗(viewport)左上角的距離。

var X= this.getBoundingClientRect().left;
var Y =this.getBoundingClientRect().top;
//再加上滾動距離,就可以得到絕對位置
var X= this.getBoundingClientRect().left+document.documentElement.scrollLeft;
var Y =this.getBoundingClientRect().top+document.documentElement.scrollTop;
複製程式碼

4.正則從2018-10-07T11:48:47 Asia/zh-cn 提取出來結果[2018,10,07,11,48,47]

"2018-10-07T11:48:47 Asia/zh-cn".match( /\d{1,}/g )


5.如何判斷object是陣列型別?

alert(typeof 1);                // 返回字串"number" 
alert(typeof "1");              // 返回字串"string" 
alert(typeof true);             // 返回字串"boolean" 
alert(typeof {});               // 返回字串"object" 
alert(typeof []);               // 返回字串"object " 
alert(typeof function(){});     // 返回字串"function" 
alert(typeof null);             // 返回字串"object" 
alert(typeof undefined);        // 返回字串"undefined"
複製程式碼

其中,typeof {}和typeof []的結果都是object,那麼問題來了,我怎麼通過typeof去判斷一個物件是不是陣列型別呢?

物件是物件,陣列也是物件,js中萬物皆物件,很顯然,通過簡單的typeof運算子是不能夠達到目的,我們得換個方法。

1、從原型入手,Array.prototype.isPrototypeOf(obj);

利用isPrototypeOf()方法,判定Array是不是在obj的原型鏈中,如果是,則返回true,否則false。

判斷object是陣列型別
2.Array.isArray()方法。

Array.isArray([1, 2, 3]);  // true
Array.isArray({foo: 123}); // false
Array.isArray('foobar');   // false
Array.isArray(undefined);  // false 
複製程式碼

程式設計題


1.已知資料結構users,請實現語法支援user.unique能夠按照name欄位去重,並輸出結構為:["a","b"]
var users=[{
   id:1,name:"a"
},{
   id:2,name:"a"
},{
   id:3,name:"b"
},{
   id:4,name:"v"
}]

複製程式碼
Array.prototype.unique = function () {
    var res;
    this.map(item => {
        this[item.id - 1] = item.name
    })
    // ES6裡新新增了兩個很好用的東西,set和Array.from
    // set是一種新的資料結構,它可以接收一個陣列或者是類陣列物件,自動去重其中的重複專案。
    res=new Set(this);
    console.log("new Set物件",res)
    // 但是這裡大家可以看到,set返回的是一個物件,但是我們想要的是陣列啊。
    // 這回,就該輪到Array.from出場了,它的作用,就是可以把類陣列物件、可迭代物件轉化為陣列。
    res=Array.from(new Set(this));
    return  res//es6 陣列去重
}
console.log(users.unique());
複製程式碼

去重


2.已知如下物件,請基於es6的proxy方法設計一個屬性攔截讀取操作的例子,要求實現去訪問目標物件example中不存在的屬性時,丟擲錯誤:Property "$(property)" does not exist
const man={
    name:'jscoder',
    age:22
}
 //補全程式碼
const proxy = new Proxy(...)
proxy.name //"jscoder"
proxy.age //22
proxy.location //Property "$(property)" does not exist
複製程式碼

考點 es6 javascript的Proxy 例項的方法 ,get() get方法用於攔截某個屬性的讀取操作。

var man = {
	name:'jscoder',
    age:22
};
var proxy = new Proxy(man, {
	get: function(target, property) {
		if(property in target) {
			return target[property];
		} else {
			throw new ReferenceError(`Property ${property} does not exist.`);
		}
	}
});
console.log(proxy.name)
console.log(proxy.age)
console.log(proxy.location)
複製程式碼

Proxy 例項的方法的其他方法參考這個連結,很詳細 blog.csdn.net/qq_30100043…


3.給出如下虛擬dom的資料結構,如何實現簡單的虛擬dom,渲染到目標dom樹
//樣例資料
let demoNode = ({
    tagName: 'ul',
    props: {'class': 'list'},
    children: [
        ({tagName: 'li', children: ['douyin']}),
        ({tagName: 'li', children: ['toutiao']})
    ]
});
複製程式碼

//構建一個render函式,將demoNode物件渲染為以下dom

<ul class="list">
    <li>douyin</li>
    <li>toutiao</li>
</ul>
複製程式碼

看到虛擬DOM,是不是感覺很玄乎,但是剝開它華麗的外衣,也就那樣:

  1. 通過JavaScript來構建虛擬的DOM樹結構,並將其呈現到頁面中;
  2. 當資料改變,引起DOM樹結構發生改變,從而生成一顆新的虛擬DOM樹,將其與之前的DOM對比,將變化部分應用到真實的DOM樹中,即頁面中。 通過上面的介紹,下面,我們就來實現一個簡單的虛擬DOM,並將其與真實的DOM關聯。

構建虛擬DOM

虛擬DOM,其實就是用JavaScript物件來構建DOM樹,如上ul元件模版,其樹形結構如下:

DOM樹
通過JavaScript,我們可以很容易構建它,如下:

var elem = Element({
    tagName: 'ul',
    props: {'class': 'list'},
    children: [
        Element({tagName: 'li', children: ['item1']}),
        Element({tagName: 'li', children: ['item2']})
    ]
});
複製程式碼

note:Element為一個建構函式,返回一個Element物件。為了更清晰的呈現虛擬DOM結構,我們省略了new,而在Element中實現。

/*
* @Params:
*     tagName(string)(requered)
*     props(object)(optional)
*     children(array)(optional)
* */
function Element({tagName, props, children}){
    if(!(this instanceof Element)){
        return new Element({tagName, props, children})
    }
    this.tagName = tagName;
    this.props = props || {};
    this.children = children || [];
}
複製程式碼

好了,通過Element我們可以任意地構建虛擬DOM樹了。但是有個問題,虛擬的終歸是虛擬的,我們得將其呈現到頁面中,不然,沒鳥用。。

怎麼呈現呢?

從上面得知,這是一顆樹嘛,那我們就通過遍歷,逐個節點地建立真實DOM節點:

  1. createElement;

  2. createTextNode.

怎麼遍歷呢?

因為這是一顆樹嘛,對於樹形結構無外乎兩種遍歷:

  1. 深度優先遍歷(DFS)

深度優先遍歷

  2. 廣度優先遍歷(BFS)

廣度優先遍歷

針對實際情況,我們得采用DFS,為什麼呢?

因為我們得將子節點append到父節點中

好了,那我們採用DFS,就來實現一個render函式吧,如下:

Element.prototype.render = function(){
    var el = document.createElement(this.tagName),
        props = this.props,
        propName,
        propValue;
    for(propName in props){
        propValue = props[propName];
        el.setAttribute(propName, propValue);
    }
    this.children.forEach(function(child){
        var childEl = null;
        if(child instanceof Element){
            childEl = child.render();
        }else{
            childEl = document.createTextNode(child);
        }
        el.appendChild(childEl);
    });
    return el;
};
複製程式碼

此時,我們就可以輕鬆地將虛擬DOM呈現到指定真實DOM中啦。假設,我們將上訴ul虛擬DOM呈現到頁面body中,如下:

var elem = Element({
    tagName: 'ul',
    props: {'class': 'list'},
    children: [
        Element({tagName: 'li', children: ['item1']}),
        Element({tagName: 'li', children: ['item2']})
    ]
});
document.querySelector('body').appendChild(elem.render());
複製程式碼

歡迎關注前端公眾號,每日訂閱前端知識

公眾號

相關文章