五、函数

目录

一、function:

二、何时使用:

三、创建函数并且调用:3种

四、箭头函数 —— ES6

五、匿名函数:创建的函数,没有函数名引用着

六、使用对象作为参数

七、函数返回值:return

八、作用域:2种

九、作用域链

十、声明提前

十一、按值传递

十二、重载(overload):

十三、闭包:

十二、函数的执行原理  5步


一、function:

function:函数,也称之为方法。也是一个对象。需要提前定义好的,以后就可以反复使用。

函数被调用时才会执行

二、何时使用:

1.不希望打开页面立刻执行,需要时再使用或者用户来触发(绑定事件)

2.希望能够反复执行,不用刷新页面

3.以后任何一个 独立的功能体,都要单独封装为一个函数

4.函数的地位非常高,函数是第一等公民,随时随地考虑能不能封装为一个函数,尤其是重复的代码

5.函数内的一切内存,函数调用完毕后都会自动释放

三、创建函数并且调用:3种

1.声明方式创建函数

用一个关键字function做声明

function  函数名(形参列表){

函数体;

return 返回值;

}

2.直接量方式创建函数:函数其实就是一个变量名

var 函数名=function(形参列表){

函数体;

return 返回值;

}

3.构造函数方式

var 函数名=new Function("形参1",....,"函数体;return 返回值;");

四、箭头函数 —— ES6

var fn=()=>{
    console.log("你好");
    console.log("不好");
}

(1)只有一句话时,大括号可以省略

var fn=()=> console.log("你好");
   

(2)只有一个参数时,可以省略()

var fn=a=> console.log("a=",a);
fn(123)
   

为什么要有带参数的函数?

    function addSum() {

            let a = 10;

            let b = 20;

            console.log(a + b);

        }

        addSum()

这样的函数是死的,只能做10+20。

所以,若函数完成功能需要调用者传入数据,那么就需要用有参数的函数,可以大大提高函数的灵活性。

 五、匿名函数:创建的函数,没有函数名引用着

语法:

○(function(){函数体;}());

  

○(function(){函数体;})();

何时使用:如果函数只会执行一次

为什么:节约内存,匿名函数没有变量引用着用户,就会自动释放

如何使用:

(1)匿名函数自调:只会执行一次,执行完毕后会自动释放,代替全局写法,节约内存空间

(function(){

console.log("我是匿名自调");

})();

(2)匿名函数回调:将函数调用时,传入的实参,又是一个匿名函数,不需要我们程序员调用,会由主函数自动执行

哪些叫做回调函数:只要不是自调,就是回调。

arr.sort(function(a,b){return a-b;})

str.replace(reg,function(){})

d1.οnclick=function(){}

    <button id="btn">按钮</button>

    <script>

        btn.onclick = function() {

            alert(1) //1  不用调用,自动执行

        }

    </script>

六、使用对象作为参数

        

        function fn(a){
            // console.log("a =", a)
            // console.log(a.name)

       
            a.name = "猪八戒" // 修改对象时,如果有其他变量指向该对象则所有指向该对象的变量都会受到影响
            console.log(a)//"猪八戒"
            
        }

        // 对象可以作为参数传递
        let obj = {name:"孙悟空"}
       // 传递实参时,传递并不是变量本身,而是变量中存储的值
         fn(obj)

         console.log(obj)//"猪八戒"
       function fn(a){
            // console.log("a =", a)
            // console.log(a.name)

            a = {} // 修改变量时,只会影响当前的变量
            a.name = "猪八戒" // 修改对象时,如果有其他变量指向该对象则所有指向该对象的变量都会受到影响

            console.log(a)//"猪八戒"
            
        }

        // 对象可以作为参数传递
        let obj = {name:"孙悟空"}

        // 传递实参时,传递并不是变量本身,而是变量中存储的值
        // fn(obj)

        console.log(obj)//"孙悟空"

      // 函数每次调用,都会重新创建默认值
        function fn2(a = {name:"沙和尚"}){
            console.log("a =", a)
            a.name = "唐僧"
            console.log("a =", a)
        }

        fn2() // 沙和尚 唐僧
        fn2() // 沙和尚 唐僧

        let obj2 = {name:"沙和尚"}
        
        // 函数每次调用,都会重新创建默认值
        function fn2(a = obj2){
            console.log("a =", a)
            a.name = "唐僧"
            console.log("a =", a)
        }

        fn2() // 沙和尚 唐僧
        fn2() //唐僧 唐僧

