JS核心知識概括

整理進行中,若有不正,煩請提出,謝謝了。javascript

JS基礎

1.數據類型?

6基本數據類型: Undefined, Null, Boolean, Number, String ,Symbol
引用類型: Array Object Date Functionhtml

區別:
基本類型值保存在棧空間,咱們經過按值來訪問的。
引用類型,的值是對象,棧內存中存放地址指向堆內存中的對象。是按引用訪問的。棧內存中存放的只是該對象的訪問地址,在堆內存中爲這個值分配空間。
1.基本數據類型不能夠添加/刪除屬性和方法;
2.複製的方式不一樣;引用類型複製的時候,複製的是指針,2個變量實際指的是同一個對象。
3.函數的參數是按值傳遞的
檢測數據類型 typeof instanceof
轉型數據類型前端

顯式:Boolean()/Number()/pareseInt()/pareseFloat()/toString()/String()
隱私: +、 賦值

區別: undefined與null 的區別java

null:node

是Null類型的值.
是個空值,空對象指針.
typeof null,結果爲Object;
null用來表示還沒有存在的對象.

undefined :git

是Undefined類型的值。
typeof undefined,結果爲undefined;
一個聲明瞭變量,但未初始化值,結果就是undefined
沒有返回值的函數,返回的也是undefined,
沒有實參的形參也是undefined;

symbol
表示獨一無二的值
Symbol 值經過Symbol函數生成
對象的屬性名如今能夠有兩種類型,一種是原來就有的字符串,另外一種就是新增的 Symbol 類型
Symbol函數前不能使用new命令,不然會報錯。這是由於生成的 Symbol 是一個原始類型的值,不是對象
因爲 Symbol 值不是對象,因此不能添加屬性。基本上,它是一種相似於字符串的數據類型
Symbol函數的參數只是表示對當前 Symbol 值的描述,所以相同參數的Symbol函數的返回值是不相等的。由於symbol的每一個值不相等。
Symbol 值不能與其餘類型的值進行運算,會報錯
Symbol 值能夠顯式轉爲字符串。
Symbol 值也能夠轉爲布爾值,可是不能轉爲數值
Symbol 值做爲對象屬性名時,不能用點運算符。es6

2.面向對象?

何爲面向對象
 萬物皆對象,
 對象又有以下特色: 
 抽象:抓住核心問題
 封裝:只能經過對象來訪問方法
 繼承:從已有的對象下繼承出新的對象
 多態:多對象的不一樣形態
建立對象的5種方式
 1.工廠方式建立對象:面向對象中的封裝函數(內置對象)
 2.構造函數建立對象
 優勢:建立自定義函數意味着未來能夠將它的實例標識爲一種特定的類型,這是構造函數賽過工廠模式的地方
 缺點:每一個方法都要在每一個實例上從新建立一遍
 三、對象字面量方式建立對象
 四、用原型方式 
 一、優勢:可讓全部的對象實例共享它所包含的屬性和方法
 二、缺點:原型中是全部屬性都是共享的,可是實例通常都是要有本身的單獨屬性的。因此通常不多單獨使用原型模式。
 5.混合模型:構造函數模式定義實例屬性,而原型模式用於定義方法和共享的屬性
總結:使用上述的混合法github

3.Array

數組的增長ajax

array.push()   向數組末尾添加元素,返回的是添加後新數組的長度,原有數組改變
array.unshift()  向數組開頭添加元素,返回的是添加後新數組的長度,原有數組改變
array.splice(n,m)   從索引n開始刪除m個元素,把刪除的內容當作新數組返回,原有數組
array.concat()
// ES6的合併數組
[...arr1, ...arr2, ...arr3]
Array.prototype.push.apply(arr1,arr2);)----將arr2追加到arr1中,返回數組的長度

數組的刪除chrome

array.pop() 刪除數組的最後一項,返回的是刪除的那一項,原有數組改變
array.shift() 刪除數組的的第一項,返回的是刪除的那一項,原有數組改變
splice(n,m,x) 從索引n開始刪除m個元素,而後插入元素x,把刪除的內容當作新數組返回,原有數組改變。做刪除使用,x不傳入數據既可。
slice(n,m) 從索引n開始刪除m個元素,返回刪除項,原數組不變
length   減少數組的長度,實際是從數組尾部刪除元素,改變原數組。

其實只有一種 splice(),但delete方法,我我的感受算修改不屬於刪除,詳情請見實例

clipboard.png

indeOf() 
lastIndexOf()
find()
findIndex()
includes()
[1, 4, -5, 10].find((n) => n < 0)    // -5
[1, 4, -5, 10].findIndex((n) => n < 0)    // 2
[1, 2, 3].includes(2)     // true

排序
array.reverse() 把數組倒過來排序,原有數組改變
array.sort() 能夠實現由大到小或者由小到大的排序 可是直接寫sort只能排序十之內的數字

3.1類型轉換

數組 對象 字符串 的轉換;

array -->string:

join("+") 把數組的每一項拿出來用指定分隔符隔開 ;
tostring 把數組的每一項拿出來用逗號隔開,原有數組不變

obj --> string

JSON.parse(); //能夠將json字符串轉換成json對象
JSON.stringify(); //能夠將json對象轉換成json對符串

string-->array:

split(「,」)

obj --> array:

For… in循環賦值法
Array.from()

number --> array

Array.of()

string --> number (4種)

