奋斗30天Javascript之3种调用函数方式和闭包(Part6)

本文是关于JavaScript的复习笔记,重点讲解了三种函数调用方式:直接调用、call方法和apply方法。此外,还深入探讨了函数返回值、局部变量和局部函数的概念。特别强调了闭包的原理和应用,以及如何解决闭包在循环中的问题,通过实例展示了使用IIFE和let来创建正确的闭包效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近又在重新复习js,不怎么用有些就就生疏了,每天都要复习复习在复习才行,分享一下跟着大神学习的日常笔记记录。

有些錯誤可能是沒寫對中英字符,可能會報錯,都手寫的,見諒,废话不多说半句,开始复习吧!

* 定义好了函数之后,javascript提供了3种调用函数的方式

1:直接调用函数:这种函数的调用时最常见,最普遍的方法。

对象.函数引用:

//当声明的一个函数没有指名分配给哪个对象使用的时候,默认分配给的是window对象.

栗子:

function aa(name,age){

alert("hello"+name+",今年:"+age)

}

window.aa("livia",18);

call方法调用函数:

函数引用.call(调用者,参数1,参数2,...)

栗子:

function aa(arr, func) {

                func.call(window, arr);

            }
            aa([1, 2, 3], function(arr) {
                for(i in arr) {
                    document.write(arr[i] + "<br/>")
                }
            })

2:以apply方法调用函数:

函数引用.apply(调用者,arguments)

//arguments相当于是数组,用来存放多个can'参数。和call调用方式类似

栗子:

function aa(arr, func) {

                func.apply(window, arr);

            }
            aa([1, 2, 3], function([arr]) {
                for(i in arr) {
                    document.write(arr[i] + "<br/>")
                }
            })

* 函数的返回值

javascriptzhon中的函数没声明返回类型,当函数想要返回值的时候,直接加上return“值”语句即可,假如不加就代表此函数没有任何返回值。

* 局部变量和局部函数

a: 根据变量的定义范围不同,变量有全局变量和局部变量之分,直接定义的变量是全局变量,在函数中定义的变量称为局部变量,局部变量只能在函数内有效,如果全局变量和局部变量使用相同的变量名,则局部变量将覆盖全局变量

b:与局部变量对应的是局部函数,局部函数在是函数中定义的,外部函数可以可以直接调用其内部的函数,在外部函数外直接调用内部函数是不可以的,所以只有当外部函数被调用时,内部局部函数才会被执行。

栗子:

1:

    var name = "taolesi";

    function func2() {

        var age = 18;
        alert(name)

    }

    func2();

}

func1();

//直接弹出taolesi

2:

function show(){

return function(){

alert("taolesi")

}

}

var func = show();

func();

//直接弹出taolesi

3:闭包

function func3(){

var a =1;

function func4(){

alert(a);

}

return func4;

}

var func = func3();

func();

//直接弹出1

来一波大神总结的闭包吧~~~

* 閉包(Closure)

閉包是函式記得並存取語彙範疇的能力,可說是指向特定範疇的參考,因此當函式是在其宣告的語彙範疇之外執行時也能正常運作。

範例如下。

function foo() {

var a = 2;

function bar() {

console.log(a);

}

return bar;

}

var baz = foo();

baz(); // 2

說明

  • 函式能夠存取的範疇即是其被內嵌後往外推的範圍,例如 bar 被內嵌於 foo 之內,因此 bar 內變數可存取的範圍就是 foo 和全域範疇。因此,基於語彙範疇的變數查找規則,bar 內的 a 在自己的函式範疇內找不到定義的話,可往外層的範疇查找,於是在 foo 內找到了,得到 a 為 2。其中,console.log(a) 是執行 RHS 查找。
  • JavaScript 引擎的垃圾回收機制會釋放不再使用的記憶體,但閉包為了保留函式記得和存取其語彙範疇的能力,就會予以保留,不做記憶體回收。因此,bar 仍保留指向 foo 的內層範疇的參考,這個參考就是閉包。
  • 最後,雖然 baz 位於 bar 所定義的範疇之外,但由於閉包的緣故,bar 仍能正常執行,而得到 a 的值。

* 迴圈與閉包

如果今天要實作一個每秒依序印出數字 1, 2, 3, ..., 5 的功能,你會怎麼做呢?

是這樣嗎?

for (var i = 1; i <= 5; i++) {

setTimeout(function timer() {

console.log(i);

}, i * 1000 );

}

這的確是錯誤的。由於 console.log(i) 中的 i 會存取的範疇是 for 所在的範疇(目前看起來是全域範疇,因為 var 宣告的變數不具區塊範疇的特性),因此當 1 秒、2 秒...5 秒後執行 console.log(i) 時,就會去取 i 的值,而此時 for 迴圈已跑完,i 變成 6,因此就會每隔一秒印出一個「6」。

若希望每隔一秒印出 1、2、...5,可使用 IIFE 加入新的範疇來修改,意即為每次迭代都建立一個新的函式範疇(但其實我們想要的是建立一個區塊範疇)。

  • for (var i = 1; i <= 5; i++) {
    
    (function(j) {
    
    setTimeout(function timer() {
    
    console.log(j);
    
    }, j * 1000);
    
    })(i);
    
    }

    结果如下:

既然是要為每次迭代建立區塊範疇,更好的解法就是使用 let,let 會在每次迭代時重新宣告變數 i,並將上一次迭代的結果作為這一次的初始值。

for (let i = 1; i <= 5; i++) {

setTimeout(function timer() {

console.log(i);

}, i * 1000);

}//依次输出12345

结果如下:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值