Bootstrap

JS学习第11天——函数进阶(this指向、严格模式、高阶函数、闭包、递归)

一、函数的定义和调用

1、函数的定义方式

①自定义函数(命名函数) ②函数表达式(匿名函数)③new Function()(效率低,很少使用)
所有函数都是Function的实例对象,函数也属于对象
在这里插入图片描述

2、函数的调用方式

6种函数:① 普通函数 ②对象的方法 ③构造函数 ④绑定事件函数 ⑤定时器函数 ⑥立即执行函数

//  调用方式
// 1.普通函数
function fn(){};
fn();
fn.call()

// 2.对象的方法
var obj = {
  sayHi: function () {},
};
obj.sayHi();

// 3.构造函数
function Star() {}
new Star();

// 4.绑定事件函数
btn.onclick = function () {};

// 5.定时器函数
setTimeout(function () {}, 1000);

// 6.立即执行函数
(function () {})();

二、this

1、this指向

调用方式this指向
普通函数调用window
构造函数调用实例对象,原型对象里面的方法也指向实例对象
对象方法调用该方法所属对象
事件绑定方法绑定事件对象
定时器window
立即执行函数window

2、改变this指向

JS中改变this指向的方法有:① bind()call()apply()方法
《1》call()(调用函数)

fun.call(thisArg, arg1, arg2, ...);
// thisArg:当前调用函数this的指向对象
// arg1,arg2:传递的其他参数

返回值:函数的返回值
使用场景:改变this指向并且调用该函数,比如继承(返回值是函数的返回值)

《2》apply()(跟数组相关)

fun.apply(thisArg, [argsArray]);
// argsArray:传递的值,必须包含在数组里面

返回值:函数的返回值
使用场景:主要跟数组有关系,比如借助于数学对象实现数组最大值最小值

《3》bind()(不调用函数)

fun.bind(thisArg, arg1, arg2, ...);

返回值:指定的 this值和初始化参数改造的原函数拷贝
使用场景:只想改变this指向,不调用该函数,比如改变定时器内部this指向

三、严格模式

JS除了提供正常模式外,还提供了严格模式(strict mode),严格模式IE10以上支持

开启严格模式的分类:① 为脚本开启严格模式 ② 为函数开启严格模式

1、为脚本开启严格模式

在所有语句之前放一个特定语句“use strict”;(或‘use strict’;)

<script>
 "use strict";
</script>

有的 script 基本是严格模式,有的 script 脚本是正常模式,这样不利于文件合并,所以可以将整个脚本文件放在一个立即执行的匿名函数之中。这样独立创建一个作用域而不影响其他 script 脚本文件。

<script>
 (function (){
 "use strict";
 var num = 10;
 function fn() {}
 })();
</script

2、为函数开启严格模式

要把“use strict”; (或 ‘use strict’; ) 声明放在函数体所有语句之前

function fn(){
 "use strict";
 return "这是严格模式。";
}

3、严格模式中的变化

《1》变量规定
① 变量都必须先用var 命令声明,然后再使用
②严禁删除已经声明变量

《2》this指向
严格模式下全局作用域中函数中的 this 是 undefined
② 如果构造函数不加new调用, this 指向的是undefined 如果给他赋值则会报错

《3》函数变化
函数不能有重名的参数
② 函数必须声明在顶层

更多严格模式要求:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode

四、高阶函数

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

//  接收函数作为参数
function fn(callback) {
  callback && callback();
}
fn(function () {});
// 函数作为返回值输出
function fn() {
  return function () {};
}
fn();

典型的高阶函数应用:回调函数

五、闭包

变量根据作用域不同分为两类:① 全局变量 ② 局部变量
函数外部不能使用局部变量,当函数执行完毕,本作用域的局部变量会销毁

1、闭包(closure)

闭包:有权访问另一个函数作用域中变量函数

function fn() {  // fn就是闭包函数
  var num = 10;
  function fn2() {
    console.log(num);
  }
  fn2();
}
fn();

2、在chrome中调试闭包

在这里插入图片描述

3、闭包的作用

延时变量的作用范围

function fn() { 
	var num = 10; 
	return function { 
	console.log(num); // 10 
	}
}
var f = fn();
f()

4、思考题

// 思考题 1:
var name = "The Window";
var object = {
    name: "My Object",
    getNameFunc: function() {
        return function() {
            return this.name;
        };
    }
};
console.log(object.getNameFunc()());
// 类似于
var f = object.getNameFunc();
var f = function() {
    return this.name;
}
f();

// 思考题 2:
var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function () {
    var that = this;
    return function () {
      return that.name;
    };
  },
};
console.log(object.getNameFunc()());

六、递归

递归函数:在函数内部可以调用其本身
由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return

1、求123*…*n的阶乘

function fn(n) {
 if (n == 1) {
   return 1;
 }
 return n * fn(n - 1);
}

2、求斐波那契数列

function fn(n) {
  if (n < 3) {
    return 1;
  }
  return fn(n - 2) + fn(n - 1);
}

3、根据ID返回对象的数据

var data = [
  {
    id: 1,
    name: "家电",
    goods: [
      {
        id: 11,
        gname: "冰箱",
        goods: [
          {
            id: 111,
            gname: "海尔",
          },
          {
            id: 112,
            gname: "美的",
          },
        ],
      },
      {
        id: 12,
        gname: "洗衣机",
      },
    ],
  },
  {
    id: 2,
    name: "服饰",
  },
];
function fn(data, id) {
  var a = {};
  data.forEach((item) => {
    if (item.id == id) {
      a = item;
    } else if (item.goods && item.goods.length > 0) {
      a = fn(item.goods, id);
    }
  });
  return a;
}
console.log(fn(data, 11));
;