6個原始類型,原始類型存儲的是值,沒有函數能夠調用的,string類型比較特殊,如 :('test').toString(),執行該方法時,'test'會被強制轉換成String類型(對象),從而能夠調用對應的方法 number string null undefined symbol booleancss
對象類型存儲的是指針,而原始類型存儲的是值,當建立一個對象的時候,內存中會開闢一個空間來存放值,經過指針指向該內存空間。html
一、使用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]"
複製代碼
什麼是原型?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');
複製代碼
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
複製代碼
進程和線程:在應用上來講進程表明的就是一個程序,線程是進程中更小的單位,指執行一段指令所需時間。
執行棧:能夠認爲是存儲函數調用的棧結構,先進後出,對於異步代碼,會被掛起並在須要執行的時候加入到Task隊列中,一旦執行棧爲空,Event Loop就會從Task隊列中拿出須要執行的代碼,並放入執行棧中執行,因此他的本質仍是同步行爲。
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時,這個操做會涉及到兩個線程之間的通訊,那麼勢必會帶來性能上的損耗。
迴流:修改寬度、高度等影響頁面佈局的都會發生迴流
重繪:當節點的外觀發生變化,不影響佈局的,會發生重繪,迴流一定重繪
前端性能優化時一個長期的過程,常見的優化方法有以下幾種:
網絡層面:
一、減小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值 四、骨架屏
現代JavaScript應用程序的靜態模塊打包工具。核心概念:
(1)入口(entry)
(2)輸出(output)
(3)loader--可以處理那些非JavaScript文件,本質上,loader將全部類型的文件,轉換成應用程序的依賴圖能夠直接引用的模塊。
(4)插件(plugins)
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賦值
CSRF跨站僞造請求,在用戶已登陸目標網站以後,誘導用戶訪問一個攻擊頁面,已用戶的身份在攻擊頁面發送僞造請求。 防護手段:
(1)使用POST,限制GET
(2)加驗證碼
(3)使用token
一、默認的內補丁和外補丁不一樣,magin和padding
解決:設置{magin:0;padding:0;}
二、標籤之間有默認間距
解決:給父元素設置font-size:0
三、ios元素綁定事件,點擊無效
解決:加樣式cursor:pointer