主页

函数的定义和调用

函数的定义方式

1.函数声明方式 function关键字(命名函数)

    function fn() {}

2.函数表达式(匿名函数)

    let fn = function() {}

3.new Function() 里面的参数都必须是字符串格式

    let fn = new Function('参数1', '参数2', '函数体')
    let fn = new Function('x', 'y', 'console.log(x + y)')

函数的调用方式

1.普通函数

    function fn() {
        console.log('被调用了')
    }
    fn()
    fn.call()

2.对象的方法

    let obj ={
        function fn() {
            say: function() { 
                console.log('被调用了')
            }
        }
    }
    obj.say()

3.构造函数

    Function Star() {}
    new Star()

4.绑定事件函数

    btn.onclick = function() {
    
    }
    btn.addEventListener('click', function() {
    
    })
    // 点击了就可以调用这个函数

5.定时器函数

    setInterval(function () { }, 1000)
    // 这个函数是定时器自动1秒钟调用一次

6.立即执行函数

    (function () {
        console.log('立即执行');
    }())
    (function () {
        console.log('立即执行');
    })()
    // 立即执行函数是自动调用

this

这些 this 的指向,是当我们调用函数的时候确定的;调用方式的不同决定了 this 的指向不同

改变函数内部 this 指向

JS为我们专门提供了一些函数方法来帮助我们处理函数内部的 thsi 指向问题,常用的有 bind()call()apply() 三种方法

call() 方法

call() 方法调用一个对象;简单理解为调用函数的方式,但是它可以改变函数的 this 指向

    fn.call(thisArg, arg1, arg2, ...)
    
    function Father(uname, age, sex) {
        this.uname = uname
        this.age= age
        this.sex= sex
    }
    function Son(uname, age, sex) {
        Father.call(this, uname, age, sex)
    }
    let son = new Son('刘德华', 18, '男')
  • thisArg:当前调用函数 this 的指向对象
  • agr1,arg2:传递的其他参数

apply() 方法

apply() 方法调用一个对象;简单理解为调用函数的方式,但是它可以改变函数的 this 指向

    fn.apply(thisArg, [argsArray])
    let arr = [1, 2, 3, 4, 5]
    let max = Math.max.apply(Math, arr)
  • thisArg:在fn函数运行时指定的 this
  • argsArray:传递的值,必须包含在数组里面
  • 返回值就是函数的返回值,因为它就是调用的函数

bind() 方法

bind() 方法不会调用函数;但是能改变函数内部 this 指向

    let f = fn.bind(thisArg, arg1, arg2, ...)
    f()
    btn.addEventListener('click', function() {
        this.disabled = true // 此时this指向的是btn这个按钮
        // let that = this
        setTimeout(function() { 
            // that.disabled = false // 定时器函数里面的this指向的是window
            this.disabled = false // 此时定时器函数里面的this指向的是btn
        }.bind(this),3000) // 这个this指向的是btn这个对象
    })
  • thisArg:在fn函数运行时指定的 this
  • agr1,arg2:传递的其他参数
  • 返回由指定的 this 值和初始化参数改造的原函数拷贝

call() apply() bind() 总结

相同点:
都可以改变函数内部 this 指向
区别点:

  1. call()apply() 会调用函数,并且改变函数内部 this 指向
  2. call()apply() 传递的参数不一样,call() 传递参数 aru1, aru2...形式 apply() 必须是数组形式[arg]
  3. bind() 不会调用函数,可以改变函数内部 this 指向

主要应用场景:

  1. call() 经常做继承
  2. apply() 经常和数组有关系,比如借助于数学对象实现数组最大值最小值
  3. bind() 不用调用函数,但是还想改变 this 指向,比如改变定时器内部的 this 指向

严格模式

什么是严格模式

  • JS除了提供正常模式外,还提供了严格模式(strict mode)
  • ES5的严格模式是采用具有限制性JS变体的一种方式,即在严格模式的条件下运行JS代码
  • 严格模式在IE10以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略

严格模式对正常的JS语义做了一些更改:

  1. 消除了JS语法的一些不合理、不严谨之处、减少了一些怪异行为
  2. 消除代码运行的一些不安全之处,保证代码运行的安全
  3. 提高编译器效率,增加运行速度
  4. 禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的JS做好铺垫;比如一些保留字:class、enum、export、extends、import、super不能做变量名

