# 函数

函数是 javascript 世界中的一等公民,技能是定义作用域。 一般存在四种基本形式:函数声明函数表达式函数嵌套闭包。 只有声明的函数才具有提升的特性。

函数声明(函数提升)

function func(){
    console.log("函数的声明形态")
}
1
2
3

函数表达式

// 函数的表达式形态 之一
let func0 = function(){
    console.log("函数的表达式形态");
}

// 函数的表达式形态 之二
(function func1() {})
1
2
3
4
5
6
7

函数嵌套

let func2 = function(){
    console.log("函数的嵌套形态");
    let func3 = function(){
        console.log("func2嵌套在func1里")
    }
    func3();
}
1
2
3
4
5
6
7

闭包

let func4 = function(){
    var a = "func4"; 
    return function(){
        console.log("我是以闭包形态存在的函数:"+a);
    }
}
1
2
3
4
5
6

# 立即执行函数

立即执行函数IIFE(Immediately-Invoked Function Expression)

(function(){
    console.log("我是立即运行的匿名函数");
})();

(function(){
    console.log("我也是立即运行的匿名函数");
}());
1
2
3
4
5
6
7

# 箭头函数

箭头函数(又叫做lambda表达式)不暴露 arguments 对象。箭头函数可以保持this的指向,总是指向定义它时所在的上下文环境。 箭头函数不能作为构造函数,因此无法被new操作。

var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
1
2

# 高阶函数

如果某个函数接收另一个函数作为参数或者返回值为一个函数,该函数就称之为高阶函数(HOF)。

回调函数是最常见的高阶函数

function fn1(cb){
    cb && cb();
}
1
2
3

数组中的高阶函数:

  1. Array.prototype.map
  2. Array.prototype.reduce
  3. Array.prototype.filter
  4. Array.prototype.sort

# 函数重载

重载是面向对象编程语言(比如Java、C#)里的特性,JavaScript语言并不支持该特性。所谓重载(overload), 就是函数名称一样,但是随着传入的参数个数不一样,调用的逻辑或返回的结果会不一样。jQuery之父John Resig 曾经提供了一个非常巧妙的思路实现重载,代码如下:

(() => {
    // IIFE+箭头函数,把要写的代码包起来,避免影响外界,这是个好习惯
    // 当函数成为对象的一个属性的时候,可以称之为该对象的方法。
  
    /**
    * @param {object}  一个对象,以便接下来给这个对象添加重载的函数(方法)
    * @param {name}    object被重载的函数(方法)名
    * @param {fn}      被添加进object参与重载的函数逻辑
    */
    function overload(object, name, fn) {
      // 存放旧函数,本办法灵魂所在,将多个fn串联起来
      var oldMethod = object[name];
      object[name] = function() {
        // fn.length为fn定义时的参数个数,arguments.length为重载方法被调用时的参数个数
        if (fn.length === arguments.length) {
          // 若参数个数匹配上 就调用指定的函数fn
          return fn.apply(this, arguments);
        } else if (typeof oldMethod === "function") {
          // 若参数个数不匹配 就调旧函数
          return oldMethod.apply(this, arguments);
          // 注意:当多次调用overload()时,旧函数中又有旧函数,层层嵌套,递归地执行if..else
          // 判断,直到找到参数个数匹配的fn
        }
      };
    }
  
    // 不传参数时
    function fn0() {
      return "no param";
    }
    // 传1个参数
    function fn1(param1) {
      return "1 param:" + param1;
    }
    // 传两个参数时,返回param1和param2都匹配的name
    function fn2(param1, param2) {
      return "2 param:" + [param1, param2];
    }
  
    let obj = {}; // 定义一个对象,以便接下来给它的方法进行重载
    
    overload(obj, "fn", fn0);//给obj添加第1个重载的函数
    overload(obj, "fn", fn1);//给obj添加第2个重载的函数
    overload(obj, "fn", fn2);//给obj添加第3个重载的函数
  
    console.log(obj.fn());//>> no param
    console.log(obj.fn(1));//>> 1 param:1
    console.log(obj.fn(1, 2));//>> 2 param:1,2
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# arguments

# 函数的arguments为什么不是数组?如何转化成数组?

因为argument是一个对象【类数组】,它的属性从0开始,依次为0,1,2...最后还有callee和length属性。

常见的类数组:

  1. getElementByTagName()getElementsByClassName()getElementsByName()获得的HTMLCollection.
  2. querySelector()获得的nodeList

转化成数组:

  1. for in循环

  2. Array.prototype.slice.call()

let argsArr = Array.prototype.slice.call(arguments, 1);
1
  1. Array.from()
let argsArr = Array.from(arguments);
1
  1. ES6展开运算符
let argsArr = [...arguments]
1
  1. concat+apply
// apply方法会把第二个参数展开
let argsArr = Array.prototype.concat.apply([], arguments)
1
2

# 构造函数

  1. 构造函数也是一个普通函数,创建方式和普通函数一样,但是构造函数 习惯上首字母大写
  2. 调用方式不一样,普通函数直接调用,构造函数要用关键字 new 来调用
  3. 调用时,构造函数内部会创建一个新对象,就是实例,普通函数不会创建新对象
  4. 构造函数内部的 this 指向实例,普通函数内部的 this 指向调用函数的 对象(如果没有对象调用,默认为 window)
  5. 构造函数默认的返回值是创建的对象(也就是实例),普通函数的返回 值由 return 语句决定
  6. 构造函数的函数名与类名相同
最后更新时间: 10/20/2021, 2:55:36 PM