Number() 
parseFloat()  //  若是parseInt()和parseFloat()不可以把指定的字符串轉換爲數字,它們就會返回NaN  parseInt(''eleven"); // Returns Nan 
parseInt()  // parseInt()是取整,即丟棄小數部分,保留整數部分 parseInt(2.7) ==>3 
+number // var c = +'2'  typeof c ---number

string <-- number (4種)
var c = String(number)
var c = number + ''
var c = number.toString(8) // 將number 轉換成8進制的數字 且c的類型是string
var c = number.toFixed(1); //數字轉換爲字符串,而且顯示小數點後的指定的位數 例 number = 123.476,則c= 123.5"

深淺拷貝
對象和數組的拷貝有兩種
淺拷貝即 拷貝了指針指向,當一個對象的值改變會影響另外一個對象的值。
深拷貝, 拷貝的是真正的值。2者相互獨立,互不干擾。
淺拷貝的方法4種方法
slice() concat() 賦值法 遍歷
注:concat 和 slice 對一維數組 能算是深拷貝;2維的 是淺拷貝

var  a= [1,2,3,4]
b= a.concat();
c=a.concat();
b[0] = 5;
c[0] = 6;
a // [1,2,3,4]
b // [5,2,3,4]
c // [6,2,3,4]
var  aa= [[1,1],[2,2],3,4]
bb= aa.concat();
cc=aa.concat();
bb[1][0] = 5;
cc[0] = 6;
aa // [[1,1],[5,2],3,4]
b // [[1,1],[5,2],3,4]
c // [6,[5,2],3,4]
var shallowCopy = function(obj) {

// 只拷貝對象
if (typeof obj !== 'object') return;
// 根據obj的類型判斷是新建一個數組仍是對象
var newObj = obj instanceof Array ? [] : {};
// 遍歷obj,而且判斷是obj的屬性才拷貝
for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        newObj[key] = obj[key];
    }
}
return newObj;
}

深拷貝的方法5種方法:
一維數組和對象的concat slice法 JSON.parse(JSON.stringify(arr)) 和遍歷法 解構賦值法
示例:(前3種畢竟簡單,這裏也不表述)
解構賦值法:const a1 = [1, 2]; const a2 = [...a1];或者const [...a2] = a1;

var deepCopy = function(obj) {

if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
    }
}
return newObj;
}

還有一些經常使用方法如filter() forEach() map() every() some()

詳情請見:最全最細緻的數組的方法整理 es5+es6

5.對象的屬性

ES5的屬性特性包括下面六個:
 configurable: 表示可否經過delete來刪除屬性從而從新定義屬性,可以修改屬性的特性,默認爲true
 enumberable: 表示是否能經過for-in循環返回屬性。默認爲true
 writable: 是否能夠修改屬性, 默認爲true
 value: 包含這個屬性的數據值。讀取屬性值時3,從這個屬性讀,寫入屬性時,把新值保存到這個位置。默認值爲undefine.
 getter: 在讀取屬性時,調用的函數
 setter: 在寫入屬性時調用的函數
 特別注意:一旦調用了Object.defineProperty方法以後,那些未定義的特性值除了configurable爲false以外,其餘都爲undefined;

6.DOM

 DOM是針對HTML和XML文檔的一個API(應用程序編程接口). DOM描繪了一個層次化的節點樹, 容許開發人員添加, 移除和修改頁面的某一部分.
 經常使用的DOM方法:
1)查找
a) getElementById(id) //經過元素Id,惟一性
b) getElementsByTagName() //經過標籤名稱
c) getElementsByName() //經過元素的Name屬性的值(IE容錯能力較強,

會獲得一個數組,其中包括id等於name值的)

2)添加、移除、替換、插入 複製
c) appendChild(node) // 可添加 可移動位置;可添加元素 可添加文本
d) removeChild(node)
e) replaceChild(取代別人的mode,已有節點) // 替換已有節點
f) insertBefore(插入節點,已有節點) //在已有的子節點前插入一個新的子節點
g) cloneNode(true/false) //深淺複製

3)建立

createDocumentFragment()    //建立一個DOM片斷
 createElement()  //建立一個具體的元素 div  p  span
 createTextNode()   //建立一個文本節點

4)
i) getAttribute()
j) setAttribute()

5 經常使用的DOM屬性
a) innerHTML 節點(元素)的文本值
b) parentNode 節點(元素)的父節點
c) childNodes
d) attributes 節點(元素)的屬性節點

6.兩個節點的關係

7.JS獲取盒模型寬高

爲了方便書寫,如下用dom來表示獲取的HTML的節點。

  1. dom.style.width/height

  這種方式只能取到dom元素內聯樣式所設置的寬高,也就是說若是該節點的樣式是在style標籤中或外聯的CSS文件中設置的話,經過這種方法是獲取不到dom的寬高的。

  1. dom.currentStyle.width/height

  這種方式獲取的是在頁面渲染完成後的結果,就是說無論是哪一種方式設置的樣式,都能獲取到。
  但這種方式只有IE瀏覽器支持。

  1. window.getComputedStyle(dom).width/height

  這種方式的原理和2是同樣的,這個能夠兼容更多的瀏覽器,通用性好一些。

  1. dom.getBoundingClientRect().width/height

  這種方式是根據元素在視窗中的絕對位置來獲取寬高的

  1. dom.offsetWidth/offsetHeight
    這個就沒什麼好說的了,最經常使用的,也是兼容最好的。

