摘要:關于構造函數有幾點需要特別注意構造函數允許在運行時動態的創建并編譯函數。而函數本身的表示該函數的形參。每一個函數都包含不同的原型對象,當將函數用作構造函數的時候,新創建的對象會從原型對象上繼承屬性。
該文章以收錄: 《JavaScript深入探索之路》 前言
函數是這樣的一段JavaScript代碼,它只定義一次,但是可能被執行或調用任意次。你可能已經從諸如子例程或者過程這些名字里對函數的概念有所了解。 JavaScript函數時參數化的:函數的定義會包括一個稱為形參的表示符列表,這些參數在函數體中像局部變量一樣工作。函數調用會為形參提供實參的值,函數使用它們實參的值來計算返回值,成為該函數調用表達式的值。除了實參外,每次調用還會擁有另一個值 —— 本次調用的上下文 —— 這就是this關鍵字的值。
參數有形參(parameter)和實參(argument)的區別,形參相當于函數中定義的變量,實參是運行時的函數調用時傳入的參數。
創建函數一般我們有三種方法去創建函數:
函數聲明:function foo(){}
函數表達式:var foo = function(){}
函數構造法:var foo = new Function("a","b","return a+b")
函數聲明和函數表達式1.什么是函數聲明,什么是函數表達式
ECMA規范說:函數聲明必須帶有標示符(Identifier)(就是大家常說的函數名稱),而函數表達式則可以省略這個標示符:
// 函數聲明 function 函數名(可選參數){} // 函數表達式 function 可選函數名(可選參數){}
我們可以很清楚的看出,如果沒有標識符(函數名),該函數就一定是函數表達式,如果有標識符我們該怎么區分函數聲明和函數表達式呢。
函數聲明我們不用太多的考慮,很容易看出來,我們來看看函數表達式都有哪些自然就知道哪些是函數聲明了。
第一種函數表達式:var聲明的函數我們很常見
// 沒有標識符一定是表達式 var fun = function(){} //我們還可以這樣寫 var fun = function foo(){}
第二種我們帶有標識符,但將函數賦值給變量后,該函數就成了函數表達式。在這里foo標識符在該函數體外訪問時并不起作用
var fun = function foo(a){ if(a){ console.log("外部調用了"); foo(false); //這會執行函數fun。 }else{ console.log("內部調用了"); } } fun(true); //外部調用了 ,內部調用了 foo(); // 報錯 ReferenceError: foo is not defined
我們可以看出,函數表達式中foo標識符只能在函數內部使用,去訪問該函數,在函數外部訪問不到任何東西。上面我們加判斷是為了防止函數一直遞歸。
第二種函數表達式:()括號包住的函數
// 這是函數表達式 (function foo(){})
括號包住的函數是函數表達式是因為,()是一個分組操作符,分組操作符內只能是表達式。
例如:
//Unexpected token var (var a = 0)
上面報錯,這是因為var是一個語句,而分組操作符內只能是表達式。還有我們在使用evel()時這樣寫 var ev = eval("(" + json + ")") ,這里是強制將{}解析為表達式而不是代碼塊。
2.函數聲明和函數表達式的特點
函數聲明在我們的代碼執行前,會被整個提升,也就是說我們在函數聲明之前就可以調用該函數,而函數表達式不能夠被提升。
a() // 結果 我是函數a" function a(){ console.log("我是函數a"); } fun() //結果 fun is not a function var fun = function b(){ console.log("我是函數b"); }
為什么會出現這種情況我們在以后的文章中會詳細的討論。同時,我們應該養成一種習慣,盡量不要在函數聲明之前使用函數。這只是一種良好的代碼書寫習慣。
其次我們需要注意的是在if判斷語句中我們不應該出現函數聲明,即便是沒有報錯,也是不推薦這樣去寫的。
立即執行函數(表達式)和自執行函數1. 立即執行函數(表達式)
我們來看一下:
(function (){ console.log("one"); })(); (function (){ console.log("two"); }());
上邊兩個函數都可以自己去執行,而值有個共同的特點就是括號左邊的函數必須是一個函數表達式,而不是函數聲明。
// 如果括號左邊是函數聲明,報錯 function fun(){ console.log() }() // 括號左邊是函數時表達式,(函數表達式都可以自執行) var F = function(){ return 10; }(); true && function (){}(); 0 , function (){}(); //你甚至看還可以這樣 !function () { /* code */ } (); ~function () { /* code */ } (); -function () { /* code */ } (); +function () { /* code */ } (); new function(){}();
其實上邊的些自執行函數表達式我們為了方便我們的閱讀我們一般會用到第一個和第二個,當然如果你非要搞個性化,使用其他的也是可以。只不過你的代碼并不美觀,后期也不容易維護。
2. 什么是自執行函數,像這樣
function fun1(){ //code } fun1(); function fun2(){ fun2() // 遞歸 } // 這是一個自執行匿名函數 var foo = function () { arguments.callee(); };
看了這些例子,我們應該清楚了什么是自執行,什么是立即調用。
函數構造器Function()構造函數并不需要通過傳入實參以指定函數名,就像函數直接量一樣,Function()構造函數創建一個匿名函數。
關于Function()構造函數有幾點需要特別注意
Function()構造函數允許JavaScript在運行時動態的創建并編譯函數。
Function()構造函數每次執行時都會解析函數主體,并創建一個新的函數對象,所以當在一個循環或頻繁執行的函數中調用Function()構造函數效率是非常低的。而函數字面量(函數表達式)卻不是每次遇到都會重新編譯的,用Function()構造函數創建一個函數時并不遵循典型的作用域,它一直把它當作是頂級函數來執行
它所創建的函數并不是使用詞法作用域,相反,函數體代碼的編譯總是會在頂層函數執行,
用函數構造器創建的函數不會在上下文中創建閉包,它們總是被創建在全局作用域中,當執行被創建的函數時,它們只能使用自己的局部變量或者全局變量。例如下面:
var scop = "global"; function fun(){ var scop = "fun"; return new Function("return scope") // global }函數的屬性、方法和構造函數
1. length屬性
函數體中,arguments.length表示傳入函數的實參個數。而函數本身的length表示該函數的形參。
function fun(x,y,z){ console.log(arguments.length);// 2 console.log(arguments.callee.length); //3 } fun(1,2);
我們這里提一下,在函數中的arguments,函數中arguments包含所用實參,它并不是一個真正的數組,而是一個實參的對象。另外他還有兩個特別的屬性callee和caller屬性。
callee屬性只帶黨慶正在執行的函數。
caller屬性時非標準的,但大多數瀏覽器都實現了這個屬性它指帶調用當前正在執行的函數的函數。
通過caller屬性可以訪問調用棧。callee屬性在某些時候會非常的有用,比如在匿名函數中通過callee來遞歸調用自身,上面我們已經提到過。
2. prototype屬性
每一個函數都包含一個prototype屬性,這個屬性是指向一個對象的引用,這個對象稱作"原型對象"。每一個函數都包含不同的原型對象,當將函數用作構造函數的時候,新創建的對象會從原型對象上繼承屬性。
3. call()方法和apply()方法
call 和 apply 是為了改變某個函數運行時的 context 即上下文而存在的,換句話說,就是為了改變函數體內部 this 的指向。因為 JavaScript 的函數存在「定義時上下文」和「運行時上下文」以及「上下文是可以改變的」這樣的概念。
它們的用法也是很簡單的。例如:
var obj = { msg:"我是obj對象", fun:function(){ console.log(this.msg); }, } var objTwo = { msg:"我是objTwo對象" }; // 這里我們想讓通過objTwo 對象調用 obj對象的fun方法, // 此時obj的fun方法中的this已經改變了指向。 obj.fun.call(objTwo) // 我是objTwo對象
call 和 apply 的區別在于他們傳參的形式不同:
var obj = { msg:"我是obj對象", fun:function(one,two){ console.log(this.msg); console.log("我是參數:"+ one + "," +two); }, } var objTwo = { msg:"我是objTwo對象" }; // 這里我們想讓通過objTwo 對象調用 obj對象的fun方法, // 此時obj的fun方法中的this已經改變了指向。 obj.fun.call(objTwo,1,2) // 我是objTwo對象 ,我是參數:1,2 obj.fun.apply(objTwo,[1,2]) // 我是objTwo對象 ,我是參數:1,2高階函數
所謂高階函數就是操作函數的函數,它接收一個或多個函數作為參數,并返回一個新函數。我們來看一個例子:
這個例子的主要作用是,fun函數接收f()和g()兩個函數,并返回一個新的函數用以計算f(g())
function fun(f,g){ return function(){ return f.call(this,g.apply(this,arguments)); } } var square = function(x){ return x * x } var sum = function(x,y){ return x + y; } var suqareOfSum = compose(square,sum) squareOfSum(2,3) // 25
在這里函數fun() 就是高階函數。
不完全函數不完全函數是一種函數變換技巧,即把一次完整的函數調用折成多次函數調用,每次傳入的實參都是完整實參的一部分,每個拆分開的函數叫做不完全函數,每次函數調用叫做不完全調用,這種函數變換的特點是每次調用都反一個函數,知道得到最終運行結果為止,例如:將函數f(1,2,3,4,5)的調用修改為等價的f(1,2)(3,4)(5)后者包含三次調用,和每次調用相關的函數就是 不完全函數”。
結束參考文獻: 《JavaScript權威指南》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89706.html
摘要:看著別人寫的功能對,就直接拿過來用,寫出來的代碼臃腫到爆炸,滿屏幕的的初級使用方式,運氣好了能湊合跑起來,出了問題全臉懵逼,心中安慰自己一萬遍我可是干設計的,但是既然打算好好整下就得從頭開始看了。 溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命 首先,說實話,我對不起javascript,作為一個接觸前端快10年的老前端(偽),一直發揚的是不求甚解的拿來就用主義。看...
摘要:原理探索模塊系統是什么拋出組件化的概念后,對于開發者而言,為了提高代碼的可讀性與結構性,通過文件目錄結構去闡述組件嵌套關系無疑是一個很好的辦法,但是目錄級別的加深,同時讓的文件路徑讓人頭疼。 React原理探索- @providesModule 模塊系統 @providesModule是什么 react拋出組件化的概念后,對于開發者而言,為了提高代碼的可讀性與結構性,通過文件目錄結構去...
摘要:溫馨提示作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命溫馨提示續本文將會成為一篇筆記類型的文章,記錄閉包具體的應用方式溫馨提示再續本文存在錯誤,會慢慢改進的,請不要把我說的當真在上一篇博文閉包不完全探索記錄閉包啥餡的中,對中 溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命溫馨提示-續:本文(maybe)將會成為一篇筆記類型的文章,記錄閉包具體的應用方式溫馨...
摘要:模塊化編程,已經成為一個迫切的需求。隨著網站功能逐漸豐富,網頁中的也變得越來越復雜和臃腫,原有通過標簽來導入一個個的文件這種方式已經不能滿足現在互聯網開發模式,我們需要團隊協作模塊復用單元測試等等一系列復雜的需求。 隨著網站逐漸變成互聯網應用程序,嵌入網頁的Javascript代碼越來越龐大,越來越復雜。網頁越來越像桌面程序,需要一個團隊分工協作、進度管理、單元測試等等......開發...
摘要:因為瀏覽器環境里是單線程的,所以異步編程在前端領域尤為重要。除此之外,它還有兩個特性,使它可以作為異步編程的完整解決方案函數體內外的數據交換和錯誤處理機制。 showImg(https://segmentfault.com/img/bVz9Cy); 在我們日常編碼中,需要異步的場景很多,比如讀取文件內容、獲取遠程數據、發送數據到服務端等。因為瀏覽器環境里Javascript是單線程的,...
閱讀 2064·2021-09-22 15:43
閱讀 8618·2021-09-22 15:07
閱讀 1078·2021-09-03 10:28
閱讀 2052·2021-08-19 10:57
閱讀 1061·2020-01-08 12:18
閱讀 2972·2019-08-29 15:09
閱讀 1521·2019-08-29 14:05
閱讀 1640·2019-08-29 13:57