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