進(jìn)階任務(wù)3 函數(shù)和作用域鏈 作業(yè)

1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別

函數(shù)聲明

使用 function 關(guān)鍵字聲明一個函數(shù)

//函數(shù)聲明
function sayHello(){
    console.log('hello')
}

//函數(shù)調(diào)用
sayHello()

聲明不必放到調(diào)用的前面,但是不要放到其它函數(shù)中。

函數(shù)表達(dá)式

var sayHello = function(){
    console.log('hello');
}

sayHello()

<span style="color:red">用函數(shù)表達(dá)式聲明函數(shù)必須放到調(diào)用的前面。</span>函數(shù)表達(dá)式是內(nèi)容為函數(shù)聲明的表達(dá)式,類似 a++ 為內(nèi)容為變量運(yùn)算的表達(dá)式,而 a++ 需要事先聲明 a 且確定 a 的值,因此同理函數(shù)表達(dá)式聲明必須放置在調(diào)用的前面。

函數(shù)也是一種引用類型,函數(shù)表達(dá)式的寫法就是把函數(shù)指針賦值給了 sayHello 變量。

為什么叫函數(shù)表達(dá)式?
因?yàn)楸磉_(dá)式其本質(zhì)是一個值,是一坨東西最終計算出一個結(jié)果即一個值;而這種寫法就是將一坨東西賦值給變量,就是將一個值賦值給變量,所以稱為函數(shù)表達(dá)式。
函數(shù)聲明的寫法就不是表達(dá)式,而是單純函數(shù)的語句。




2. 什么是變量的聲明前置?什么是函數(shù)的聲明前置

var 和 function 的聲明前置

在一個作用域下,var 聲明的變量和 function 聲明的函數(shù)會前置.
首先將所有 var variableName 前置(不包括變量賦值部分);
其次將所有 function functionName(){} 前置(包括函數(shù)定義部分)
例如:

console.log(a); //undefined
var a = 3;
console.log(a); //3

sayHello();

function sayHello(){
  console.log('hello');
}

代碼的實(shí)際的執(zhí)行順序?yàn)椋?/p>

var a;
function sayHello() { console.log('hello'); }

console.log(a);
a = 3
console.log(a);
sayHello()

3. 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);
}   

arguments 是一個類數(shù)組對象,可用 arguments[0] 等來標(biāo)識各個參數(shù),也可以調(diào)用 length 屬性來顯示對象中屬性的數(shù)量,但是也沒有了一些數(shù)組的屬性。


4. 函數(shù)的"重載"怎樣實(shí)現(xiàn)

C語言重載范例

int sum(int num1, int num2){
  return num1 + num2;
}

float sum(float num1, float num2){
  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');

5. 立即執(zhí)行函數(shù)表達(dá)式是什么?有什么作用

(function(){
  var a  = 1;
})()
console.log(a); //undefined

作用: <span style="color:red">隔離作用域</span>,避免和全局變量發(fā)生沖突。
包裹函數(shù)定義語句的括號使得 JS 解析器認(rèn)為括號內(nèi)是一個表達(dá)式,而不是一個函數(shù)聲明語句。

其他寫法

(function fn1() {});
 
// 在數(shù)組初始化器內(nèi)只能是表達(dá)式
[function fn2() {}];
 
// 逗號也只能操作表達(dá)式,逗號兩邊也被認(rèn)為是表達(dá)式
1, function fn3() {};

// !號也可以寫成立即表達(dá)式的方法
!function(){
    var a = 1;
}()

6. 求n!,用遞歸來實(shí)現(xiàn)

function recursive(n) {
    if (n == 1) {
        return 1;
    } else {
        return n * (n-1);
    }
}

7. 以下代碼輸出什么?

function getInfo(name, age, sex){
    console.log('name:',name);
    console.log('age:', age);
    console.log('sex:', sex);
    console.log(arguments);
    arguments[0] = 'valley';
    console.log('name', name);
}
getInfo('饑人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');

輸出:

name: 饑人谷
age: 2
sex: 男
["饑人谷",2,"男"] // 別漏了作字符串標(biāo)記的引號
name valley

name: 小谷
age: 3
["小谷",3]
name valley

name: 男
[男]
name valley

8. 寫一個函數(shù),返回參數(shù)的平方和?

function sumOfSquares(){
    var sumOfSquares = 0;
    for(var i = 0; i < arguments.length; i++){
        sumOfSquares += arguments[i] * arguments[i];
    }
    return sumOfSquares;
}

var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result) //10

