封裝一個函數,參數是定時器的時間,.then執行回調函數。javascript
function sleep (time) { return new Promise((resolve) => setTimeout(resolve, time)); }
怎麼判斷兩個對象相等?
一、轉化成字符串後比較字符串是否一致:php
JSON.stringify(obj)===JSON.stringify(obj2);
二、Object.is(obj1,obj2):判斷兩個值是否 [相同]。若是下列任何一項成立,則兩個值相同。css
* 兩個值都是 [undefined] * 兩個值都是 [null] * 兩個值都是true或者都是false * 兩個值是由相同個數的字符按照相同的順序組成的字符串 * ~兩個值指向同一個對象~ * 兩個值都是數字而且 * 都是正零+0 * 都是負零-0 * 都是 [NaN] * 都是除零和[NaN]外的其它同一個數字
實現mvvm主要包含兩個方面,數據變化更新視圖,視圖變化更新數據:html
關鍵點在於data如何更新view,由於view更新data其實能夠經過事件監聽便可,好比input標籤監聽 'input' 事件就能夠實現了。因此咱們着重來分析下,當數據改變,如何更新視圖的。
數據更新視圖的重點是如何知道數據變了,只要知道數據變了,那麼接下去的事都好處理。如何知道數據變了,其實上文咱們已經給出答案了,就是經過Object.defineProperty( )對屬性設置一個set函數,當數據改變了就會來觸發這個函數,因此咱們只要將一些須要更新的方法放在這裏面就能夠實現data更新view了。前端
Vue是經過Object.defineProperty()來實現數據劫持的。它能夠來控制一個對象屬性的一些特有操做,好比set()、get()、是否能夠枚舉。
實現數據的雙向綁定,首先要對數據進行劫持監聽,因此咱們須要設置一個監聽器Observer,用來監聽全部屬性。若是屬性發上變化了,就須要告訴訂閱者Watcher看是否須要更新。由於訂閱者是有不少個,因此咱們須要有一個消息訂閱器Dep來專門收集這些訂閱者,而後在監聽器Observer和訂閱者Watcher之間進行統一管理的。接着,咱們還須要有一個指令解析器Compile,對每一個節點元素進行掃描和解析,將相關指令對應初始化成一個訂閱者Watcher,並替換模板數據或者綁定相應的函數,此時當訂閱者Watcher接收到相應屬性的變化,就會執行對應的更新函數,從而更新視圖。所以接下去咱們執行如下3個步驟,實現數據的雙向綁定:
1.實現一個監聽器Observer,用來劫持並監聽全部屬性,若是有變更的,就通知訂閱者。
2.實現一個訂閱者Watcher,能夠收到屬性的變化通知並執行相應的函數,從而更新視圖。
3.實現一個解析器Compile,能夠掃描和解析每一個節點的相關指令,並根據初始化模板數據以及初始化相應的訂閱器。java
流程圖以下:面試
瀏覽器兼容性問題
圖片描述
一、Normalize.css
二、不一樣瀏覽器的標籤默認的外邊距和內邊距不一樣:
三、IE6雙邊距問題:在 IE6中設置了float , 同時又設置margin , 就會出現邊距問題:設置display:inline;
四、圖片默認有間距:使用float 爲img 佈局
五、IE9如下瀏覽器不能使用opacity:ajax
opacity: 0.5; filter: alpha(opacity = 50); filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50);
六、cursor:hand 顯示手型在safari 上不支持:統一使用 cursor:pointer
七、當標籤的高度設置小於10px,在IE六、IE7中會超出本身設置的高度:超出高度的標籤設置overflow:hidden,或者設置line-height的值小於你的設置高度
八、CSS HACK的方法:json
height: 100px; // 全部瀏覽器 通用 _height: 100px; // IE6 專用 *+height: 100px; // IE7 專用 *height: 100px; // IE六、IE7 共用 height: 100px !important; // IE七、FF 共用
代碼的順序必定不能顛倒了,要不又前功盡棄了。由於瀏覽器在解釋程序的時候,若是重名的話,會用後面的覆蓋前面的,就象給變量賦值一個道理,因此咱們把通用的放前面,越專用的越放後面segmentfault
前端跨域
什麼是跨域?
> 只要協議、域名、端口有任何一個不一樣,都被看成是不一樣的域。 > 同源策略是瀏覽器的行爲,是爲了保護本地數據不被JavaScript代碼獲取回來的數據污染,所以攔截的是客戶端發出的請求回來的數據接收,即請求發送了,服務器響應了,可是沒法被瀏覽器接收。 > 之因此會跨域,是由於受到了同源策略的限制,同源策略要求源相同才能正常進行通訊,即協議、域名、端口號都徹底一致。 > > 注意點: > 若是是協議和端口形成的跨域問題「前臺」是無能爲力的; > 在跨域問題上,域僅僅是經過「URL的首部」來識別而不會去嘗試判斷相同的ip地址對應着兩個域或兩個域是否在同一個ip上。 (「URL的首部」指window.location.protocol +window.location.host,也能夠理解爲「Domains, protocols and ports must match」。)
什麼是同源策略?
> 所謂同源是指,域名,協議,端口相同。瀏覽器採用同源策略,就是禁止頁面加載或執行與自身來源不一樣的域的任何腳本。
經過document.domain跨域(只適用於不一樣子域的框架間的交互)
瀏覽器有一個同源策略,其限制之一是不能經過ajax的方法去請求不一樣源中的文檔。第二個限制是瀏覽器中不一樣域的框架之間是不能進行js的交互操做的。不一樣的框架之間是能夠獲取window對象的,但卻沒法獲取相應的屬性和方法。好比,有一個頁面,它的地址是 [www.damonare.cn/a.html], 在這個頁面裏面有一個iframe,它的src是 [damonare.cn/b.html], 很顯然,這個頁面與它裏面的iframe框架是不一樣域的,因此咱們是沒法經過在頁面中書寫js代碼來獲取iframe中的東西的:
經過jsonp跨域
JSONP的優缺點 * JSONP的優勢是:它不像XMLHttpRequest對象實現的Ajax請求那樣受到同源策略的限制;它的兼容性更好,在更加古老的瀏覽器中均可以運行,不須要XMLHttpRequest或ActiveX的支持;而且在請求完畢後能夠經過調用callback的方式回傳結果。 * JSONP的缺點則是:它只支持GET請求而不支持POST等其它類型的HTTP請求;它只支持跨域HTTP請求這種狀況,不能解決不一樣域的兩個頁面之間如何進行JavaScript調用的問題。
經過CORS跨域
CORS(Cross-Origin Resource Sharing)跨域資源共享,定義了必須在訪問跨域資源時,瀏覽器與服務器應該如何溝通。CORS背後的基本思想就是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功仍是失敗。目前,全部瀏覽器都支持該功能,IE瀏覽器不能低於IE10。整個CORS通訊過程,都是瀏覽器自動完成,不須要用戶參與。對於開發者來講,CORS通訊與同源的AJAX通訊沒有差異,代碼徹底同樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感受。
經過window.name跨域
window對象有個name屬性,該屬性有個特徵:即在一個窗口(window)的生命週期內,窗口載入的全部的頁面都是共享一個window.name的,每一個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的全部頁面中的,並不會因新頁面的載入而進行重置。
前端優化:瀏覽器緩存
前端優化:瀏覽器緩存技術介紹 - 掘金
瀏覽器緩存分爲強緩存和協商緩存。
當客戶端請求某個資源時,獲取緩存的流程以下:
1)瀏覽器在加載資源時,先根據這個資源的一些http header判斷它是否命中強緩存,強緩存若是命中,瀏覽器直接從本身的緩存中讀取資源,不會發請求到服務器。好比:某個css文件,若是瀏覽器在加載它所在的網頁時,這個css文件的緩存配置命中了強緩存,瀏覽器就直接從緩存中加載這個css,連請求都不會發送到網頁所在服務器;2)當強緩存沒有命中的時候,瀏覽器必定會發送一個請求到服務器,經過服務器端依據資源的另一些http header驗證這個資源是否命中協商緩存,若是協商緩存命中,服務器會將這個請求返回,可是不會返回這個資源的數據,而是告訴客戶端能夠直接從緩存中加載這個資源,因而瀏覽器就又會從本身的緩存中去加載這個資源;
3)強緩存與協商緩存的共同點是:若是命中,都是從客戶端緩存中加載資源,而不是從服務器加載資源數據;區別是:強緩存不發請求到服務器,協商緩存會發請求到服務器。
4)當協商緩存也沒有命中的時候,瀏覽器直接從服務器加載資源數據。
jsonp的原理與實現
Jsonp是一種跨域通訊的手段,它的原理其實很簡單:
> 1. 首先是利用script標籤的src屬性來實現跨域。 > 2. 經過將前端方法做爲參數傳遞到服務器端,而後由服務器端注入參數以後再返回,實現服務器端向客戶端通訊。 > 3. 因爲使用script標籤的src屬性,所以只支持get方法
實現流程:
一、設定一個script標籤
<script src="http://jsonp.js?callback=xxx"></script>
二、callback定義了一個函數名,而遠程服務端經過調用指定的函數並傳入參數來實現傳遞參數,將function(response)傳遞迴客戶端
$callback = !empty($_GET['callback']) ? $_GET['callback'] : 'callback'; echo $callback.'(.json_encode($data).)';
三、客戶端接收到返回的js腳本,開始解析和執行function(response)
簡單的實例:
一個簡單的jsonp實現,其實就是拼接url,而後將動態添加一個script元素到頭部。
function jsonp(req){ var script = document.createElement('script'); var url = req.url + '?callback=' + req.callback.name; script.src = url; document.getElementsByTagName('head')[0].appendChild(script); }
前端js示例:
function hello(res){ alert('hello ' + res.data); } jsonp({ url : '', callback : hello });
服務器端代碼:
var http = require('http'); var urllib = require('url'); var port = 8080; var data = {'data':'world'}; http.createServer(function(req,res){ var params = urllib.parse(req.url,true); if(params.query.callback){ console.log(params.query.callback); //jsonp var str = params.query.callback + '(' + JSON.stringify(data) + ')'; res.end(str); } else { res.end(); } }).listen(port,function(){ console.log('jsonp server is on'); });
可靠的jsonp實例:
(function (global) { var id = 0, container = document.getElementsByTagName("head")[0]; function jsonp(options) { if(!options || !options.url) return; var scriptNode = document.createElement("script"), data = options.data || {}, url = options.url, callback = options.callback, fnName = "jsonp" + id++; // 添加回調函數 data["callback"] = fnName; // 拼接url var params = []; for (var key in data) { params.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key])); } url = url.indexOf("?") > 0 ? (url + "&") : (url + "?"); url += params.join("&"); scriptNode.src = url; // 傳遞的是一個匿名的回調函數,要執行的話,暴露爲一個全局方法 global[fnName] = function (ret) { callback && callback(ret); container.removeChild(scriptNode); delete global[fnName]; } // 出錯處理 scriptNode.onerror = function () { callback && callback({error:"error"}); container.removeChild(scriptNode); global[fnName] && delete global[fnName]; } scriptNode.type = "text/javascript"; container.appendChild(scriptNode) } global.jsonp = jsonp; })(this);
使用示例:
jsonp({ url : "www.example.com", data : {id : 1}, callback : function (ret) { console.log(ret); } });
歡迎閱讀:
2019年前端面試題-01
2019年前端面試題-02
2019年前端筆試題
我是Cloudy,年輕的前端攻城獅一枚,愛專研,愛技術,愛分享。
我的筆記,整理不易,感謝閱讀、點贊和收藏。
文章有任何問題歡迎你們指出,也歡迎你們一塊兒交流前端各類問題!