8.通用的事件偵聽器

主要考覈 事件處理程序 和event對象及其屬性和方法

var EventUtil = {
        addHandler: function(element,type,handler) {//添加事件處理程序
            if(element.addEventListener) {
                element.addEventListener(type,handler,false)
            } else if(element.attachEvent){
                element.attachEvent("on" + type, handler);
            } else {
                element["on" + type] = handler;
            }
        },
        removeHandler:function(element,type,handler) {//移除事件處理程序
            if(element.removeEventListener) {
                element.removeEventListener(type,handler,false)
            }
        },
        getEvent:function(event){// 獲取事件對象
            return event ? event : window.event;
        },
        getTarget:function(event){// 獲取事件的目標
            return event.target || event.srcElement;
        },
        preventDefault(){
            (event) =>{
                if(event.preventDefault){event.preventDefault()}
                else {event.returnValue= false}
            }
        },
        stopPropagation(){
             (event) =>{
                if(event.stopPropagation){event.stopPropagation()}
                else {event.cancelBubble= true;}
            }
        }
    }
    var list = document.getElementById('list')
    EventUtil.addHandler(list,'click',function(ev){
        event= EventUtil.getEvent(ev);
        var target = EventUtil.getTarget(event);
        alert(target.id);
    })

9.實現點擊ul中li元素

方法有不少,閉包法、當即執行函數法、、事件委託法;
但本題主要考覈 DOM事件流 利用事件委託,減小dom操做,提升性能

var list = document.getElementById('list')
 list.onclick = function(ev){
       var ev = ev || window.event;     
       var target = ev.target || ev.srcElement;
       console.log(target.id);
     }

10.Ajax

原生的寫法

var xhr = new XMLHttpRequest();
   xhr.onreadystatechange = function(){
       if(xhr.readyState == 4){
           console.log(xhr.status)
            if((xhr.status >= 200 && xhr.status < 300) || xhr.status ==304){
               var hh = xhr.responseText;
               var haha1 = document.getElementById('wokao');
               haha1.innerHTML = hh;
            }else{
                alert('failed11',xhr.status);
            } 
        }
    }
   xhr.open("get","http://10.10.65.109:8888/text.json",true);
   xhr.setRequestHeader("Accept", "application/json"); 
 //  xhr.responseType = "json";
   xhr.send(null);

何爲異步? 異步與同步的概念
實現異步的方法:回調 事件 promise
Ajax最大特性:能夠實現動態不刷新(局部刷新).
優勢:

經過異步模式,提高了用戶體驗
優化了瀏覽器和服務器之間的傳輸,減小沒必要要的數據往返,減小了帶寬佔用
Ajax在客戶端運行,承擔了一部分原本由服務器承擔的工做,減小了大用戶量下的服務器負載。

缺點

一、ajax不支持瀏覽器back按鈕。
二、安全問題 AJAX暴露了與服務器交互的細節。
三、對搜索引擎的支持比較弱。
四、破壞了程序的異常機制。
五、不容易調試。

**post 和get的區別:**

 GET請求會將參數跟在URL後進行傳遞,而POST請求則是做爲HTTP消息的實體內容發送給WEB服務器。固然在Ajax請求中,這種區別對用戶是不可見的。
 GET方式請求的數據會被瀏覽器緩存起來,所以其餘人就能夠從瀏覽器的歷史記錄中讀取到這些數據,例如帳號和密碼等。在某種狀況下,GET方式會帶來嚴重的安全問題。而POST方式相對來講就能夠避免這些問題。
 "GET方式提交的數據最多隻能是1024字節",post無
 get請求和post請求在服務器端的區別:在客戶端使用get請求時,服務器端使用Request.QueryString來獲取參數,而客戶端使用post請求時,服務器端使用Request.Form來獲取參數.

**適用場景:**
POST用於建立資源,資源的內容會被編入HTTP請示的內容中。例如,處理定貨表單、在數據庫中加入新數據行等。

當請求無反作用時(如進行搜索),即可使用GET方法;當請求有反作用時(如添加數據行),則用POST方法。

若符合下列任一狀況,則用POST方法:
  • 請求的結果有持續性的反作用,例如,數據庫內添加新的數據行。
  • 若使用GET方法,則表單上收集的數據可能讓URL過長。
  • 要傳送的數據不是採用7位的ASCII編碼。
    若符合下列任一狀況,則用GET方法:
  • 請求是爲了查找資源,HTML表單數據僅用來幫助搜索。
  • 請求結果無持續性的反作用。
  • 收集的數據及HTML表單內的輸入字段名稱的總長不超過1024個字符。
  1. 對cookie localStorage sessionStorage的理解

localStorage和sessionStorage都具備相同的操做方法,例如setItem、getItem和removeItem等

**cookie:**

 cookie是網站爲了標示用戶身份而儲存在用戶本地終端(Client Side)上的數據(一般通過加密)。
 cookie數據始終在同源的http請求中攜帶(即便不須要),記會在瀏覽器和服務器間來回傳遞。
 sessionStorage和localStorage不會自動把數據發給服務器,僅在本地保存。
 存儲大小:
 cookie數據大小不能超過4k。
 sessionStorage和localStorage 雖然也有存儲大小的限制,但比cookie大得多,能夠達到5M或更大。
 有期時間:
 localStorage 存儲持久數據,瀏覽器關閉後數據不丟失除非主動刪除數據;
 sessionStorage 數據在當前瀏覽器窗口關閉後自動刪除。
 cookie 設置的cookie過時時間以前一直有效,即便窗口或瀏覽器關閉
 做用域不一樣:
 sessionStorage不在不一樣的瀏覽器窗口中共享,即便是同一個頁面;
 localStorage 在全部同源窗口中都是共享的;cookie也是在全部同源窗口中都是共享的。
 Web Storage 支持事件通知機制,能夠將數據更新的通知發送給監聽者。
 Web Storage 的 api 接口使用更方便。
