• JavaScript之函数


    JavaScript之函数

    函数的定义方式

    • 函数声明
    • 函数表达式
    • new Function

    函数声明

    function foo() {
      
    }
    

    函数表达式

    var foo = function() {
      
    }
    
    两者之间的区别
    • 函数声明必须要有名字
    • 函数声明会函数提升, 在预解析就已经创建,声明前后都可以调用
    • 函数表达式类似于变量赋值
    • 函数表达式可以没有名字,匿名函数
    • 函数表达式没有变量提升, 在执行阶段创建, 必须要在表达式执行之后才可以进行调用

    demo

    if (1){
        function f() {
            console.log(1);
        }
    }else {
        function f() {
            console.log(2);
        }
    }
    

    以上代码执行结果在不同浏览器中结果不一致。为了解决则使用函数表达式

    var f;
    if (1){
        f = function() {
            console.log(1);
        }
    }else{
        f = function() {
            console.log(2);
        }
    }
    

    函数的调用方式

    • 普通函数
    • 构造函数
    • 对象方法

    函数中this指向不同场景

    函数的调用方式决定了this指向的不同:

    调用方式非严格模式备注
    普通函数调用 window 严格模式下是 undefined
    构造函数调用 实例对象 原型方法中 this 也是实例对象
    对象方法调用 该方法所属对象 紧挨着的对象
    事件绑定方法 绑定事件对象  
    定时器函数 window  

    函数也是对象

    • 所有函数都是Function的实例

    call、apply、bind

    call

    call() 方法调用一个函数,其中具有一个指定的this值和分别提供的参数(参数的列表)

    注意: 该方法的作用和apply()方法类似, 只有一个区别, 就是call()方法接受的是 若干个参数的列表,而apply()`方法接受一个或者多个参数的数组。

    语法:

    fun.call(thisArg[1, arg1[1, arg2[1,2]]])
    

    参数:

    • thisAry
      • 在fun函数运行时指定的this值
      • 如果制定了null或者undefined, 则内部this指向window
    • arg1, arg2
      • 指定的参数列表
    apply

    apply()方法调用一个函数, 具体制定了一个this值,以及作为一个数组(或类似于数组的对象)提供的参数。

    注意: 该方法的作用和call()方法类似,只有一个区别,call()方法接受的是若干个参数的列表,而apply()方法接受的 是一个包含多个参数的数组。

    语法:

    fun.apply(thisArg, [argsArray])
    

    参数:

    • thisArg
    • argsArray

    apply()与call() 非常相似,不同之处在于提供参数的方式。

    apply()使用参数数组而不是一组参数列表。

    fun.apply(this, ['eat', 'bananas'])
    
    bind

    bind()函数会创建一个新函数(称为绑定函数), 新函数和与被调函数(绑定函数的目标函数)具有相同的函数体(在es5中内置的call属性)。 当目标函数被调用的时 this 值绑定 bind() 的第一个参数, 该参数不能被重写。 绑定函数被调用,bind()也接受预设的参数提供给原函数。

    一个绑定函数可以使用 new 操作符创建对象: 这种行为就像是吧原函数当做为解析器。 提供的 this 值忽略,同时调用时参数被提供给模拟函数。

    语法:

    fun.bind(thisArg[1, agr1[1]])
    

    参数:

    • thisArg
      • 当绑定函数被调用时, 该参数会作为原函数运行是的 this 指向。当使用 new 操作符调用绑定函数时,该参数无效。
    • arg1, arg2
      • 当绑定函数被调用的时, 这些参数将置于实参之前传递被绑定的方法。

    返回值:

    返回有指定的 this值 和初始化参数改造的原函数的拷贝。

    demo01

    this.x = 9;
    var module = {
        x: 81,
        getX: function() {
          return this.x;
        }
    };
    
    module.getX(); // 返回81, 使用的是函数内部作用域
    
    var retrieveX = module.getX;
    retrieveX(); // 返回9, this指向余全局作用域
    
    //创建一个新函数, 将 this 绑定到module对象上面
    // 新手可能会被全局变量x和model里面的属性 x 迷惑
    var boundGetX = retrieveX.bind(module);
    boundGetX(); // 返回81
    
    小结
    • call和apply特性一样
      • 都是用来调用函数,而且是立即调用
      • 但是可以在调用函数的同时, 通过第一个参数指定函数内部的 this 的指向
      • call调用时, 参数一参数列表进行传递,以逗号分隔的方式依次传递即可
      • apply调用时, 参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
      • 如果第一个参数指向了null,或者undefined则内部 this 指向余 window
    • bind
      • 可以用来指定内部 this 的指向, 然后生成一个改变 this 指向的新的函数
      • 区别: bind不会调用
      • bind支持传递参数,两个位置传递
        • 在bind的同时,以参数列表的形式进行传递
        • 在调用的时候,以参数列表的形式进行传递
        • 那到底以谁 bind 的时候传递的参数为准呢还是以调用的时候传递的参数为准
        • 两者合并:bind 的时候传递的参数和调用的时候传递的参数会合并到一起,传递到函数内部

    函数的其他成员

    • arguments
      • 实参集合
    • caller
      • 函数的调用者
    • length
      • 形参的个数
    • name 
      • 函数的名称
    function fn(x, y, z) {
        console.log(fn.length);
        console.log(arguments);
        console.log(arguments.callee === fn);
        console.log(fn.caller);
        console.log(fn.name);
    }
    
    function f() {
        fn(10, 20, 30)
    }
    f()
    

    高阶函数

    • 函数可以作为参数
    • 函数可以作为返回值
    • setTimeout延时函数,里面是毫秒单位

    作为参数

    function eat(run) {
        setTimeout(function() {
            console.log("在吃饭");
            run();
        }, 3000)
    }
    
    eat(function() {
        console.log("跑步");
    })
    

    作为返回值

    function genFun() {
        return function() {
            var name = "胡珺";
            return name;
        }
    }
    
    var isArray = genFun();
    console.log(isArray());
    

    作用域,作用域链, 预解析

    • 全局作用域
    • 函数作用域
    • 没有块级作用域
    var a = 10;
    function fn() {
        var b = 20;
        function fn1() {
            var c = 30;
            console.log(a+b+c);
        }
        function fn2() {
            var d = 40;
            console.log(c+d);
        }
        fn1();
        fn2();
    }
    fn()
    

    内层作用域可以访问外层作用域,反之不行

    闭包

    闭包就是能够读取其他函数内部变量的函数, 由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量, 因此可以把闭包简单理解成 “定义在一个函数内部的函数”。

    所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

    闭包的用途:

    • 可以在函数外读取函数内部成员
    • 让函数内成员始终存活于内存中

    demo1

    var array = [11,22,33];
    for (var i = 0; i < array.length; i++){
        array[i] = function() {
            console.log(i);
        }
    }
    
    array[1]();
    

    demo2

    console.log(111);
    
    for(var i = 0; i < 3; i++) {
      setTimeout(function () {
        console.log(i)
      }, 0)
    }
    console.log(222)
    

    递归函数

    • 自己调用自己
    计算阶乘的递归函数
    function factorial (num) {
      if (num <= 1) {
        return 1
      } else {
        return num * factorial(num - 1)
      }
    }
    factorial(4);
  • 相关阅读:
    断开/删除 SVN 链接(.svn)的几种方法
    Android 中 ListView 常用属性合集
    Android 中 GridView 常用属性合集
    LeetCode-387-字符串中的第一个唯一字符
    LeetCode-374-猜数字大小
    LeetCode-290-单词规律
    LeetCode-278-第一个错误的版本
    LeetCode-383-赎金信
    LeetCode-367-有效的完全平方数
    LeetCode-350-两个数组的交集 II
  • 原文地址:https://www.cnblogs.com/liudemeng/p/11506176.html
Copyright © 2020-2023  润新知