函数进阶

118 阅读4分钟

函数的定义

   //  1.函数定义的方式:函数的声明

    //fun就是标识符  

    function fun() {
        console.log(1)
    }
    fun()
        // 2.函数定义的方式:函数表达式
    var fn = function() {
        console.log(2)
    }
    fn()
        // 3.函数声明的提升
    fun()

    function fun() {
        console.log(3)
    }
    // 4.函数表达式不可以提升
    fn() //fn is not a function
    var fn = function() {
        console.log(fn)
    }

函数定义的new的方式

通过构造函数定义一个函数,函数本身也是一个对象

       // 本节技术了解即可
 // 通过构造函数定义一个函数,函数本身也是一个对象
  // var fun = new Function('a','b','var a = "1";console.log(a+b)')
 var fun = function (a,b){
var a = "1"
console.log(a+b) // console.log("1" + 3) => console.log("1" + "3") => "13"
}
 fun(2,3)
 

函数的调用

判断函数内部的this是指向谁?

函数被谁调用,那么这个函数内部的this就指向谁

1、普通函数的调用

通过给函数名称(标识符)或者变量名添加()执行

内部有个this对象,默认指向window

    function fun() {
        console.log(1)
        console.log(this)
    }
    fun()

2、构造函数

通过new关键字进行调用,构造函数内部的this指向的是创建的实例对象

如果是通过普通函数的方式调用,内部的this指向Window类型的对象

    function Person(name) {
        this.myName = name
        console.log(this) // p1
    }
    // var p1 = new Person("zhangsan")

    Person("zs")

3、对象中的方法

对象中的方法的this默认指向的是调用这个方法的对象

    function fun() {
        console.log(1)
        console.log(this)
    }
    var obj = {
            sayHi: function() {
                console.log(this)
                console.log('hahah')
            },
            fn: fun
        }
         obj.sayHi()
        // 判断一个函数内部this的指向的时候,要联系执行上下文,在调用的时候,分析他们之间的关系,看按照什么方式调用
    obj.fn()
    
    

4、事件处理函数

在事件被触发之后,会自动执行函数

事件函数内部this指向的是 事件源

    // 需求:点击网页,产生一个事件。输出一句话
    // document.onclick = function (){
    //     console.dir(this)
    // }

5、回调函数中this

定时器和延时器中的回调函数的this

    window.setTimeout(function() {
        console.log(this) //window
    }, 1000)
    

call、bind、apply方法

1、call方法

1.1功能:第一个可以改变函数内部的this指向;

第二个是可以执行函数并传参

1.2参数:第一个参数,this要指向的对象;

第二个参数就是要传递给调用call方法的函数的参数

1.3返回值:就是调用call方法的函数的返回值

    var obj = {
        myName: 'zhangsan'
    }
    var res = fun.call(obj, 3, 5)
    console.log('res:', res)
    

call方法的运用

构造函数中扩展原型方法(原型对象上的方法就是原型方法)

给Array构造函数添加计算数组的元素的和的方法

  Array.prototype.getSum = function() {

    }

1、 需求: 求[1, 2, 3, 4, 5, 6, 7, 8] 的所有元素的和

    var arr = [1, 2, 3, 4, 5, 6, 7, 8]

    Array.prototype.getSum = function() {
        // console.log(this)
        const res = this.reduce((curr, pre) => {
            return curr + pre
        }, 0)
        console.log(res)
    }

    var sum = arr.getSum()
    console.log(sum)

2、 伪数组

     var obj = {
        0: 10,
        1: 20,
        2: 30,
        length: 3
    }

    Array.prototype.push.call(obj, 50)


    

2、apply方法

2.1功能:第一个可以改变函数内部的this指向;

第二个是可以执行函数并传参

2.2参数:第一个参数,this要指向的对象;

第二个参数就是要传递给调用call方法的函数的参数,但是一个有参数组成的数组

2.3返回值:就是调用call方法的函数的返回值

    var obj = {
        myName: 'zhangsan'
    }
    var res = fun.apply(obj, [3, 5])
    console.log('res:', res)
    

apply方法的运用

需求:求一个数组中的最大元素值

var max = 0
var arr = [1, 2, 3, 4, 5, 6]
for (var i = 0; i < arr.length; i++) {
    if (max < arr[i]) {
        max = arr[i]
    }
}

var arr = [2, 1, 6, 8, 1, 5]
Math.max.apply(Math, arr)

