JavaScript函數(shù)是指一個特定代碼塊,可能包含多條語句,可以通過名字來供其它語句調(diào)用以執(zhí)行
函數(shù)包含的代碼語句。
比如我們有一個特定的功能需要三條語句實現(xiàn)
statement1;
statement2;
statement3;
那么每次想實現(xiàn)這個功能的時候就需要寫這三句話,很麻煩,我們可以把這三條語句打包為一個函數(shù)
function doSomething(){ 函數(shù)的命名一般用動詞,兩個單詞用駝峰
statement1;
statement2;
statement3;
}
這樣每次想實現(xiàn)功能的時候我們就調(diào)用一下函數(shù)就可以了,調(diào)用函數(shù)通過函數(shù)名稱()的形式調(diào)用
doSomething();
聲明函數(shù)
使用function關(guān)鍵字可以聲明一個函數(shù)
//函數(shù)聲明
function sayHello(){
console.log('hello')
}
//函數(shù)調(diào)用
sayHello()
聲明不必放到調(diào)用的前面
函數(shù)表達式
var sayHello = function(){
console.log('hello');
}
sayHello()
聲明必須放到調(diào)用的前面
參數(shù)
function sayHello(name){
console.log('hello ' + name)
}
sayHello('若愚')
sayHello('饑人谷)
多個參數(shù)
函數(shù)在定義的時候可以寫多個參數(shù)
function printInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
}
printInfo('饑人谷', 2, 'boy')(其實并不能一一對應(yīng))
arguments
在函數(shù)內(nèi)部,你可以使用arguments對象獲取到該函數(shù)的所有傳入?yún)?shù)
function printPersonInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
console.log(arguments);
}
重載
其他語言重載范例:例如C語言中的
int sum(int num1, int num2){ 整數(shù)
return num1 + num2;
}
float sum(float num1, float num2){ 浮點數(shù)
return num1 + num2;
}
sum(1, 2);
sum(1.5, 2.4);
在 JS 中
沒有重載! 同名函數(shù)會覆蓋。 但可以在函數(shù)體針對不同的參數(shù)調(diào)用執(zhí)行相應(yīng)的邏輯
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);
printPeopleInfo('Byron', 26, 'male');
返回值
有時候我們希望在函數(shù)執(zhí)行后得到一個結(jié)果供別人使用,可以通過return來實現(xiàn)
function sum(a, b){
a++;
b++;
return a + b;
}
var result = sum(2, 3);
conslole.log(result);
注意點
如果不寫return語句,函數(shù)也會默認給我們返回undefined
注意點2
函數(shù)在執(zhí)行過程中,只要遇到return就會立即結(jié)束退出函數(shù)體
function fn(a){
if(a < 0){
return;
}
//下面沒用 else ,但效果一樣
a++;
return a + a;
}
注意點3
函數(shù)的返回值和 console.log()是兩個不同的東西,千萬不要這樣
function getAge(age){
return console.log(age);
}
console.log()作用是我們?nèi)フ{(diào)試代碼,是把東西展示出來
聲明前置
var 和 function 的聲明前置
在一個作用域下,var 聲明的變量和function 聲明的函數(shù)會前置
console.log(a); //undefined
var a = 3;
console.log(a); //3
sayHello();
function sayHello(){
console.log('hello');
}
函數(shù)表達式
console.log(fn); //undefined
fn(); //報錯
var fn = function(){}
函數(shù)表達式和 var 一個變量沒什么區(qū)別
先有,再 用
函數(shù)內(nèi)部的聲明前置
function fn(){
console.log(a) //undefined
var a = 3
console.log(a)
}
fn()
當命名沖突時
先 前置,再 覆蓋
var fn = 3;
function fn(){}
console.log(fn); // 3
function fn(){}
var fn = 3;
console.log(fn); // 3
參數(shù)重名
function fn(fn){
console.log(fn);
var fn = 3;
console.log(fn);
}
fn(10); //10 3
作用域
在 JS 中只有函數(shù)作用域,沒有塊作用域
function fn(){
var a =1;
if(a > 2){
var b = 3;
}
console.log(b);
}
fn(); // undefined
console.log(a); // "ReferenceError: a is not defined
var
聲明一個已經(jīng)存在的變量
function fn(){}
var fn
console.log(fn)
var a = 1
var a
var a
console.log(a)
var重復(fù)聲明一個已經(jīng)存在的變量,原變量值不變
不加var作用
function fn(){
a = 1;
}
fn();
console.log(a); // 1
可以看到不寫var會聲明一個全局的變量,這是我們在編程中應(yīng)該要避免的,即使真的需要全局變量,也應(yīng)該在最外層作用域使用var聲明
更深入了解,參考下一節(jié) 作用域鏈
遞歸
自己調(diào)用自己
設(shè)定終止條件
優(yōu)點: 算法簡單
缺點: 效率低
求 n 的階乘 n!
function factor(n){
if(n === 1) {
return 1
}
return n * factor(n-1)
}
factor(5)
求 1+2+...+n 的值
function sum(n){
if(n === 1) {
return 1
}
return n + sum(n-1)
}
sum(10)
立即執(zhí)行函數(shù)表達式
(function(){ 用小括號,里面相當于 一個表達式
var a = 1;
})()
console.log(a); //undefined
作用: 隔離作用域
其他寫法
(function fn1() {});
// 在數(shù)組初始化器內(nèi)只能是表達式
[function fn2() {}];
// 逗號也只能操作表達式
1, function fn3() {};
作用域鏈
相關(guān)概念
執(zhí)行上下文 executionContext
活動對象 AO
Scope 屬性
執(zhí)行順序
范例1
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo() // 輸出什么
}
globalContext = {
AO: {
x: 10
foo: function
bar: function
},
Scope: null
}
//聲明 foo 時 得到下面
foo.[[scope]] = globalContext.AO
//聲明 bar 時 得到下面
bar.[[scope]] = globalContext.AO
注意: 在當前的執(zhí)行上下文內(nèi)聲明的函數(shù),這個函數(shù)的[[scope]]就執(zhí)行當前執(zhí)行上下文的 AO
范例2
var x = 10;
bar() // 輸出什么
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
//聲明 bar 時 得到下面
bar.[[scope]] = globalContext.AO
注意: 在當前的執(zhí)行上下文內(nèi)聲明的函數(shù),這個函數(shù)的[[scope]]就執(zhí)行當前執(zhí)行上下文的 AO
當調(diào)用 bar() 時, 進入 bar 的執(zhí)行上下文
barContext = {
AO: {
x: 30,
foo: function
},
Scope: bar.[[scope]] //globalContext.AO
}
//在 bar 的執(zhí)行上下文里聲明 foo 時 得到下面
foo.[[scope]] = barContext.AO
當調(diào)用 foo() 時,先從 bar 執(zhí)行上下文中的 AO里找,找到后即調(diào)用
當調(diào)用 foo() 時,進入 foo 的執(zhí)行上下文
fooContext = {
AO: {},
Scope: foo.[[scope]] // barContext.AO
}
所以 console.log(x)是 30