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);

版权声明:本文为liudemeng原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/liudemeng/p/11506176.html