开启严格模式

严格模式可以应用到整个脚本个别函数中;因此我们可以将严格模式分为为脚本开启严格模式为函数开启严格模式两种情况

为脚本开启严格模式

为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句"use strict"'use strict'
<script>
    "use strict";
</script>

<script>
    (function() {
        "use strict";
        // 为立即执行函数开启严格模式
    }())
</script>

为函数开启严格模式

    function() {
        "use strict";
    }

严格模式中的变化

严格模式变量规定

  1. 在正常模式中,如果严格变量没有声明就赋值,默认是全局变量;严格模式禁止这种用法,变量都必须先声明,然后在使用
    <script>
        'use strict'
        num = 10
        consoel.log(num) // 报错,必须先声明在使用
    </script>
  1. 严禁删除已经声明的变量;例如,delete x; 语法是错误的
    <script>
        'use strict'
        let num = 10
        delete num // 报错,严禁删除已经声明的变量
    </script>

严格模式 this 指向问题

  1. 以前在全局作用域中函数中的 this 指向 window 对象,严格模式下全局作用域函数中的 this 指向的是 undefined
    <script>
        'use strict'
        function fn() {
            console.log(this) // 严格模式指向undefined
        }
        fn()
    </script>
  1. 以前构造函数时不加 new 也可以调用,当普通函数,this 指向全局对象严格模式下不加 new 调用 this 指向的是 undefined 如果给它赋值会报错
  2. new 实例化的构造函数指向创建的对象实例
  3. 严格模式下定时器的 this 还是指向 window
  4. 严格模式下的事件、对象还是指向调用者

严格模式函数变化

  1. 函数不能有重名的参数
  2. 函数必须声明在顶层,新版本的JS会引入"块级作用域"(ES6中已引入);为了与新版本接轨,不允许在非函数的代码块内声明函数

高阶函数

高阶函数是对其他函数进行操作的函数,它接收函数作为参数将函数作为返回值输出

    function fn(callback) {
        callback && callback()
    }
    fn(function () {
        console.log('Hi');
    })
    
    function fn() {
        return function () { console.log('Hi'); }
    }
    fn()
此时fn就是一个高阶函数
函数也是一种数据类型,同意作为参数,传递给另一个参数使用;最典型的就是回调函数

闭包

变量作用域

变量根据作用域的不同分为两种:全局变量和局部变量

  1. 函数内部可以使用全局变量
  2. 函数外部不可以使用局部变量
  3. 当函数执行完毕,本作用域内的局部变量会销毁

什么是闭包

闭包(closure)指有权访问另一个函数作用域中变量函数


简单理解就是,一个作用域可以访问另一个函数内部的局部变量

闭包的主要作用:延伸了变量的作用范围

闭包案例

循环注册点击事件

    var btns = document.querySelectorAll('button')
    // 利用闭包的方式得到当前按钮的索引号
    for (var i = 0; i < btns.length; i++) {
        // 利用for循环创建了4个立即执行函数
        (function (i) {
            btns[i].addEventListener('click', function () {
                console.log(i);
            })
        }(i))
    }

循环中的 setTimeout()

    var btns = document.querySelectorAll('button')
    // 闭包应用 3秒之后打印所有btn元素的内容
    for (var i = 0; i < btns.length; i++) {
        (function (i) {
            setTimeout(function () {
                console.log(btns[i].innerHTML);
            }, 3000)
        }(i))
    }

闭包总结

闭包是什么

闭包是一个函数(一个作用域可以访问另一个函数的局部变量)

闭包的作用是什么

延伸变量的作用范围

递归

什么是递归

  1. 如果一个函数内部可以调用其本身,那么这个函数就是递归函数
  2. 简单理解:函数内部自己调用自己,这个函数就是递归函数
  3. 递归函数的作用和循环效果一样
  4. 由于递归很容易发生”栈溢出“错误(stack overflow),所以必须要加退出条件 return
    let num = 1
    function fn() {
        console.log('打印6次')
        if (num === 6) {
            return // 递归里面必须加退出条件
        }
        num++
        fn()
    }
    fn()

JavaScript

版权属于:Joe
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
0

目录

来自 《JS-函数进阶》
评论

qiaofugui

博主很懒,啥都没有
188 文章数
14 评论量
3 分类数
191 页面数
已在风雨中度过 2年139天0小时46分