做爲junior developer,僅僅以爲這些問題常常在我面試的時候被問到,好記性不如爛筆頭,本身整理記錄一遍~~~javascript
1.javascript如何實現繼承? 三種方式: 1. 原型繼承 // 優勢:既繼承了父類的模板,又繼承了父類的原型對象 // 缺點:父類實例化傳參,而不是子類實例化傳參(不符合常規語言的寫法) function Parent(work, drink) { this.work = function() { console.log(work); } this.drink = drink; } Parent.prototype.draw = function() { alert("I can draw"); } function Child() { this.cry = function() { console.log("the best ability is to cry"); } } Child.prototype = new Parent('code', 'beer'); var xiaoLi = new Child(); xiaoLi.work(); // code xiaoLi.draw(); // I can draw xiaoLi.cry(); // the best ability is to cry 關於原型鏈的解釋:https://www.cnblogs.com/chengzp/p/prototype.html 2. 類繼承(借用構造函數的方式繼承) // 優勢:繼承了父類的模板,方便經過子類實例化傳參 // 缺點:不能繼承父類的原型對象 function Parent(work, drink) { this.work = function() { console.log(work); } this.drink = drink; } Parent.prototype.draw = function() { alert("I can draw"); } function Child(work, drink, sex) { Parent.call(this, work, drink); this.sex = sex; } var xiaoLi = new Child('code', 'beer', 'male'); alert(xiaoLi.drink); // code xiaoLi.work(); // beer // xiaoLi.draw(); //沒有繼承父類的原型對象,因此,會報錯:xiaoLi.draw() is not a function console.log(xiaoLi.sex); // male 3. 混合繼承(原型繼承和類繼承) // 混合繼承(原型繼承和類繼承(借用構造函數的方式繼承)) function Parent(eat, sleep) { this.eat = function() { console.log("function 1" + eat); } this.sleep = function() { console.log("function 2" + sleep); } } Parent.prototype.other = "work"; function Child(eat, sleep, age) { Parent.call(this, eat, sleep); this.age = age; } Child.prototype = new Parent(); var xiaoLi = new Child("cake", "want to sleep", "10"); xiaoLi.eat(); xiaoLi.sleep(); console.log(xiaoLi.age); console.log(xiaoLi.other);
2.原生ajax是如何實現的? 特色: 在不從新加載整個網頁的狀況下,對頁面局部進行刷新。 XMLHttpRequest對象是實現ajax的基礎,XMLHttpRequest有不少方法,經常使用的有open(),send()等 ajax請求共包含五個步驟: 1.建立XMLHttpRequest對象(一個異步調用對象) 2.設置HTTP請求的參數(請求方法,url,是否異步) 3.設置響應HTTP請求狀態變化的回調函數 4.發送HTTP請求 5.獲取異步調用返回的數據 6.局部更新頁面 var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) { fn.call(this, xhr.responseText); } }; xhr.send(data); post方法必定要用setRequestHeader("header","value");
3.做用域 塊級做用域:ES6才支持,在{}大括號內的就是塊級做用域 (塊級做用域的出現解決了:for循環定義的變量形成的全局污染;不用再經過閉包來保存必要的變量了) 函數做用域:在函數中實現的 全局做用域:在外部聲明的,若是沒有用var關鍵字聲明,在非嚴格模式下,也爲全局做用域 注意: 在es6以前沒有塊級做用域這個概念,因此在{}塊級做用域中聲明的變量其實就是全局變量(舉個栗子) for (var i = 1; i <= 10; i++) { console.log (i); // outputs 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; }; // The variable i is a global variable and it is accessible in the following function with the last value it was assigned above function aNumber () { console.log(i); } // The variable i in the aNumber function below is the global variable i that was changed in the for loop above. Its last value was 11, set just before the for loop exited: aNumber (); // 11 關於es6的let和const: let和const沒有變量聲明的提高; let和const不容許在相同做用域內重複聲明;
4.如何理解閉包? 比較經常使用的情景: 在A函數裏返回B函數,B函數能夠調用A函數的局部變量; 特色: 1.函數嵌套 2.函數內部能夠引用外部的參數和變量 3.閉包函數裏的參數和變量不會被垃圾回收機制回收(閉包會使變量始終保存在內存中,若是使用不當會增大內存消耗) 閉包的好處: 1.但願變量長期保存在內存中 2.避免全局變量的污染 3.私有變量的存在
5.回調函數 定義: 函數A做爲參數傳遞給函數B,在函數B中執行函數A,此時函數A就叫作回調函數。若是函數沒有名稱(函數表達式),就叫作匿名回調函數。 回調函數不必定用於異步,同步(阻塞)場景下也會用到回調函數。好比說要求在執行完某些操做後執行回調函數。 舉幾個栗子: 同步(阻塞)回調: fn1執行完後執行fn2 在同步場景下,回調函數最後執行 異步回調: ajax請求 在異步回調中,回調函數有可能不執行,由於時間沒有被觸發或者條件不知足 回調函數的應用場景: 動態加載js後,圖片加載完成後,ajax請求等 另外,最好保證回調存在且必須是函數引用或者函數表達式: (callback && typeof(callback) === "function") && callback();
6.es6經常使用新特性: 1.let和const(新的變量聲明方式,容許把變量做用域控制在塊級裏面) 2.解構賦值(對象和數組都適用) 3.promise 一個對象,用來表示並傳遞異步操做的最終結果 交互方式:將回調函數傳入then方法獲取最終結果或出錯緣由 以鏈式調用代替回調函數層層嵌套 //生成promise實例 var promise = new Promise(function(resolve, reject) { //...other code... if (/* 異步操做成功 */){ resolve(value);//resolve函數將Promise對象的狀態從Pending變爲Resolved } else { reject(error);//reject函數將Promise對象的狀態從Pending變爲Rejected } }); //Promise實例生成之後,用then方法分別指定Resolved狀態和Reject狀態的回調函數。 promise.then(function(value) { // success }, function(err) { // failure }); jQuery.ajax()方法中運用promise: var http = { get: function(url) { var promise = new Promise(function(resolve, reject) { $.ajax({ url: url, method: 'get', success: function(data) { resolve(data); }, error: function(xhr, statusText) { reject(statusText); } }); }); return promise; } }; http.get('data.php').then(function(data) { document.write(data); }, function(err) { document.write(err); }); 這裏是獲取的data值: /* data.php文件 */ <?php echo '{"name":"Tom","age":"22"}'; 4.箭頭函數(簡化函數的寫法、修復this的指向,箭頭函數裏this指向方法原來的做用域,即方法綁定在哪一個對象上,this就指向哪一個對象) 5.多行字符串 6.類(方法名再也不須要function關鍵字) 7.模板對象(${xxx}) 8.默認參數(把默認值放在函數聲明裏) 9.iterable類型(Map):具備iterable類型的集合均可以用for...of來循環遍歷 舉個栗子: var m = new Map(); m.set("name", "lysa");//添加新的key-value; Map對象對應不少的方法,如.set(),.has(),.delete() 10.modules(模塊): 舉個栗子: 在a.js中, export var aa="test"; export function bb(){ do something; } 在b.js中導入a.js的某個變量並引用:import {aa, bb} from 'a' console.log(aa); 在b.js中導入a.js整個文件並引用:import * as xxx from 'a' console.log(xxx.aa);
7.cookie和web storage的區別? 1.與服務器的交互上 cookie始終會在http同源請求頭上攜帶(即便不須要),在瀏覽器端和客戶端之間傳來傳去 localStorage和sessionStorage不會主動發送給服務器,僅保存在本地 2.儲存大小 cookie因爲不一樣瀏覽器的限制,大小在4KB左右 localStorage和sessionStorage儲存大小達5MB或以上 3.過時時間 cookie與設置的有效期時間有關 localStorage存儲持久數據,除非主動刪除 sessionStorage在瀏覽器關閉後自動刪除
8.cookie和session的區別? cookie數據存放在客戶的瀏覽器,session存儲在服務器上 考慮到安全性 建議: 將登錄等重要信息存放爲session 其它信息能夠放在cookie中
9.一個頁面從輸入url到頁面加載,這個過程都發生了什麼? 簡潔版: 1.瀏覽器根據請求的url向服務器發送請求 2.服務求處理完成後返回數據,瀏覽器接收文件 3.瀏覽器對加載到的資源(html, css, js, image等)進行語法解析 4.載入解析到的資源,渲染頁面
10.事件委派 優勢:減小事件註冊;簡化DOM更新時,相應事件的更新 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <ul id="lists"></ul> </body> <script> var oUl=document.getElementById("lists"); var fragment=document.createDocumentFragment(); for(i=0;i<10;i++){ var oLi=document.createElement("li"); oLi.innerHTML="this is an item"; oLi.index=i; fragment.appendChild(oLi); } oUl.appendChild(fragment); // oUl.onclick=function(ev){ // console.log("ev是:",ev) // var src=ev.target||ev.srcElement; // if(src.tagName==="LI"){ // console.log(src.index) // } // } oUl.addEventListener("click",function(ev){ var src=ev.target||ev.srcElement; if(src.tagName==="LI"){ console.log(src.index); } },false)//默認false,事件句柄在冒泡階段執行 </script> </html>
11.拖拽 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <style> body{margin:0;} .box{width:100px;height: 100px;background: red;position: relative;cursor: move;} </style> </head> <body> <div class="box"></div> <script> var oBox=document.getElementsByClassName("box")[0]; oBox.onmousedown=function(ev){ // 鼠標按下的狀態 var ev=ev||window.event;//兼容ie瀏覽器 // 元素的x座標和y座標 var l_dis=oBox.offsetLeft; var t_dis=oBox.offsetHeight; // 1.記錄下鼠標的x座標和y座標 // 2.計算鼠標離元素邊距的距離 var disX=ev.clientX-l_dis; var disY=ev.clientY-t_dis; var that=this; // 鼠標移動的狀態 document.documentElement.onmousemove=function(ev){ var ev=ev||window.event; // 這裏的ev.pageX值是否和ev.clientX值一致? // 計算元素如今的位置 let new_l_dis=ev.pageX-disX; let new_t_dis=ev.pageY-disY; // 最大可拖動的距離 let max_l_dis=window.innerWidth-oBox.offsetWidth; let max_t_dis=window.innerHeight-oBox.offsetHeight; // 邊界問題 if(new_l_dis<0){ new_l_dis=0; } if(new_l_dis>max_l_dis){ new_l_dis=max_l_dis; } if(new_t_dis<0){ new_t_dis=0; } if(new_t_dis>max_t_dis){ new_t_dis=max_t_dis; } oBox.style.left=new_l_dis+"px"; that.style.top=new_t_dis+"px"; document.documentElement.onmouseup=function(){//鼠標擡起,再也不移動 this.onmousemove=null; this.onmouseup=null; } } } </script> </body> </html>
12.DOM事件 DOM事件(3個級別):DOM0;DOM2;DOM3; DOM0特色:js與html強耦合;綁定的速度快,不須要操做dom,可直接在元素上綁定 dom.onclick=function(){ do something; } DOM2特色:能夠在一個元素中添加不一樣的事件,事件不會覆蓋; dom.addEventListener("click",function(){},false) DOM3特色:在dom2的基礎上,添加更多的事件類型;可自定義事件; var event=new Event("test"); dom.addEventListener("test",function(){},false); setTimeout(function(){ oBox.dispatchEvent(event); },2000) DOM事件捕獲的具體流程: window->document->html->body->...->目標元素 事件流: 捕獲->目標階段->冒泡 一個節點上註冊多個事件: 解決響應優先級:event.stopImmediatePropagation();
13.javascript如何實現一個類,怎麼實例化這個類? 1.構造函數法 // 構造函數法(this + prototype) // 用new關鍵字生成實例 對象 function Person(name, age) { this.name = name; this.age = age; } Person.prototype.info = function() { alert(this.name + this.age); } var xiaoLi = new Person("李佳", 26); xiaoLi.info(); 2.es6語法糖 // es6語法糖 // 用new關鍵字生成實例化對象 // 優勢:避免了使用prototype class Person { constructor(x, y) { this.x = x; this.y = y; } info() { alert(this.x + this.y); } } var xiaoLi = new Person("李佳", 26); xiaoLi.info();
14.解釋做用域鏈 1.全局函數沒法查看局部函數的細節,局部函數能夠訪問全局函數的屬性 2.當前做用域沒有找到屬性或方法,能夠向上層乃至全局尋找,這種形式就是做用域鏈
15. .call()和.apply()的區別? .call()和.apply()是每一個函數都包含而非繼承來的方法,用於改變函數的做用域 兩方法做用相同 區別在接收參數的方式不一樣,call()要求明確傳入每個參數; 擴充做用域,舉個栗子: window.color = "red"; var o = {color: "blue"}; function sayColor() { alert(this.color); } sayColor(); // red sayColor.call(this); // red sayColor.call(window); //red sayColor.call(o); // blue
15.jsonp的原理 利用script標籤能夠跨域訪問的特性,動態建立script標籤,給標籤設置src屬性。 經過script標籤訪問跨域的地址,返回一個參數爲請求數據的callback的回調函數,而再也不直接是json數據。 具體實現步驟: 原生: $(document).ready(function(){ var url = "http://www.practice-zhao.com/student.php?id=1&callback=jsonhandle"; var obj = $('<script><\/script>'); obj.attr("src",url); $("body").append(obj); }); jquery: $(document).ready(function(){ $.ajax({ type : "get", async: false, url : "http://www.practice-zhao.com/student.php?id=1", dataType: "jsonp", jsonp:"callback", //請求php的參數名 jsonpCallback: "jsonhandle",//要執行的回調函數 success : function(data) { alert("age:" + data.age + "name:" + data.name); } }); });
16.jquery鏈式調用 原理:對象方法上最後加上return this;語句 優勢:節省代碼,代碼看起來更優雅
17.原型和原型鏈 先記兩個乾巴巴的結論: 舉個栗子: function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function() { alert(this.name) } } var person1 = new Person('Zaxlct', 28, 'Software Engineer'); var person2 = new Person('Mick', 23, 'Doctor'); console.log(person1.constructor == Person); //true console.log(person2.constructor == Person); //true 1.實例的構造函數屬性(constructor)指向構造函數。 var A = new Person(); Person.prototype = A; 2.原型對象(Person.prototype)是 構造函數(Person)的一個實例。