需求:输出一个数组中的所有元素或者展开一个数组或者提取个数组

console.log.apply(console, arr)

需求:返回一个数组中的最大值和最小值的和并且输出

var arr = [2, 1, 6, 8, 1, 5]
    // 需求最好用函数
function MaxMin() {
    var x = Math.max.apply(Math, arr)
    var y = Math.min.apply(Math, arr)
    console.log(x + y)
    return (x + y)
}
MaxMin()

3、bind方法

3.1功能:第一个可以改变函数内部的this指向;注意:它不能执行函数!!!!!!!!!

3.2参数:第一个参数,this要指向的对象;第二个参数就是要传递给调用call方法的函数的参数

3.3返回值:返回一个新的函数,这个函数的this就指向了参数指定的对象

    var obj = {
        myName: 'zhangsan'
    }

    function fun(a, b, c, d) {
        console.log(this)
        console.log(a + b + c + d)
        return a + b + c + d
    }
    var fn = fun.bind(obj, 1, 2, 3, 4)
    var res = fn()
    console.log('res:', res)
    

bind方法的运用

改变定时器内部的函数的this指向

    var obj = {
        myName: 'zs',
        age: 19,
        s: function() {
            // 每隔1秒循环定时打印这个对象的年龄
            setInterval(function() {
                console.log(this.age)
            }.bind(this), 1000)
        }
    }

    obj.s()

改变事件函数中的this

让this指向指定的对象

    var o = {

    }
    document.onclick = function() {
        console.log(this)
    }.bind(o)

函数的其他成员

输出函数,观察内部成员

    function fun() {
        console.log(1)
    }

    console.dir(fun)



    function fn(a, b) {
        // arguments
        // 获取函数实参的所有值
        // console.log(fn.arguments)
        // console.log(arguments)

        // 获取实参个数
        console.log(fn.length)

        // 获取函数名字
        console.log(fn.name)
    }

    fn(1, 2, 3, 4, 5, 6, 7, 8)

需求:求一个数据列表中的元素的最大值

可以接受不定个数的参数,并求这些参数的最大值

    function max() {
        // 1、获取到列表中的所有数据
        const arr = arguments
        var max = arr[0]

        for (var i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i]
            }
        }

        return max
    }

    var m1 = max(2, 3, 5, 6)
    var m2 = max(3, 5, 2, 9, 1, 2, 5, 7)
    console.log(m1)
    

高阶函数

1、函数作为另一个函数的参数

    function eat(fn) {
        fn()
    }

    eat(function() {
        console.log('看电影')
    })

2、函数作为一个函数的返回值

    // 实现 一个函数可以输出1000+m,10000+m,1000000+m
    function outer(n) {
        return function inner(m) {
            console.log(m + n)
        }
    }

    var fun = outer(1)
    console.log(fun)
    fun(7)
    fun(9)
    fun(10)

闭包

1.闭包的定义

在一个外部函数内部定义内部函数,在内部函数中调用了外部的函数定义的变量,并且在外部函数返回内部函数

在一个内部函数内部拿到外部函数中的变量,然后在外部函数外部可以访问到外部函数中的变量

function outer(){
  var a = 10

  function inner(){
      // console.log(a)
      return a
  }

  // 注意:返回的是函数,不是函数的调用
  return inner
}

// 由于函数作用域的原因,在函数外部是无法访问到函数内部定义的变量的
// console.log(a) //Uncaught ReferenceError: a is not defined

var fun = outer()
 var res = fun()
console.log(res)

闭包的用途场景

1、类似于缓存的作用

    function outer() {
        var a = 10

        function inner() {
            // console.log(a)
            a++
            return a
        }

        // 注意:返回的是函数,不是函数的调用
        return inner
    }

    // 由于函数作用域的原因,在函数外部是无法访问到函数内部定义的变量的
    // console.log(a) //Uncaught ReferenceError: a is not defined

    var inner = outer()
    var res = inner()
    console.log(res)

    var res1 = inner()
    console.log(res1)

2、解决循环过程中函数赋值的问题

    var arr = []

    for (var i = 0; i < 3; i++) {
        // ()() 立即执行函数IIEF
        (function(i) {
            arr[i] = function() {
                console.log(i)
            }
        })(i)
    }

    arr[0]() // 0
    arr[1]() // 1
    arr[2]() // 2