9. 如下代碼的輸出?為什么

console.log(a); // undefined
var a = 1;
console.log(b); // Uncaught ReferenceError

代碼的執(zhí)行順序?yàn)椋?/p>

var a;
console.log(a); //undefined,此時變量 a 已經(jīng)聲明,但是并未賦值,所以顯示 undefined,表示未定義,此處目前沒有任何值
a = 1;
console.log(b); //Uncaught ReferenceError,此時出現(xiàn)了錯誤,因?yàn)樽兞?b 并未被聲明,所以 JS 解析器將會顯示出現(xiàn)了搓球


10. 如下代碼的輸出?為什么

sayName('world');
sayAge(10);
function sayName(name){
    console.log('hello ', name);
}
var sayAge = function(age){
    console.log(age);
};

代碼實(shí)際執(zhí)行順序:

function sayName(name){
    console.log('hello ', name);
}

sayName('world'); 
// hello world
// 由于函數(shù)聲明會被前置到代碼首部,所以此語句正常運(yùn)行
sayAge(10); 
// Uncaught TypeError
// 用函數(shù)表達(dá)式的方式來聲明函數(shù),JS 解析器會認(rèn)為這是一個表達(dá)式而非函數(shù)聲明
// 所以這樣聲明的函數(shù)不會被聲明前置
// 所以在調(diào)用 sayAge 時 JS 解析器會認(rèn)為函數(shù)未被聲明,顯示錯誤
var sayAge = function(age){
    console.log(age);
};

輸出:
hello world
Uncaught TypeError


11. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼

var x = 10
bar() 
function foo() {
  console.log(x)
}
function bar(){
  var x = 30
  foo()
}

12. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼

var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}
作用域鏈如下:
globalContext = {
    AO: {
        x: 10,
        bar: function
    }
    Scope: null
}
// 聲明 bar 函數(shù)時,生成其作用域鏈如下
bar.[[scope]] = globalContext.AO


barContext = {
    AO: {
        x: 30,
        foo: function
    }
    scope: globalContext
}
// 聲明 foo 函數(shù)時,生成其作用域鏈如下
foo.[[scope]] = barContext.AO


fooContext = {
    AO: {}
    Scope: barContext.AO
}
查找過程:

Step1 聲明變量 x 并且賦值為10
Step2 聲明前置 bar 函數(shù),在其內(nèi)聲明 bar 域內(nèi)變量x 并賦值30,
聲明域內(nèi) foo 函數(shù),并隨后執(zhí)行 foo 函數(shù)
Step3 代碼執(zhí)行 bar 函數(shù),然后執(zhí)行 foo 函數(shù),foo 函數(shù)活動對象 AO 中沒有 x,
通過其作用域鏈找到 bar 函數(shù)的活動對象 AO,在其中找到 x 值為30,然后輸出值為30


13. 以下代碼輸出什么? 寫出作用域鏈的查找過程偽代碼

var x = 10;
bar() 
function bar(){
    var x = 30;
    (function (){
        console.log(x)
    })()
}

作用域鏈如下:

globalContext = {
    AO: {
        x: 10,
        bar: function
    }
    Scope: null
}
bar.[[scope]] = globalContext.AO


barContext = {
    AO: {
        x: 30,
        immediatelyFunction
    }
    Scope: globalContext.AO
}


immediatelyFunctionContext = {
    AO:{}
    Scope: barContext.AO
}