sessionStorage用於本地存儲一個會話(session)中的數據,這些數據只有在同一個會話中的頁面才能訪問而且當會話結束後數據也隨之銷燬。所以sessionStorage不是一種持久化的本地存儲,僅僅是會話級別的存儲。

而localStorage用於持久化的本地存儲,除非主動刪除數據,不然數據是永遠不會過時的。
Web Storage的概念和cookie類似,區別是它是爲了更大容量存儲設計的。Cookie的大小是受限的,而且每次你請求一個新的頁面的時候Cookie都會被髮送過去,這樣無形中浪費了帶寬,另外cookie還須要指定做用域,不能夠跨域調用。

除此以外,Web Storage擁有setItem,getItem,removeItem,clear等方法,不像cookie須要前端開發者本身封裝setCookie,getCookie。
總之:cookie的做用是與服務器進行交互,做爲HTTP規範的一部分而存在 ,而Web Storage僅僅是爲了在本地「存儲」數據而生
cookie優勢:極高的擴展性和可用性 缺點: 數量和長度受限、安全問題
cookie 和session 的區別:
一、cookie數據存放在客戶的瀏覽器上,session數據放在服務器上。
二、cookie不是很安全,別人能夠分析存放在本地的COOKIE並進行COOKIE欺騙

考慮到安全應當使用session。

三、session會在必定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能

考慮到減輕服務器性能方面,應當使用COOKIE。

四、單個cookie保存的數據不能超過4K,不少瀏覽器都限制一個站點最多保存20個cookie。
五、因此我的建議:

將登錄信息等重要信息存放爲SESSION
其餘信息若是須要保留,能夠放在COOKIE中

12.IE的不一樣之處

IE支持currentStyle,FIrefox使用getComputStyle

IE 使用innerText,Firefox使用textContent

濾鏡方面:IE:filter:alpha(opacity= num);Firefox:-moz-opacity:num

事件方面:IE:attachEvent:火狐是addEventListener

鼠標位置:IE是event.clientX;火狐是event.pageX

IE使用event.srcElement;Firefox使用event.target

IE中消除list的原點僅需margin:0便可達到最終效果;FIrefox須要設置margin:0;padding:0以及list-style:none

CSS圓角:ie7如下不支持圓角

13.this工做原理

原則,那就是this指的是調用函數的那個對象。

javascript 的this主要是看如何調用這個函數,而不是這個函數所在的做用域。obj.fn() fn中的 this 就是 obj。 fn() this是undifine, 而在js進入函數以前,會有 if(!this) { this = window} 這樣的操做。

this 一共有六種不一樣的值:

普通函數調用,this爲全局對象或是undefined

做爲對象的方法,this爲那個對象

new 表達式,this爲以該函數爲原型的新建立的對象

使用 apply/call指定 this

用bind綁定固定的this

事件處理函數中的this是當前的觸發事件的DOM元素(event.currentTarget)
IE attachEvent添加的事件處理函數中this爲window

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>this</title>
</head>
<body>
在嚴格模式下,通常的函數調用中 this 的值是 undefined。
<button onclick="console.log(this)" >
    show this
</button>
<p id="hahah">測試DOM元素(event.currentTarget)</p>
<p id="ha">測試DOM元素IE</p>
<script type="text/javascript">
var obj={a:1};
var aa = function func(a,b){ 
    console.log('this',this); 
    console.log('this',a);
    return 1;
}
var bb = function funb(){ console.log('this',this); }
bb.prototype= new aa();//

obj.f = aa;
/*
做爲對象的方法 
**
*/
obj.f(123);//輸出 obj 123
aa(123); //輸出 window  123

(obj.f)();// obj 沒懂
(a=obj.f)(); // window
(0,obj.f)(); //  window

/*
call spply bind中this
*
*
*/
aa.call('call',1);// call 1
aa.apply('apply',[1]); // apply 1
var cc = aa.bind('bind',1); 
cc(22); //bind 1
var cc1 = new cc(33)// func 1
/*
*
*new 表達式,this爲以 該函數爲原型 的新建立的對象
*/
var dd = new aa(11,22); // func {}
var bb1 = new bb();
/*
*
**事件處理函數中的this
**當前的觸發事件的DOM元素(event.currentTarget)
**IE attachEvent添加的事件處理函數中this爲window
*/
function evtHandle(e)
{
    console.log('e.currentTarget.id',this.id); // 
    console.log('e.target.id',this.id);        // 
}
var elements = document.getElementById('hahah');
var elements1 = document.getElementById('ha');
elements.addEventListener('click',evtHandle,false);
// ie專屬  chrome下報錯
 // elements1.attachEvent('onclick',evtHandle);

obj = { go: function() { console.info('oo',this) } };
(0 || obj.go)() // window
</script>    
</body>
</html>

14.函數

