摘要:函數表達式定義函數表達式區別于函數聲明,也是一種定義函數的方式,形似與變量賦值,這個值就是函數體,例如函數表達式之匿名函數函數表達式之具名函數匿名函數之立即執行函數目前知道的是這三種形式,希望高人補充特點區別于函數聲明,和普通變量一樣使用前
函數表達式
定義:函數表達式區別于函數聲明,也是一種定義函數的方式,形似與變量賦值,這個值就是函數體,例如:
var a = function(){}; // 函數表達式之匿名函數 var a = function fn(){}; // 函數表達式之具名函數 (function(){})(); // 匿名函數之立即執行函數 // 目前知道的是這三種形式, 希望高人補充
特點:
1 . 區別于函數聲明,和普通變量一樣使用前必須聲明,不聲明在非嚴格模式下被認為是全局的變量,在嚴格模式下報錯
定義:在一個函數中調用自身,遞歸必須要有結束條件階乘
// fibonacci數列 function fibonacci(n){ if(n == 1 || n == 2){ // 結束條件 return 1; }else{ var num = fibonacci(n-1) + fibonacci(n-2); // 遞歸調用 return num // 每一層遞歸都返回和 } }; console.log(fibonacci(6)); // 8
特點:
1 . 調用匿名函數表達式自身,為了便于維護,可以通過arguments.callee(指向當前函數的指針)來調用當前函數,這樣做的好處是當遞歸函數換名稱時不用更換內部的函數名稱
function fibonacci(n){ if(n == 1){ return 1; }else{ var num = arguments.callee(n-1) * n ; return num } }; let a = fibonacci; fibonacci = null; console.log(a(6)); // 函數內在再次調用fibonacci就會報錯 Uncaught TypeError: fibonacci is not a function
一變
function fibonacci(n){ if(n == 1){ return 1; }else{ var num = arguments.callee(n-1) * n ; return num } }; let a = fibonacci; fibonacci = null; console.log(a(6)); // 720 但是在嚴格模式下回報錯 Uncaught TypeError: "caller", "callee", and "arguments" properties may not be accessed
二變
"use strict"; let a = (function fibonacci(n){ if(n == 1){ return 1; }else{ var num = fibonacci(n-1) * n ; return num } }); let b = a; a=null; console.log(b(4)); // 24 ,這里相當于包了一層,如果外邊的變量改變是不會影響函數內部調用的
注:在嚴格模式下arguments.callee會報錯,可以通過命名函數表達式來實現
閉包閉包是指有權訪問另一個作用域中的變量的函數,形式很多,不舉例了,重點在下面
特點:關于閉包的特點都得先理解執行環境、作用域、活動對象的概念
執行環境: 函數被調用時會創建當前函數的執行環境,可以想象成一個對象,對象包含一個屬性,該屬性指向作用域(作用域鏈表)
作用域,也可以看成是作用域鏈表,一個list,list的元素是指向活動對象,包括本作用域內的活動對象的指向和對上級的指向,當前函數執行完畢作用域就消失了
活動對象,包含當前函數內的所有屬性,當沒有作用域鏈引用時活動對象被銷毀
注:指向可以理解為引用,像 a=[], a就指向了內存中的一個數組
{ scope: scopeList ----| } | 執行環境(context) | [ | activeObj1: activeObjects1, --|--| activeObj2: activeObjects2, --|--|--| ... | | | ] | | | 作用域鏈(scopeList) <----| | | { | | var1: 1, | | var2: 1, | | var1: [], | | } | | 活動對象(activeObjects1) <--| | { | _var1: 1, | _var2: 1, | _var1: [], | } | 活動對象(activeObjects2) <--| // 可以看出執行環境和作用域鏈是一對一的, 所以當執行完函數后執行環境就沒了,作用域沒有被引用了就也沒了,但是活動對象和作用域鏈是多對多的(途中只展示了一對多) ,所以就算作用域沒了,當前作用域的活動對象也可能被其它作用域引用(例如閉包),所以仍然存在于內存中閉包與變量
特點:閉包對外層活動對象是引用不是復制(也可以說是復制了引用),這里寫一個親身經歷的筆試題
var nAdd = null; function f(){ let n = 99; nAdd = () => { ++n; } return () => { console.log(n); } }; var f1 = f(); var f2 = f(); nAdd(); f1(); f2(); nAdd(); f1(); f2();
我認為這個題挺有意思。這里不給答案,讀者可以自己先猜一下,然后自己跑一下和自己的猜想對對。
我認為這個題目的關鍵在nAdd是在f函數的外層,也就是每次實例化這個f函數都會對nAdd重新賦值,重新賦值后執行環境中n會不同,多次賦值取最后一個,只要能搞清楚執行環境、作用域、活動對象的關系其實不難,不會也沒關系,一開始看到我也懵。
定義:this是和執行環境綁定的
特點:特點和定義息息相關,this和執行環境綁定,只要執行完畢執行環境不存在了就,例如:
var name = "china,hebei"; var province = { name: "hebei", getName: function(){ return function(){ return this.name; }; } }; console.log(province.getName()()); // china,hebei
從結果來看this指的是全局的那個this,這個和常規理解不太一樣,按說getName屬于province這個對象,this指向province才對,想想定義就明白了,province.getName()這個執行了getName函數,并返回了一個函數體,再次執行這個函數體的時候getName()已經執行完了,執行完了執行環境當然就不存在了,this就返回給執行的環境(全局環境),那如何改成指向province呢?
var name = "china,hebei"; var province = { name: "hebei", getName: function(){ let that = this; return function(){ return that.name; }; } }; console.log(province.getName()()); // hebei
很容易理解,that在getName執行完畢后并不會消失,因為它所在的活動對象還被最后返回的函數的作用域鏈引用著,所以最后輸出的就是hebei
塊級作用域
定義:通過創建一個立即執行函數來模仿模塊作用域的效果,普通的{}沒有塊級概念
for(var i=0; i<2; i++){ console.log(i); } console.log(i) // 2
塊級作用域,很簡單,通過函數作用域封裝一層即可,例如
(function(){ for(var i=0; i<2; i++){ console.log(i); } })() console.log(i) // Uncaught ReferenceError: i is not defined私有變量
定義:在函數定義的變量和方法都可以看成是私有變量,可以通過在函數創建閉包實現在函數外部訪問私有變量,稱之為共有方法(特權方法),例如:
function Student(){ var name = "jiang"; this.getName = function(){ return name; }; }; var xiaoming = new Student(); console.log(xiaoming.getName()); // jiang 只有這種特權方法可以訪問到
特點:私有變量只能通過特權方法在函數外部被訪問
解決的問題:增強函數的封裝性,函數作用域內得變量只能通過特權方法訪問
帶來的問題:每個實例都會重新創建一個特權方法
定義: 在私有作用域內(立即執行函數)定義函數內的私有變量和全局的(變量沒有聲明就賦值時)匿名函數,為匿名函數添加原型方法,原型方法內訪問函數內的變量,這樣在函數外部可以可以通過變量名稱直接訪問全局的匿名函數上的原型方法,方法內部可以訪問函數私有變量
(function(){ let name = "jiang"; student = function(){}; student.prototype.getName = function(){ return name; }; })() console.log(student.prototype.getName()); // jiang
解決的問題:解決了每個實例都不共享的私有變量和特權方法的問題
帶來的問題:解決的問題也變成了它自身的問題,最好的方案是私有變量和靜態私有變量結合使用
模塊模式定義:模塊模式就是把私有變量和單例模式結合起來,在JS中通過字面對象來創建對象是最簡單的單例模式,而私有變量是函數作用域被的,方法就是定義一個變量(單例對象),然后創建一個立即執行函數返回一個字面對象,對象內部創建公共的特權方法和屬性,函數內部定義私有變量。
單例模式,例如
var a = {}; var a = {}; // 總是只有一個a對象
var a = (function(){ var name = "jiang"; // 私有變量 return{ // 單例模式 getName: function(){ return name; } } })() console.log(a.getName());
解決的問題:在單例內創建私有變量, 單例模式的應用場景是需要重復使用但不需要同時使用的對象,像錯誤提示彈框
帶來的問題:返回的對象是沒有類型的就是不能通過instanceof確認對象類型
增強版的模塊模式
定義:將函數內返回的對象通過構造函數的方式聲明,然后為其添加特權方法和屬性,然后將對象返回,這樣的對象就可以通過instanceof確認其類型了
var a = (function(){ var name = "jiang"; function Student(){}; var xiaoming = new Student(); xiaoming.getName = function(){ return name; }; return xiaoming; })()
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100574.html
摘要:要理解立即執行函數,需要先理解一些函數的基本概念。函數表達式使用關鍵字聲明一個函數,但未給函數命名,最后將匿名函數賦予一個變量,叫函數表達式,這是最常見的函數表達式語法形式。 javascript和其他編程語言相比比較隨意,所以javascript代碼中充滿各種奇葩的寫法,有時霧里看花,當然,能理解各型各色的寫法也是對javascript語言特性更進一步的深入理解。 ( functio...
摘要:將匿名函數賦予一個變量,叫函數表達式,這是最常見的函數表達式語法形式。組成這是一個被稱為自執行匿名函數的設計模式,主要包含兩部分。 一、函數聲明&函數表達式 1.1 函數聲明 (函數語句) showImg(https://segmentfault.com/img/bVbbqvT?w=278&h=166); (1)使用 function 關鍵字聲明一個函數,再指定一個函數名,叫函數聲明。...
摘要:對象數組初始化表達式,闖關記之上文檔對象模型是針對和文檔的一個。闖關記之數組數組是值的有序集合。數組是動態的,根闖關記之語法的語法大量借鑒了及其他類語言如和的語法。 《JavaScript 闖關記》之 DOM(下) Element 類型 除了 Document 類型之外,Element 類型就要算是 Web 編程中最常用的類型了。Element 類型用于表現 XML 或 HTML 元素...
摘要:函數表達式對于函數聲明,函數的名稱是必須的,而對于函數表達式而言則是可選的,因此,就出現了匿名函數表達式和命名函數表達式。這是因為對命名函數處理的機制,函數的名稱永遠在函數內部的作用域中有效。 function 是 Javascript 中的第一類對象,這就意味著函數可以像其他值一樣被傳遞。一個最常見的用法就是將一個匿名函數作為回調函數傳遞到另外一個異步函數中。 函數聲明 func...
摘要:和是兩種立即執行函數的常見寫法,最初我以為是一個括號包裹匿名函數,再在后面加個括號調用函數,最后達到函數定義后立即執行的目的,后來發現加括號的原因并非如此。 javascript和其他編程語言相比比較隨意,所以javascript代碼中充滿各種奇葩的寫法,有時霧里看花,當然,能理解各型各色的寫法也是對javascript語言特性更進一步的深入理解。 ( function(){…} )...
摘要:字面形式允許你在不需要使用操作符和構造函數顯式創建對象的情況下生成引用值。操作符以一個對象和一個構造函數作為參數鑒別數組有前一小結可以知道鑒別數組類型可以使用。屬性是函數獨有的,表明該對象可以被執行。這種函數被稱為匿名函數。 引子: 1.JavaScript 中的變量類型和類型檢測 1.1原始類型 1.2引用類型 1.3內建類型的實例化 1.4函數的字面形式 1.5正則表達式的字...
閱讀 2885·2021-10-26 09:49
閱讀 3221·2021-10-14 09:42
閱讀 2042·2021-09-13 10:31
閱讀 2580·2019-08-30 11:13
閱讀 2962·2019-08-29 16:31
閱讀 1068·2019-08-29 13:58
閱讀 1859·2019-08-29 12:12
閱讀 3556·2019-08-26 13:48