前端常見概念講解

一、原始類型有哪幾種?對象類型和原始類型有什麼區別?null是對象嗎?

6個原始類型,原始類型存儲的是值,沒有函數能夠調用的,string類型比較特殊,如 :('test').toString(),執行該方法時,'test'會被強制轉換成String類型(對象),從而能夠調用對應的方法 number string null undefined symbol booleancss

對象類型存儲的是指針,而原始類型存儲的是值,當建立一個對象的時候,內存中會開闢一個空間來存放值,經過指針指向該內存空間。html

二、如何準確判斷數據類型?typeof、constructor、instanceof、Object.prototype.toString.call()

一、使用typeof進行判斷前端

typeof 除了null,判斷原始類型是準確的,其餘類型判斷都爲object(除了function)
typeof 'test'           > "string"
typeof 1                > "number"
typeof undefined        > "undefined"
typeof true             > "boolean"
typeof Symbol()         > "symbol"
typeof null             > "object"
typeof []               > "object"
typeof {}               > "object"

typeof function aaa(){} > "function"

二、使用constructor進行判斷

('test').constructor.name           > "String"
(2).constructor.name                > "Number"
(true).constructor.name             > "Boolean"
([]).constructor.name               > "Array"
({}).constructor.name               > "Object"
(function aa(){}).constructor.name  > "Function"
複製代碼

constructor判斷類型,看似完美,但也存在缺陷,由於對象的constructor是能夠更改的,更改後,判斷就不可靠了vue

三、使用instanceof
(1) instanceof Number                   > false
('test') instanceof String              > false
({}) instanceof Object                  > true
([]) instanceof Object                  > true
([]) instanceof Array                   > true
(function aaa(){}) instanceof Function  > true
複製代碼

能夠看出instanceof只能準確判斷出對象和函數類型,其餘就不能精準判斷了。node

四、Object.prototype.toString.call()webpack

以上三種結合起來能夠判斷數據類型,這裏提供一種終極方案。使用Object對象的原型方法toStringios

var test = Object.prototype.toString
test.call(2)            > "[object Number]"
test.call('test')       > "[object String]"
test.call(null)         > "[object Null]"
test.call(undefined)    > "[object Undefined]"
test.call([])           > "[object Array]"
test.call({})           > "[object Object]"
test.call(function(){}) > "[object Function]"
test.call(Symbol())     > "[object Symbol]"
複製代碼

三、JS原型和原型鏈

什麼是原型?es6

任何對象都有一個原型對象,原型對象,由對象的內置屬性_proto_指向它的構造函數的prototype對象,任何對象都是由一個構造函數建立的,不是每一個對象都有prototype屬性,只有方法纔有。web

什麼是原型鏈?json

原型鏈的核心是依賴_proto_的指向,當自身不存在屬性時,就一層一層的去查找建立對象的構造函數,直到查找到Object時,就沒有_proto_指向了。 如下爲簡單的原型鏈分析

function Person(name){
    this.name = name;
}
var p = new Person('hanhan');

/* new的過程分三步 (1) var p = {};--初始化對象p (2) p.__proto__ = Person.prototype;--將對象p的__proto__設置爲Person的prototype (3)Person.call(p,'hanhan');--調用構造函數Person來初始化p */

/* p.__proto__ === Person.prototype > true Person.prototype.__proto__ === Object.prototype > true Object.prototype.__proto__ > null */

//因而可知,原型鏈的頂端是Object,最終__proto__指向null
複製代碼

四、閉包

什麼是閉包?

閉包是函數和聲明該函數的詞法環境的組合。如:函數A內部中存在函數B,函數B能夠訪問函數A中的變量,這就是閉包

function A{
        let age =18;
        window.B = function () {
            console.log(age);
        }
    }
    B(); //打印:18

    /* 有個需求,延遲打印循環的值,代碼以下 */
    for(var i = 0;i<10;i++){
        setTimeout(function(){
            console.log(i);
        },0);
    }

    //打印結果爲10個10,顯然不符合需求,由於setTimeout爲異步函數,執行的時候i已經變成10,可使用閉包解決這問題

    for(var i = 0;i<10;i++){
        (function(value){
            setTimeout(function(){
                console.log(value);
            },0);
        })(i);
    }
複製代碼

閉包有哪些做用?

主要有兩點用處:

一、能夠讀取函數內部的變量

二、讓這些變量的值始終保持在內存中

注意點:

一、使用閉包時,因爲變量會被保存在內存中,內存消耗大,因此不能濫用。IE瀏覽器中可能會致使內存泄露,因此在退出函數以前,將不適用的局部變量進行刪除。