1.函數的調用方式

  1. 方法調用模型 var obj = { func : function(){};} obj.func()
  2. 函數調用模式  var aa = function(){} aa();
  3. 構造器調用模式
  4. apply/ call調用模式
  5. 當即執行函數(function(){}())

區別:函數調用模式,有函數提高的;即aa() 無需必須在var aa = function(){} 後面

2.return的含義

注:return不必定非得用在function 中,也能夠直接放在html中,如:onsubmit="return false";

語法:return 表達式;
含義:語句結束函數執行,返回調用函數,並且把表達式的值做爲函數的結果
一般函數通過一系列的處理後須要給外部返回一個值,這個值通常用return返回出去,也能夠是說return是向函數返回返回值,並終止函數的運行.

return;

含義:即 return null 無函數返回值;
能中斷方法的執行,但沒法阻止事件的默認行爲。
把控制權返回給頁面。

return false;

含義:至關於終止符;
    1. 通常是用來取消默認動做的。好比,終止表單提交。好比你單擊一個連接除了觸發你的onclick事件外
    還會觸發一個默認事件就是執行頁面的跳轉。
    因此若是你想取消對象的默認動做(event.preventDefault();)就能夠return false。
    2. return false 只在當前函數有效,不會影響其餘外部函數的執行

retrun true;

含義:至關於執行符。執行終止默認的事件行爲
     返回正確的處理結果。

15.閉包

閉包是指有權訪問另外一個函數做用域中的變量的函數. 建立閉包常見方式,就是在一個函數內部建立另外一個函數.
做用:
1.匿名自執行函數 (function (){ ... })(); 建立了一個匿名的函數,並當即執行它,因爲外部沒法引用它內部的變量,所以在執行完後很快就會被釋放,關鍵是這種機制不會污染全局對象。
2.緩存, 可保留函數內部的值
3.實現封裝
4.實現模板
5.給了js函數生成函數的能力,增長了js代碼的抽象能力
缺點
1.形成內存泄露;變量內存沒法被標記,致使內存不會被垃圾回收機制回收。
爲何要用
局部變量沒法共享和長久的保存,而全局變量可能形成變量污染,因此咱們但願有一種機制既能夠長久的保存變量又不會形成全局污染。
如何使用
1.定義外層函數,封裝被保護的局部變量。
2.定義內層函數,執行對外部函數變量的操做。
3.外層函數返回內層函數的對象,而且外層函數被調用,結果保存在一個全局的變量中。

var getNum;
function getCounter() { 
    var n = 1; 
    var inner = function () { return n++; }
    return inner;
}

getNum = getCounter();
console.log(getNum()); //1   2 3 4

16.call aplly bind

apply 、 call 、bind 三者都是用來改變函數的this對象的指向的;
apply 、 call 、bind 三者第一個參數都是this要指向的對象,也就是想指定的上下文;
apply 、 call 、bind 三者均可以利用後續參數傳參;
bind是返回對應函數,便於稍後調用;
apply 、call 則是當即調用 。

function fn(a,b){
    console.log(this);
    console.log(a);
    console.log(b);
}
// bind(this,args...)
bf = fn.bind("Bind this",10); // 沒有任何輸出,也就是說沒有執行這個函數
bf(); // "Bind this",10,undefined
bf(20);// 「Bind this」,10,20
// 原函數不受影響
fn(1,2); //window, 1,2
bf2 = fn.bind("Bind this",1,2);
bf2(); // "Bind this",1,2

// call(this,args...)
fn.call("Call this",1) // "Call this",1,undefined
fn.call("Call this",1,2) // "Call this",1,2

// apply(this,[args])
fn.apply("Apply this",[1]) // "Apply this",1,undefined
fn.apply("Apply this",[1,2]) // "Apply this",1,2

17.js語言特性

特性,即封裝、繼承、多態
此處內容較多,便不詳細敘述。注意一下繼承的方式
繼承6方式:
  一、拷貝繼承:通用型 有new無new均可以用
  二、類式繼承:new構造函數---利用構造函數(類)繼承的方式
  三、原型繼承:無new的對象---藉助原型來實現對象繼承對象
  4. 屬性繼承:調用父類的構造函數call
  5. 方法繼承:用for in的形式 拷貝繼承(jq也用拷貝繼承)

18."use strict"

嚴格模式」的目的,主要有如下幾個:

  • 消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲;

  - 消除代碼運行的一些不安全之處,保證代碼運行的安全;
  - 提升編譯器效率,增長運行速度;
  - 爲將來新版本的Javascript作好鋪墊。
「嚴格模式」體現了Javascript更合理、更安全、更嚴謹的發展方向

19.加載方式

1.延遲加載有些 js 代碼並非頁面初始化的時候就馬上須要的,而稍後的某些狀況才須要的。延遲加載就是一開始並不加載這些暫時不用的js,而是在須要的時候或稍後再經過js 的控制來異步加載。
JS延遲加載有助於提升頁面加載速度。

js的進程由解析和執行構成。全部的延遲加載方式都只是延遲了執行過程。解析從未中止
js的執行順序是自上而下。
延遲加載幾種方式:

defer 屬性 defer的做用是,告訴瀏覽器,等到DOM加載完成後,再執行指定腳本。
async 屬性 async的做用是,使用另外一個進程下載腳本,下載時不會阻塞渲染,下載好了 就執行。
動態建立DOM方式  document.createElement 
使用jQuery的getScript方法
使用setTimeout延遲方法
讓JS最後加載(放在文檔尾部)