七、函数返回值:return

返回值概念:当调用某个函数时,这个函数会返回一个结果出来

        function fn() {

            return 20

        }

        fn()

            //return 相当于执行了 fn()=20。返回的是函数值

return的本意:退出函数的意思

只不过如果return后面跟着一个数据,会顺便将其返回到全局作用域中,但是只负责返回不负责保存!

所以在调用函数时:如果有return,记得拿一个变量接住结果

 function getSum() {

            for (var i = 1, sum = 0; i <= 100; i++) {

                sum += i;

            }

            return sum


        }

        var result = getSum();

        console.log(result);//5050

八、作用域:2种

1.全局作用域:在网页运行时创建,在网页关闭时消耗。

                        所有直接编写到script标签中的代码都位于全局作用域中。 

                        函数每次调用都会产生一个全新的函数作用域。

                        在函数中定义的变量是局部变量,只能在函数内部访问,外部无法访问。

        function fn() {
            let a = 10;
            console.log(a);
        }
        fn()
        console.log(a);

 

                

2.函数作用域(局部作用域):成员只能在函数调用时内部可用

       

 var a = 1;


        function fn1() {

            var a = 2;

            var b = '22';

            fn2();


            function fn2() {

                var a = 3;

                fn3();


                function fn3() {

                    var a = 4;

                    console.log(a); //4

                    console.log(b); //22

                }

            }

        }

        fn1()


        function fn() {

            let num = 10;

            console.log(num);//10


            function fn1() {

                console.log(num);//10

                let num2 = 20;


            }

            fn1();

            console.log(num2); //num2 is not undefined


        }

        fn();

        console.log(num); //num is nor undefined(前面报错了,这不不会被执行了)

带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就会报错了

特殊:(1)尽量不要全局污染:在函数中创建变量的使用记得一定要叫var。

                ​​​​​​​        ​​​​​​​        在局部作用域中,如果没有使用var或者let声明变量,则变量会称为window对象的属性,也就是全局变量。

       function fn() {

            num = 10;   —— 此时是全局变量   不推荐

        }

        fn();

        console.log(num); //10

    (2)本身是函数的东西,全局用不到,但是配合return其实也可以

九、window对象

                (1)在浏览器中,浏览器为我们提供了一个window对象,可以直接访问

                (2)window对象代表的是浏览器窗口,通过该对象可以对浏览器窗口进行各种操作

                               除此之外window对象还负责存储JS中的内置对象和浏览器的宿主对象

                (3)window对象的属性可以通过window对象访问,也可以直接访问

                (4) 函数可以认为是window对象的方法

                window.alert(123);= window.alert(123);

                (5)var用来声明变量,作用和let相同,但是var不具有块作用域

                               在全局中使用var声明的变量,都会作为window对象的属性保存

var b=20//window.b=20
console.log(window.b)

                                使用function声明的函数,都会作为window的方法保存

function fn(){
    alert('我是fn')
}
window.fn()

                                使用let声明的变量不会存储在window中,而是存在一个秘密的小地方(无法访问)

let b=20//window.b=20
console.log(window.b)//报错

 

十、声明提前

预解析:JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript解析器在运行JavaScript代码时分为两部分:预解析和代码执行。

预解析js引擎会把js里面所有的var和function提升到当前作用域的最前面,然后才是代码执行 —— 从上往下

变量预解析:

变量提升:把所有的变量声明提升到当前作用域的最前面 ,不提升赋值操作。

函数提升:把所有的函数声明提升到当前作用域的最前面,不调用函数。

变量提升

        console.log(num); //undefined

        var num = 10;

        

        相当于:

        


        var num;

        console.log(num);

        num = 10

 

      fun();

        var fun = function() {

            console.log(22); //爆错


        }

        

        相当于:

                var fun;

        fun();//调用要写在 函数表达式很后面才可以

        fun = function() {

            console.log(22);

        }

函数提升(只能是以下这种函数创建方式才行)

        fn()


        function fn() {

            console.log(2);

        }

        

        相当于:

         function fn() {

            console.log(2);

        }

        fn();

var a,b;

