函數(shù)是什么,作用域鏈

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容