2.同步加載,又稱阻塞模式,會阻止瀏覽器的後續處理,中止了後續的解析,所以中止了後續的文件加載(如圖像)、渲染、代碼執行。

3.異步加載:也就是說第一個fun請求數據時,數據還未返回時便開始執行第二個fun了
表明:ajax 回調 事件 promise

4.預加載
一種瀏覽器機制,使用瀏覽器空閒時間來預先下載/加載用戶接下來極可能會瀏覽的頁面/資源,當用戶訪問某個預加載的連接時,若是從緩存命中,頁面就得以快速呈現
5.圖片延遲加載的方式

js--進階

1.原型鏈

許多OO語言支持兩種繼承方式:接口繼承和實現繼承。
接口繼承只繼承方法簽名,實現繼承則繼承實際的方法。
因爲函數無簽名,在JavaScript中沒法實現接口繼承。因此只能實現方法繼承。
實現繼承主要依賴原型鏈。
基本思想:利用原型,讓那個一個引用類型繼承另外一個引用類型的屬性和方法。A.prototype= new B();讓原型對象等於另外一個類型的實例。
全部函數的默認原型都是Object的實例
即A繼承了B ;B 繼承了Object;

什麼是原型對象。咱們知道每一個構造函數一旦建立都有prototype指針指向它的原型對象(構造函數.prototype)。而原型對象(構造函數.prototype)會默認生成一個constructor指針又指向構造函數。在建立實例時,每一個實例有一個__proto__指向該原型對象。原型對象內建立的全部方法會被全部實例共享。
例:

Function.prototype = {    
        constructor : Function,
        __proto__ : parent prototype,
        some prototype properties: ...
    };

原型對象中的方法屬性是被全部實例共享的。若是含有引用類型的屬性,如數組,修改person1中的數組屬性,也會致使person2中的該屬性發生變化。

什麼是原型鏈?
函數的原型對象constructor默認指向函數自己,原型對象除了有原型屬性外,爲了實現繼承,還有一個原型鏈指針proto,該指針指向上一層的原型對象,而上一層的原型對象的結構依然相似,這樣利用proto一直指向Object的原型對象上,而Object的原型對象用Object.prototype.proto = null表示原型鏈的最頂端,如此變造成了javascript的原型鏈繼承,同時也解釋了爲何全部的javascript對象都具備Object的基本方法。

原型鏈就是建立一個構造函數,它會默認生成一個prototype屬性並指向原型對象。使用下一個構造函數的原型對象做爲這個構造函數的實例。即 A.prototype = new B(); 在下下一個構造函數的原型對象 = new nextFuction。這樣下去就會構成一條實例與原型之間的鏈條,這就是原型鏈。

clipboard.png

2.繼承

構造函數A()和實例a1 a2之間的關係;var a1 = new A(); var a2 = new A();
實例a1與實例a2是獨立的
實例和原型的關係 a1.__proto__ = A.prototype
構造函數A()和其原型的關係 A.prototype.constructor=A

6種繼承方式
原型鏈繼承本質:
是子用類型B的原型等於超類型的實例,
B.prototype= new A()

構造函數繼承本質:
是子用類型的構造函數內部調用A(),
B(){A.call(this,**);}

組合繼承本質
原型鏈和構造函數的組合,原型繼承方法,構造函數繼承屬性

原型式繼承本質:基於已有對象建立一個對象,
即對象A的淺拷貝,
var b= Object.create(A)

寄生式繼承本質:
建立一個用於封裝繼承過程的函數,
function b(A){var clone = Object.create(A) ;clone.=;return clone;}

寄生組合繼承本質:
寄生式繼承超類型A的原型,並將結果賦值給子類型的原型;
或對對象A的原型淺拷貝,
function B(**){

A.call(this,**)

}
function c(A,B){var clone = Object.create(A.prototype); clone.constructor = B;B.prototype=clone;) ;}

function Person(name) {
            this.name = ['123','456','789',name];
        }
        Person.prototype.go = function(){
            return console.log(this.name)
        }
        Person.prototype.sex = ['男','女'];
        var ren = new Person();
        console.log('構造函數和原型的關係:',Person.prototype.constructor ===Person)
        console.log('實例和原型的關係',ren.__proto__ ===Person.prototype)
        
        // 原型鏈繼承 
        // 缺點1.不能向person中傳遞參數;
        // 缺點2.超類型的原型屬性會被其餘實例共享,一個實例改變,則其餘實例也改變。
        // 下面2個原型的順序不能換  
        function Shuagnfeng(love) {
            this.love = ['fd','fddfdf']; 
        }
        Shuagnfeng.prototype = new Person();
        console.log('會誤會超類型Person:',Shuagnfeng.prototype.constructor ===Person) //true
        console.log('構成原型鏈,',Shuagnfeng.prototype.__proto__ ===Person.prototype) //true
        Shuagnfeng.prototype.constructor ===Shuagnfeng;
        Shuagnfeng.prototype.goWork = function(){
           return  console.log('原型鏈繼承的方法');
        }
        var child = new Person();
