js學習(4) 函數
JavaScript有三種聲明函數的方法
(1)function命令
function print(s) { console.log(s); }
(2)函數表達式
1.var print = function(s) { console.log(s); }; 2.var print = function x(){ console.log(typeof x); }; x // ReferenceError: x is not defined print() // function 3.var f = function f() {};
將匿名函數賦予變量,如果不匿名,也只在內部有效
函數表達式定義函數最後要加上分號代表結束
(3)Function構造函數
可以傳遞任意數量的參數給Function構造函數,但只有最後一個參數被當做函數體
Function構造函數可以不使用new命令,返回結果完全一樣
var add = new Function( ‘x‘, ‘y‘, ‘return x + y‘ ); // 等同於 function add(x, y) { return x + y; }
此方法比較不常用 第一種方法倒更熟悉
如果一個函數被多次聲明,後面的聲明就會覆蓋前面的聲明
調用函數時和其他語言大致相同,使用圓括號運算符
第一等公民
Js把函數看成一種值,與其他值(數值,字符串,布爾值等)地位相同
凡是可以使用值的地方,就能使用函數,函數只是一個可以執行的值
function add(x, y) { return x + y; } // 將函數賦值給一個變量 var operator = add; // 將函數作為參數和返回值 function a(op){ return op; } a(add)(1, 1) // 2
函數提升
函數的屬性和方法
name屬性:返回函數名字 如果采用表達式定義函數,且function後有名字,則返回那個名字
length屬性:返回函數預期傳入的參數個數
toString():返回一個字符串,內容是函數的源碼,以及註釋
對於var命令來說,局部變量只能在函數內部聲明,在其他區塊中聲明,一律都是全局變量
函數內部也有變量提升,var命令聲明的對象,不管在什麽位置,變量聲明都會被提升到函數體的頭部
函數本身的作用域
函數本身作用域就是聲明時所在的作用域,與運行時所在作用域無關
在定義時綁定作用域
var a = 1; var x = function () { console.log(a); }; function f() { var a = 2; x(); } f() // 1
函數的參數
可以省略,但沒辦法只省略靠前的參數,而保留靠後的參數,如果一定要省略靠前的參數,只有顯式傳入undefined
參數傳遞對原值的影響
如果是原始類型的值,無影響,只是一份拷貝
如果傳入的是對象,則修改其屬性的話,原值會受到影響
但把對象整個替換掉,不會影響原始值,因為相當於指向其他地址
同名參數
如果有同名參數,則取最後出現的那個值
function f(a, a) { console.log(a); //a為最後一個a } f(1) // undefined 相當於f(1,undefined)
arguments對象
由於js允許函數提供不定數目的參數,所以需要一種機制,可以在函數體內部讀取所有參數,這就是arguments對象的由來
arguments對象包含函數運行時所有參數,使用類似數組
如果在非嚴格模式下還可以在函數內部修改參數的值,嚴格模式下只讀
通過它的length屬性,可以判斷函數調用時到底帶了幾個參數
與數組關系:
是對象,不能使用數組方法,除非轉換為數組
var args = Array.prototype.slice.call(arguments); // 或者 var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); }
arguments自帶一個callee屬性1,返回它所對應的原函數
函數的閉包
閉包即能夠讀取其他函數內部變量的函數,可以簡單理解為“定義在一個函數內部的函數”
用處:1.讀取函數內部變量 2.記住誕生的環境
function createIncrementor(start) { return function () { return start++; }; } var inc = createIncrementor(5); inc() // 5 inc() // 6 inc() // 7
3.封裝對象的私有屬性和方法,感覺像類
function Person(name) { var _age; function setAge(n) { _age = n; } function getAge() { return _age; } return { name: name, getAge: getAge, setAge: setAge }; } var p1 = Person(‘張三‘); p1.setAge(25); p1.getAge() // 25
立即調用的函數表達式,聲明時就調用(IIFE)
(function(){ /* code */ }()); // 或者 (function(){ /* code */ })();
所以以下寫法都行
var i = function(){ return 10; }(); true && function(){ /* code */ }(); 0, function(){ /* code */ }(); !function () { /* code */ }(); ~function () { /* code */ }(); -function () { /* code */ }(); +function () { /* code */ }();
通常只對匿名函數使用
目的:1.不必命名,避免汙染全局變量 2。在IIFE內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量
eval命令
eval命令接受一個字符串作為參數,並將這個字符串當做語句執行
eval(‘var a = 1;‘); a // 1
如果無法執行就報錯
如果eval的參數不是字符串,那麽會原樣返回
eval的作用域是當前作用域,因此小心修改當前作用域變量的值
eval本質是在當前作用域中註入代碼,由於安全風險和不利於js引擎優化執行速度,一般不推薦使用
最常用的場合是解析json數據的字符傳你,不過正確做法應該使用原生的JSON.parse方法
js規定,凡是使用別名執行eval,eval內部一律是全局作用域
var a = 1; function f() { var a = 2; var e = eval; e(‘console.log(a)‘); } f() // 1
js學習(4) 函數