執(zhí)行流程:
Step1 聲明變量 x 并賦值為10
Step2 前置聲明函數(shù) bar,在 bar 域內(nèi)聲明變量 x 并賦值30,聲明立即執(zhí)行函數(shù)
Step3 執(zhí)行 bar 函數(shù),然后執(zhí)行 bar 域內(nèi)立即執(zhí)行函數(shù),其找到其作用域
為 barContext.AO, 然后輸出值為30


14. 以下代碼輸出什么? 寫出作用域鏈查找過程偽代碼

var a = 1;
function fn(){
    console.log(a)
    var a = 5
    console.log(a)
    a++
    var a
    fn3()
    fn2()
    console.log(a)
    function fn2(){
        console.log(a)
        a = 20
    }
}
function fn3(){
    console.log(a)
    a = 200
}
fn()
console.log(a)
作用域鏈如下:
globalContext = {
    AO: {
        a: 1,200(代碼執(zhí)行 fn3() 時)
        fn: function,
        fn3: function   
    }
    Scope: null
}
fn.[[scope]] = globalContext.AO
fn3.[[scope]] = globalContext.AO


fnContext = {
    AO: {
        a: undefined(被聲明前置時),5(被賦值為5時),
           6(執(zhí)行++操作),20(被 fn2() 函數(shù)修改)
        fn2: function
    }
    Scope: globalContext.AO
}
fn2.[[scope]] = fnContext.AO


fn2Context = {
    AO: {
        a: 20
    }
    Scope = fnContext.AO
}


fn3Context = {
    AO: {
        a: 200  
    }
    Scope = globalContext.AO
}

解答
var a = 1;

function fn(){
    console.log(a) 
// 輸出第1行:undefined,此時輸出 a 的值是函數(shù) fn 作用域中的值,
// fn 函數(shù)已經(jīng)前置聲明變量 a,但是還未賦值,固輸出 undefined
    var a = 5
    console.log(a)
// 輸出第2行:5,此時輸出 a 的值是函數(shù) fn 作用域中 a 的值,
// 該作用域中變量 a 剛剛被賦值為5
    a++
    var a
    fn3()
// 輸出第3行:1,此時輸出 a 的值是是函數(shù) fn3 在其作用域鏈 
// globalContext.AO 即全局上下文中找到的,在該作用域中 a 的值為1
    fn2()
// 輸出第4行:6,此時輸出 a 的值是函數(shù) fn 作用域中 a 的值,剛剛執(zhí)行++操作
    console.log(a)
// 輸出第5行:20,此時輸出 a 的值是函數(shù) fn 作用域中 a 的值,剛剛在 fn2 中
// 被改變?yōu)?0
    function fn2(){
        console.log(a)
        a = 20
    }
}

function fn3(){
    console.log(a)
    a = 200
}

fn()

console.log(a)
// 輸出第6行:200,此時輸出 a 的值是全局上下文中 a 的值,在 fn3 中被改變?yōu)?00
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 函數(shù)聲明 代碼執(zhí)行時函數(shù)聲明會被提升到最前執(zhí)行,所以函數(shù)的調(diào)用與函數(shù)聲明的順序...
    Feiyu_有貓病閱讀 466評論 0 0
  • 1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 (*) 函數(shù)聲明 函數(shù)表達(dá)式 函數(shù)聲明:函數(shù)調(diào)用可以發(fā)生在函數(shù)聲明之前,例如下...
    TimeLesser閱讀 460評論 4 4
  • 任務(wù) 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別答:函數(shù)聲明:function functionName(){}??函數(shù)表達(dá)式...
    mhy_web閱讀 448評論 0 0
  • 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 函數(shù)聲明語法:function functionName(arg0,arg1,ar...
    _Dot912閱讀 659評論 0 3
  • 我們學(xué)校今年的迎新晚會請來了許巍,八首歌,最后一首藍(lán)蓮花引爆全場! 沒有什么能夠阻擋, 你對自由的向往, 天馬行空...
    暖冬zyc閱讀 452評論 2 2

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