Shuagnfeng.prototype.name.push(121);
console.log('超類型實例2 child',child.name);

        var xiaozhang = new Shuagnfeng('dff');
        var xiaozhang1 = new Shuagnfeng('zzz');
        xiaozhang.go();
        xiaozhang.goWork();   
        xiaozhang.name.push('只對xiaozhang增長屬於超類型Person中array值',22);
        xiaozhang.love.push('只對xiaozhang增長屬於構造函數中array值',22);
        xiaozhang.sex.push('只對xiaozhang增長屬於超類型的原型中array值');

        console.log('xiaozhang.超類型Person中name',xiaozhang.name);
        console.log('xiaozhang1.超類型Person中name',xiaozhang1.name);
        console.log('xiaozhang.構造函數中中love',xiaozhang.love);
        console.log('xiaozhang1.構造函數中love',xiaozhang1.love);
        console.log('xiaozhang.超類型的原型中sex',xiaozhang.sex);
        console.log('xiaozhang1.超類型的原型中sex',xiaozhang1.sex);


// 構造函數的繼承
// 優勢,不會改變引用類型的屬性,能傳遞參數
// 缺點沒法複用方法;
        function Jianbo() {
            Person.call(this,'構造函數的繼承')
        }
        var xiaonie = new Jianbo();
        console.log('構造函數的繼承xiaonie.name可傳參數',xiaonie.name);
       // xiaonie.go(); // 不存在



// 組合繼承
// 原型鏈繼承方法、構造函數繼承屬性
        function Nb(love) {
            Person.call(this,'nb')
            this.love = love
        }
        Nb.prototype = new Person('12');
        console.log('12',Nb.prototype.constructor ===Person) // true 
        console.log('13',Nb.prototype.constructor ===Nb)// false 由於重寫原型,會使原型失去了constructor屬性
        Nb.prototype.constructor =Nb
         console.log('14',Nb.prototype.constructor ===Person) // false
        Nb.prototype.say = function(){
            console.log('say','say')
        }
        var nb= new Nb();
        var nb1= new Nb('組合繼承');
        nb.name.push('xiaoniubi');
        console.log('nb.name',nb.name);
        console.log('nb1.name',nb1.name);
        console.log('nb1.love',nb1.love);
        nb.go();
        nb.say();

// 原型式繼承Object.create()  將基礎對象傳給object()函數 
// 本質是淺複製  副本的引用類型會被改變
// 缺點:引用類型的屬性會被共享  和原型鏈繼承差很少
// 使用場景: 讓一個對象與另外一個對象的保持相似
function object(o){
    function F(){}
    F.prototype= o;
    return new F();
}
var animal = {
    name:'原型式繼承默認值',
    friends:[1,2,3,4]
}
var haha= object(animal);
var gaga = Object.create(animal);
var haha1= object(animal);
console.log('haha',haha.name);
console.log('gaga',gaga.name);
haha.name='原型式繼承name值變了';
haha.friends.push('原型式繼承array值變了');
console.log('haha',haha.name);
console.log('haha1',haha1.name);
console.log('haha',haha.friends);
console.log('haha1',haha1.friends);

// 寄生式繼承
// 能繼承方法,但方法不能複用
function createAnother(original){
 var clone =  object(original);
 clone.say = function(){
    console.log('寄生式繼承方法')
 }
  return clone;
}

var hh = createAnother(animal);
hh.name='寄生式繼承'
console.log('hh',hh.name);
hh.say()       

// 寄生組合式
// 全部方式中最有效的方式 只調用繼承的構造函數一次




// 判斷實例和原型的關係  使用instanceof 和 isPrototypeOf()
        console.log('實例和原型的關係',xiaozhang instanceof Shuagnfeng);
        console.log('實例和原型的關係',xiaozhang instanceof Person);
        console.log('實例和原型的關係',xiaozhang instanceof Object);
        console.log('實例和原型的關係',Object.prototype.isPrototypeOf(xiaozhang));
        console.log(xiaozhang.__proto__);

3.事件委託

事件處理程序 獲取事件對象 事件目標
好處 減小DOM 操做 ,減小性能

<div id="list">
    <img id="1" src="1.png">
    <img id="3.2.2" src="3.2.2.png">
    <img id="3.2" src="3.2.png">
</div>

    <script type="text/javascript">
    var EventUtil = {
        addHandler: function(element,type,handler) {
            if(element.addEventListener) {
                element.addEventListener(type,handler,false)
            } else if(element.attachEvent){
                element.attachEvent("on" + type, handler);
            } else {
                element["on" + type] = handler;
            }
        },
        removeHandler:function(element,type,handler) {
            if(element.removeEventListener) {
                element.removeEventListener(type,handler,false)
            }
        },
        getEvent:function(event){
            return event ? event : window.event;
        },
        getTarget:function(event){
            return event.target || event.srcElement;
        },
    }
    var list = document.getElementById('list')
    EventUtil.addHandler(list,'click',function(ev){
        event= EventUtil.getEvent(ev);
        var target = EventUtil.getTarget(event);
        alert(target.id);
    })
    //    list.onclick = function(ev){
//          var ev = ev || window.event;
//     var target = ev.target || ev.srcElement;
//         console.log(target.id);
//     }
    </script>

4.跨域

形成跨域的緣由
瀏覽器的同源策略,即XMLHttpRequest(XHR)對象只能訪問同一域中的資源
這是種防止惡意行爲的安全策略。
第二個:瀏覽器中不一樣域的框架之間是不能進行js的交互操做的。

何謂同源:URL由協議、域名、端口和路徑組成,若是兩個URL的協議、域名和端口相同,則表示它們同源。