五、淺拷貝和深拷貝

淺拷貝只會拷貝全部屬性值到新的對象,若是屬性值包含對象的話,那麼拷貝的是其地址,淺拷貝可使用Object.assgin方法,還能夠經過擴展運算符來實現淺拷貝,如:let b = {...a};

在不少狀況下,咱們須要用到深拷貝,如何實現深拷貝呢?

一、jQuery中$.extend能夠實現深拷貝

二、JSON.parse(JSON.stringify(obj))--該方法會忽略undefined、symbol,不能序列化對象

三、手動實現一個簡單的深拷貝

/** * 實現深拷貝 * @param {被深拷貝對象} obj */
function deepClone(obj){
    //判斷是否爲對象,除null外
    function isObj(o){
        return (typeof o === 'object' || typeof o === 'function') && o !==null
    }
    if(!isObj(obj)){
        throw new Error('傳入的值非對象');
    }
    //判斷是不是數組
    let isArray = Array.isArray(obj);
    let newObj = isArray ? [...obj] : {...obj}
    Reflect.ownKeys(newObj).forEach(key=>{
        //判斷屬性對應的值是否爲對象,若是是對象的話就進行遞歸clone
        newObj[key] = isObj(obj[key]) ? deepClone(obj[key]) : obj[key]
    });
    return newObj;
}
複製代碼

六、繼承

es6中新增了class,用此來實現繼承很方便

/** * 繼承 * class只是語法糖,本質仍是函數 */

//父類
class Parent{
    // 構造函數,在new的時候執行
    constructor(value){
        this.val = value;
    }

    getValue(){
        console.log(this.val);
    }
}

//子類
class Child extends Parent{
    constructor(value,name){
        super(value)
        this.name = name;
    }

    sayHello(){
        console.log(this.name);
    }
}

var aaa = new Child('18','piao');
複製代碼

七、ES6新特性

1:let、const

二、Proxy

new Proxy(aaa,{
    get(target, property, receiver){
        console.log('獲取值');
        return Reflect.get(target, property, receiver)
    },
})
複製代碼

三、map 生成新數組,遍歷原數組,進行變換放入到新的數組

[1,2,3,4].map(v=>v*v)   // ->[1,4,9,16]
複製代碼

四、filter 生成新數組,遍歷數組,將返回值爲true的元素放入新的數組

[1,2,3,4].filter(val=>val>=3)    // ->[3,4]
複製代碼

五、reduce 能夠將數組中元素,經過回調函數最終轉換成一個值,如實現數組元素求和,第二個參數表明初始值

[1,2,3,4].reduce((acc,current)=>acc+current,0)    // ->10
複製代碼

八、Event Loop(事件循環)

進程和線程:在應用上來講進程表明的就是一個程序,線程是進程中更小的單位,指執行一段指令所需時間。

執行棧:能夠認爲是存儲函數調用的棧結構,先進後出,對於異步代碼,會被掛起並在須要執行的時候加入到Task隊列中,一旦執行棧爲空,Event Loop就會從Task隊列中拿出須要執行的代碼,並放入執行棧中執行,因此他的本質仍是同步行爲。

九、call、apply、bind

call、apply是爲了改變某個函數運行時的上下文而存在的,也就是改變函數內部的this指向。

call、apply的功能徹底同樣,只是參數的方式不同,以下:

func.call(this, arg1, arg2);

func.apply(this, [arg1, arg2])

bind()最簡單的用法就是建立一個函數,使這個函數不論怎麼調用都有一樣的this值

十、事件

事件:就是文檔或瀏覽器窗口發生的一些特色交互的瞬間

事件流:(IE)事件冒泡、(Netscaoe)事件捕獲

事件冒泡:事件開始由最具體的元素接收,而後逐級向上傳播較爲不具體的節點。

事件捕獲:由不太具體的節點接收事件,而後再一級一級向下到具體的節點。

事件代理:若是一個節點中的子節點是動態生成的,那麼子節點須要註冊事件的話,應該註冊到父節點上。優勢: (1)節省內存 (2)不須要給子節點註銷事件

十一、跨域

出於安全考慮,瀏覽器有同源策略,若是協議、域名、端口號有一個不一樣就是跨域。主要用於阻止CSRF攻擊。解決跨域問題以下:

一、JSONP

利用script標籤沒有跨域限制的漏洞,經過標籤指向一個須要訪問的地址,並提供一個回調函數來接收數據。JSONP只是適用於GET請求

<script src="//xxx.com/api?param=xx&callback=jsonp"></script>
    function jsonp(data){
        console.log(data);
    }