(function(){

alert(a);

alert(b);

var a=b=3;

alert(a);

alert(b);

})();

alert(a);

alert(b);


相当于:

// 经过预编译原来的代码可以理解为下面的代码

var a, b; // 全局作用域下 var 定义的变量将成为 window 的对象 windows: {a: undefined, b: undefined, ...}

(function () {

  var a // 这个局部变量 a 访问优先级比 外面的 a 更高

  alert(a); // 局部变量 a: undefined

  alert(b); // window.b: undefined

  a = b = 3; // 局部变量 a: 3, window.b: 3

  alert(a); // 局部变量 a: 3

  alert(b); // window.b : 3

})();


alert(a); // window.a: undefined

alert(b); // window.b: 3

十一、按值传递

十二、重载(overload):

相同的函数名,根据传入的实参的不同,会自动选择对应的函数执行

为什么:减少调用者的负担

问题:JS的语法不支持重载。JS不允许存在 多个同名函数,最后一个函数会覆盖之前所有的    

 function zwjs(name) {

            return "我的名字叫" + name;

        }


        function zwjs(name, age) {

            return "我叫" + name + ",今年" + age + "岁";

        }


        function zwjs(name, age, hobby) {

            return name + ",今年" + age + "岁,喜欢" + hobby;

        }


        console.log(zwjs("袍哥")); //做第三个函数。袍哥,今年undefined岁,喜欢undefined。

解决:在函数内部有一个对象:arguments

什么是arguments对象:函数中,自带的,不需要我们创建的,是一个【类数组】对象,作用:接收住所有实参

只有三个点和数组是相同的

(1)都可以用下标访问某个元素

arguments[i] - 传入的某个实参

(2)都可以用length获取到长度

arguments.length

(3)可以遍历拿到每一个元素 - for循环

强调:类数组对象不是数组,所有的数组的API,类数组都不能使用

       优点:何时使用:以后不需要形参,也可以接住所有的实参!

      变相实现重载:在函数内部判断传入的实参(个数、类型)的不同,执行不同的分支操作         

    function zwjs(){

                        if(arguments.length==1){

                            return "我的名字叫"+arguments[0];

                        }else if(arguments.length==2){

                            return "我叫"+arguments[0]+",今年"+arguments[1]+"岁";

                        }else if(arguments.length==3){

                            return arguments[0]+",今年"+arguments[1]+"岁,喜欢"+arguments[2];

                        }

                    }

                   

                    console.log(zwjs("袍哥"));

                    console.log(zwjs("袍哥",128));

                    console.log(zwjs("袍哥",128,"打游戏"));

十三、闭包:

作用域:(scope)2种

全局作用域:

随处可用,可以反复使用。缺陷:容易被污染

函数作用域:

不会被污染,只有函数调用时内部可用。缺点:调用结束后,就释放了,一次性的,不可以反复使用

块级作用域:

if(3<5){

var num=10;

}

console.log(num);//10

十二、函数的执行原理  5步

(1)程序加载时会

创建一个执行环境栈(ESC):保存函数调用顺序的数组。栈:一端开启,一端封闭

ECS里首先压入全局执行函数(全局EC)

全局 EC中引用着全局对象window

window中保存着全局变量

(2)定义时:

创建函数对象:封装代码段

在函数对象中定义了scope属性,记录着函数来自的作用域

全局函数的scope都是window

(3)调用前:

在执行环境栈中压入新的函数EC

创建出活动对象(AO):保存本次函数调用用到的局部变量

在EC中添加了scope chain(作用域链)属性引用着AO

设置AO的parent属性为函数的scope引用的对象

(4)调用时

变量的使用规则:优先使用局部变量,局部没有找全局,全局没有就报错

(5)调用完:

函数的EC会出栈,AO自动释放,局部变量也就自动释放

两链一包:

作用域链(scope chain):以函数的EC中的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构

作用:查找,带来了 变量的使用规则:

优先使用局部变量,局部没有找全局,全局没有就报错

闭包:保护一个可以反复使用的局部变量的一种此法结构。

为什么需要闭包:全局变量:缺点:容易被污染

局部变量:缺点:只能使用一次就被释放

如何使用:

(1)两个函数进行嵌套

(2)外层函数创建受保护的局部变量,并且返回内层函数

(3)内层函数在操作受保护的局部变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值