在瀏覽器中,<script>、<img>、<iframe>、<link>等標籤屬於DOM, 非XHR對象,是能夠加載跨域資源

跨域方法(實踐中後兩種最經常使用,因此重點介紹):
(1) 經過jsonp跨域
ajax請求受同源策略影響,不容許進行跨域請求,而script標籤src屬性中的連接卻能夠訪問跨域的js腳本,利用這個特性,服務端再也不返回JSON格式的數據,而是返回一段調用某個函數的js代碼,在src中進行了調用,這樣實現了跨域。
(2) 經過修改document.domain來跨子域
(3) 使用window.name來進行跨域
(4) 使用HTML5中新引進的window.postMessage方法來跨域傳送數據
(5) 使用代理服務器,使用代理方式跨域更加直接,由於同源限制是瀏覽器實現的。若是請求不是從瀏覽器發起的,就不存在跨域問題了。

使用本方法跨域步驟以下:
1. 把訪問其它域的請求替換爲本域的請求
2. 服務器端的動態腳本負責將本域的請求轉發成實際的請求

爲了經過Ajax從http://localhost:8080訪問http://localhost:8081/api,能夠將請求發往http://localhost:8080/api。
而後利用Apache Web服務器的Reverse Proxy功能作以下配置:ProxyPass /api http://localhost:8081/api

(6) CORS全稱是"跨域資源共享"(Cross-origin resource sharing),CORS須要瀏覽器和服務器同時支持。目前,全部瀏覽器都支持該功能 發送請求時,附加一個額外的Origin頭部
IE:XDR(XDomainRequest) 建立一個xdr實例,調用open() ,再send()方法;
其餘的,原生的支持,使用絕對的URL便可。

附:ajax的擴展,comment/Web Sockets
(7) fetch api

5.輸入url以後,到底發生了什麼?

clipboard.png

6 JS引擎

瀏覽器內核又能夠分紅兩部分:
渲染引擎(layout engineer或者RenderingEngine)和JS引擎。
JS的引擎深刻分析連接描述
10分鐘理解JS引擎的執行機制
http://www.ruanyifeng.com/blo...
JS引擎負責對JavaScript進行解釋、編譯和執行,以使網頁達到一些動態的效果。

js的幾種引入方式
js引擎是單線程 異步的
--- 任務隊列 事件 和回調函數 Event Loop
是經過的事件循環(event loop),實現單線程和異步的。
單線程:同一時刻只能執行一個代碼塊
將要執行的代碼放在任務隊列中,但js引擎執行代碼塊結束,事件循環會執行任務隊列中的下一個任務。
Event Loop 負責監控代碼執行和管理任務隊列。
異步的,便可經過事件 回調等方式,向任務隊列中添加新任務。

JS的執行機制是

首先判斷JS是同步仍是異步,同步就進入主進程,異步就進入event table
異步任務在event table中註冊函數,當知足觸發條件後,被推入event queue
同步任務進入主線程後一直執行,直到主線程空閒時,纔會去event queue中查看是否有可執行的異步任務,若是有就推入主進程中
以上三步循環執行,這就是event loop

準確的劃分方式是:
macro-task(宏任務):包括總體代碼script,setTimeout,setInterval
micro-task(微任務):Promise,process.nextTick
按照這種分類方式:JS的執行機制是

執行一個宏任務,過程當中若是遇到微任務,就將其放到微任務的【事件隊列】裏
當前宏任務執行完成後,會查看微任務的【事件隊列】,並將裏面所有的微任務依次執行完
重複以上2步驟,結合event loop(1) event loop(2) ,就是更爲準確的JS執行機制了。

7 錯誤監控
前端錯誤的分類

  1. 運行時錯誤(代碼錯誤)
  2. 資源加載錯誤
  3. 接口錯誤

錯誤的捕獲方式

運行時錯誤的捕獲方式:

try...catch
window.onerror 含有詳細的error信息  
    window.onerror = function(msg, url, lineNo, columnNo, error){}
window.addEventListener('error')
     window.addEventListener('error', event =>  
        { console.log('addEventListener error:' + event.target); 
        }, true);

資源加載錯誤:

object.onerror(如img,script)
performance.getEntries()
Error事件捕獲

接口錯誤:

全部http請求都是基於xmlHttpRequest或者fetch封裝的。
    因此要捕獲全局的接口錯誤,方法就是封裝xmlHttpRequest或者fetch

結論
1.使用window.onerror捕獲JS運行時錯誤
2.使用window.addEventListener(‘unhandledrejection’)捕獲未處理的promise reject錯誤
3.重寫console.error捕獲console.error錯誤
4.在跨域腳本上配置crossorigin="anonymous"捕獲跨域腳本錯誤
window.addEventListener(‘error’)捕獲資源加載錯誤。由於它也能捕獲js運行時錯誤,爲避免重複上報js運行時錯誤,此時只有event.srcElement inatanceof HTMLScriptElement或HTMLLinkElement或HTMLImageElement時才上報
5.重寫window.XMLHttpRequest和window.fetch捕獲請求錯誤

延伸:跨域的js運行錯誤能夠捕獲嗎,錯誤提示什麼,應該怎麼處理?

能夠。
Script error
1.在script標籤增長crossorigin屬性
2.設置js資源響應頭Access-Control-Allow-Orgin:*

上報錯誤的基本原理

1. 採用Ajax通訊方式上報
2. 利用Image對象上報

更多

相關文章
相關標籤/搜索