複製代碼

二、CORS 服務端設置Access-Control-Allow-Origin 就能夠開啓 CORS,該屬性標識哪些域名能夠訪問資源,若是設置通配符,表示全部網站均可以訪問資源。

三、Proxy代理---經過服務端代理轉發,例如用node做爲web服務器,請求過程以下:接口請求->node->服務端接口->node->前端,

十二、瀏覽器渲染原理

JS有引擎,那麼執行渲染也有一個渲染引擎,Gecko、WebKit

爲何操做DOM慢?

DOM操做屬於渲染引擎中的東西,而JS又屬於JS引擎中的東西,當咱們經過JS操做DOM時,這個操做會涉及到兩個線程之間的通訊,那麼勢必會帶來性能上的損耗。

迴流:修改寬度、高度等影響頁面佈局的都會發生迴流

重繪:當節點的外觀發生變化,不影響佈局的,會發生重繪,迴流一定重繪

1三、性能優化

前端性能優化時一個長期的過程,常見的優化方法有以下幾種:

網絡層面:

一、減小HTTP請求,具體作法以下:

(1)如把多個js或css進行合併請求

(2)設計層面簡化頁面,如百度首頁

(3)合理設置http緩存(設置Cache-Control: max-age)

(4)資源合併與壓縮

(5)css雪碧圖、base64

(6)懶加載

二、減小資源體積

(1)gzip壓縮

(2)代碼混淆、壓縮

三、緩存

(1)DNS緩存--訪問一個域名後,DNS返回正常IP後,操做系統會將這個地址臨時存儲起來,這就是DNS緩存

(2)CDN部署與緩存

(3)http緩存

強緩存:直接從緩存中讀取(Expires、Cache-Control)

協商緩存:由服務端告知,能夠從緩存中讀取
複製代碼

四、使用webp格式的圖片

渲染和DOM操做方面:

在網頁初步加載時,獲取HTML文件以後,最初的工做是構建DOM和構建CSSOM兩個樹,以後他們合併造成渲染樹,最後進行打印。

一、css放在header中,js放在body底部,先讓頁面渲染

二、儘可能避免內聯樣式--減小html體積

三、避免直接進行頻繁的DOM操做

四、使用class代替內聯樣式修改

五、使用事件代理

六、函數節流:在必定時間內,函數只能執行一次,函數防抖:函數防抖的基本思想是設置一個定時器,在指定時間間隔內運行代碼時清除上一次的定時器,並設置新的定時器,直到函數請求中止並超過期間間隔纔會執行

vue項目的性能優化:

vue自己對虛擬DOM diff後纔會更新DOM,性能相對來講已經很高,可是項目中還可能會遇到性能問題,優化主要方法:

一、組件懶加載 二、服務端渲染 三、數據遍歷時,設置key值 四、骨架屏

1四、webpack

現代JavaScript應用程序的靜態模塊打包工具。核心概念:

(1)入口(entry)

(2)輸出(output)

(3)loader--可以處理那些非JavaScript文件,本質上,loader將全部類型的文件,轉換成應用程序的依賴圖能夠直接引用的模塊。

(4)插件(plugins)

1五、XSS

XSS,跨站腳本攻擊。本質上講,XSS就是瀏覽器錯誤的把用戶輸入的信息當作js腳本執行了。主要分爲反射性XSS、存儲型XSS、DOM XSS。

反射型XSS:XSS代碼出如今URL中,服務端進行解析,最後返回給瀏覽器,瀏覽器執行了XSS代碼。

存儲型XSS:主要是將XSS代碼存儲在服務器中,下次請求頁面的時候就不用帶上XSS代碼了。例如留言板。

DOM XSS:該問題通常咱們編寫JS代碼形成的,比如使用eval語句執行用戶輸入的字符串。

防護:

(1)cookie設置httpOnly

(2)對用戶輸入的特殊字符進行編碼、解碼或者過濾

(3)禁止使用eval

(4)使用$().text賦值

1六、CSRF

CSRF跨站僞造請求,在用戶已登陸目標網站以後,誘導用戶訪問一個攻擊頁面,已用戶的身份在攻擊頁面發送僞造請求。 防護手段:

(1)使用POST,限制GET

(2)加驗證碼

(3)使用token

1七、常見的兼容性問題

一、默認的內補丁和外補丁不一樣,magin和padding

解決:設置{magin:0;padding:0;}

二、標籤之間有默認間距

解決:給父元素設置font-size:0

三、ios元素綁定事件,點擊無效

解決:加樣式cursor:pointer

相關文章
相關標籤/搜索