函數 與 優化
1. 函數構造方法: js中所有函數的構造函數都是Function,包括Function本身,(Function是自己的實例,也是自己的構造函數)
證明:
Function.prototype === Function.__proto__
1.1 函數聲明: function 函數名(){}
1.2函數表達式: var 函數名 = function(){};
1.3構造函數: var 函數名 = new Function(參數1,參數2,函數體);
1. 不傳參數創建出來的是空函數.
2. 一個參數:函數體(字符串).
3. 傳多個參數的情況:(字符串).
例:簡單的求兩個數和:
var sum = new Function('a','b','return a + b'); sum(1,2);
注:傳參數時候可以使用:拼接字符串或反引號(ES6方法)或者創建模板引擎
2. 訪問函數的方法:
2.1. 函數調用模式: 函數名();
this:指向window
2.2. 方法調用模式: 對象.函數名();
this:誰調用就指向誰
2.3. 構造函數調用模式 :new 函數名();
this:指向new出來的對象
2.4. 上下文調用模式 : 解決this作為左值不能賦值的問題
左值(LValue):能正常的在等號左邊被賦值的值
右值(RValue):能正常的在等號右邊賦值的值
* 語法:1 函數名.call(this指向,實參,實參)
注意: 1當傳入的第一個參數為undefined或Null時,指向的是window
2當傳入的第一個參數為簡單數據類型時,this指向該數據的基本包裝類型
* 語法:2 函數名.apply(this指向,數組或偽數組)
注意:第一個參數與call語法相同,后面的數組參數中的元素拆解后傳給函數
3. eval(符合js語法規范的字符串) 函數:
* 功能:將字符串轉化為代碼並執行;
* 1.eval與Function()的共同點:將字符串轉化為代碼;
2.不同點:Function()轉化成代碼之后是函數,需要手動調用才能執行,eval()會直接執行
* Function與eval的問題
1.需要預解析,執行效率問題
2.安全性問題(如果別人輸入的內容符合規范,可以進行跨站腳本攻擊xss)
3.eval會將json字符串中的{}當做代碼段處理,所以會報錯
處理:在json字符串外面拼接小括號易形成一段完整的語句;
把變量聲明也寫在eval參數中:
var jsonStr = {"key":"value"}; eval("var obj =" + jsonStr);
4. json2.js:引入解決IE7及以下版本JSON未定義問題。
json2.js提供了json的序列化和反序列化方法,可以將一個json對象轉換成json字符串,也可以將一個json字符串轉換成一個json對象。
源碼地址:https://github.com/douglascrockford/JSON-js
4.1. json2.js使用基本模型:
//在頁面中添加json2.js的引用。
<--引入json2.js文件-->
<script type="text/javascript" src="JS/json2.min.js"></script>
//序列化方法
var jsonObj = { id: '01', name: 'Tom' };
JSON.stringify(jsonObj); //反序列化方法 var jsonString = '{ "id": "01", "name": "Tom" }'; JSON.parse(jsonString);
5. 函數對象的成員
* arguments
* caller 函數在哪個環境中調用的,就指向誰,如果函數是在全局環境下調用的,指向Null
* length 形參個數
* name 函數函數聲明與函數表達式創建出的name為函數名,new Function()創建的函數name為'anonymity'
5.1. arguments對象:是一個函數內部的對象(執行環境在函數內部),是偽數組.
1 偽數組:有length屬性(但是不會動態改變),可以被遍歷,但沒有數組的方法.
2 arguments對象:
* 作用:當函數調用的時候會將所有實參一次存入偽數組中(無論形參與實參個數是否對應).
* 應用場景:當時參數個數不確定的時候,就可以不用寫形參直接用arguments 獲取實參.
* 屬性:
1.length 判斷用戶調用函數時輸入的實參個數
2.callee 指向 arguments對象 所在的這個 函數!
6. 重載:overload
重載:根據參數個數的不同,調用相同函數名函數不同的功能;
JavaScript沒有重載!不過可以根據arguments屬性的長度判斷來模擬重載.
7. 靜態成員與實例成員
7.1. 靜態成員:通過構造函數去訪問的成員
一般將工具方法,比如($.ajax)設置為靜態成員
7.2. 實例成員:通過對象去訪問的成員
一般將於對象相關的成員,比如(.css) 設置為實例成員
8. 作用域:
8.1. 詞法作用域(靜態作用域): 在代碼寫好的時候,根據代碼的書寫結構確定變量的作用域
8.2. 動態作用域: 根據代碼的調用環境確定變量的作作用域. JavaScript沒有動態作用域!!
作用域的意義:保護變量.
8.3. JavaScript代碼執行順序:
1 預解析階段:會對變量的聲明(變量只提升聲明以及函數的聲明提升到其當前作用域的頂部! 變量提升(hoisting)
* 函數形參賦值的過程是在 函數與變量提升之前
* 當兩個函數同名的時候兩個函數都會提升
* 當函數與變量同名的時候,會忽略變量聲明,只提升函數聲明
* 就算有多個script標簽,全局作用域也只有一個,但聲明提升是分段的
* 條件式函數聲明在變量提升的時候會將條件是函數聲明當做函數表達式處理只會提升函數名)
注:條件式函數聲明:在條件語句中的函數聲明
2 自上而下執行
9. 沙箱模式: JS中的沙箱模式通過函數去實現的
沙箱模式的基本模型:
(function(window){ //聲明所有需要的變量 //寫主要的功能代碼 //如果需要,就通過window對象向外界暴露接口 })(window)
9.1. 沙箱模式為什么要把window做為參數傳進去?
1. 有利於代碼壓縮,因為原生的內置對象無法被壓縮,使用形參接收后,形參是可以被壓縮的
2. 實現隔離的思想,外界不直接去使用內部的東西,內部也不直接去訪問外部的任何東西!
3. 沙箱的參數不都是window,而是如果要在沙箱內部使用沙箱外部的東西就需要把該東西當做參數,傳遞進沙箱內部!
9.2. 沙箱模式應用在哪里?
1. 框架
2. 組件
3. 插件
10. 遞歸
1 定義:在一個函數 通過名字直接或間接地調用自身
2 用遞歸解決問題的關鍵點:化歸思想.
例: 斐波那契數列第n項
function fib(n){ if(num <= 2) { return 1; } else { return fib(n - 1) + fib(n - 2); } } console.log(fib(6));
3 * 遞歸的問題:時間復雜度多,產生多次重復計算發生效率問題 ,
* 解決方案:可以使用緩存容器解決;
例: 斐波那契數列第n項
function recursive() { var arr = []; //記錄已經找到的項,作為緩存,免於遞歸重復計算 return function(n) { if (!arr[n]) { //判斷數組中有沒有這一項,有的話直接返回 if (n <= 2) { arr[n] = 1; } else { arr[n] = outer(n - 1) + outer(n - 2); } } return arr[n]; } } var fib = recursive(); console.log(fib(1000));
11. 閉包
11.1. 定義: 一個具有封閉的對外不公開的包裹結構, 或空間.(有權訪問另一個函數作用域中的變量的函數)
11.2. 概念:可以訪問獨立數據的函數
11.3. 作用:
* 1.保護數據
如果直接將數據定義全局中,那么將對數據失去控制權
使用閉包可以將數據保護起來,外界想要訪問數據,必須通過指定的渠道,而制定渠道的方法,就是建立一個函數,在函數中建立校驗機制以保證數據的合理性與安全性.
* 2.可以給函數提供私有的變量
閉包的基本模型:
function outer(){ var a = 10; var inner = { //將兩個方法封裝為一個對象 getA:function(){ //獲取數據 return a; }, setA:function(形參){ //通過傳入參數,設置數據 //可以在這建立校驗機制以保證數據的合理性與安全性 a = 形參; return a; //也可以不返回,只是設置 } } return inner; } var getFun = outer(); //先調用,再賦值,返回的是inner對象 console.log(getFun.getA()); //獲取a console.log(getFun.setA(實參)); //設置a console.log(getFun.getA()); //再次獲取的為修改后的a
實例:用延時定時器,逐個打印數字
for (var i = 0; i < 10; i++) { function outer() { var j = i; function inner() { console.log(j); } return inner; } setTimeout(outer(),1000*i); };
11.4. 閉包的問題:不合理的使用會造成內存泄露,,因為閉包的內存空間會常駐內存,造成資源損耗
12. JS是單線程的語言:
js中的任務: 在執行完主要任務之后才會執行次要任務
*主要任務(主邏輯代碼)
*次要任務(例如setTimeout()與setInterval())
13. 緩存:將數據臨時存儲起來,避免重復計算,以提高用戶訪問效率
13.1. 瀏覽器緩存:
將網站資源在瀏覽器端進行保存,用戶在請求服務器的時候,這些被保運的資源直接從本地讀取而不必去服務區讀取,從而提高用戶訪問速度;
13.2. CDN:
* CDN系統能夠實時地根據網絡流量和各節點的連接、負載狀況以及到用戶的距離和響應時間等綜合信息將用戶的請求重新導向離用戶最近的服務節點上。使用戶可就近取得所需內容,解決 Internet網絡擁擠的狀況,提高用戶訪問網站的響應速度。CDN的關鍵技術主要有內容存儲和分發技術。
* 實現原理:CDN廣泛采用各種緩存服務器,在用戶訪問網站時,利用全局負載技術將用戶的訪問指向距離最近的緩存服務器上,由緩存服務器直接響應用戶請求。
13.3. 數據庫緩存:
靜態的網站的內容都是些簡單的靜態網頁直接存儲在服務器上,可以非常容易地達到非常驚人的訪問量。但是動態網站因為是動態的,也就是說每次用戶訪問一個頁面,服務器要執行數據庫查詢,啟動模板,執行業務邏輯到最終生成一個你所看到的網頁,這一切都是動態即時生成的。從處理器資源的角度來看,這是比較昂貴的。
對於大多數網絡應用來說,過載並不是大問題。但是對於中等至大規模流量的站點來說,盡可能地解決過載問題是非常必要的。
13.4. 硬件緩存:
這是另一個領域的問題,這里暫時不做具體研究,有機會深入接觸后再作補充