前端知識點整理——javascript

javascript

做爲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)的一個實例。
相關文章
相關標籤/搜索