博客列表 >PartIII 04 函数与闭包(0903thu)

PartIII 04 函数与闭包(0903thu)

老黑
老黑原创
2020年09月05日 22:01:46753浏览

主要内容:函数与闭包(类放在下一天)

  1. 函数默认值(原生及es6的简洁实现 - 技巧类)
  2. 传统函数表达式/回调的缺点与解决(this不好用)
  3. 通过箭头函数来解决(=>),但有些时候抽象了也不好理解
    • 箭头函数语法(无参数、单参数、多参数)
  4. …rest/spread 剩余及扩展参数
  5. 对象字面量的扩展(或者叫简化)
  6. 闭包:可以访问自由变量的函数。可以用来:
    • 访问函数中的私有变量;
    • 快速创建多个全局可用的API。

1. 函数默认值

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>函数默认值</title>
  7. </head>
  8. <body>
  9. <script>
  10. // 原生方式
  11. function delay(timeout, callback) {
  12. timeout = typeof timeout !== undefined ? timeout : 3000;
  13. callback = typeof callback !== undefined ? timeout : function () {};
  14. setTimeout(callback, timeout);
  15. }
  16. delay();
  17. // es6
  18. function delay(timeout = 3000, callback = function () {}) {
  19. setTimeout(callback, timeout);
  20. }
  21. delay();
  22. </script>
  23. </body>
  24. </html>

2. 传统函数表达式/回调的缺点与解决

  • 直接用this会出现错误,需要通过临时变量来转化
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>传统函数表达式/回调的缺点与解决方案</title>
  7. </head>
  8. <body>
  9. <script>
  10. let user = {
  11. // 属性
  12. name: "peter-zhu",
  13. // 方法
  14. getName: function () {
  15. // console.log(this);
  16. // 将当前this(user)放在一个临时变量中保存起来
  17. let that = this;
  18. setTimeout(function () {
  19. // 回调的作用域是全局window
  20. // console.log(this);
  21. // console.log("My name is ", this.name);
  22. console.log("My name is ", that.name);
  23. }, 1000);
  24. },
  25. };
  26. user.getName();
  27. </script>
  28. </body>
  29. </html>

3. 通过箭头函数来解决

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>箭头函数的一个小案例</title>
  7. </head>
  8. <body>
  9. <script>
  10. let user = {
  11. // 属性
  12. name: "peter-zhu",
  13. // 方法
  14. getName: function () {
  15. setTimeout(() => {
  16. console.log(this);
  17. console.log("My name is ", this.name);
  18. }, 1000);
  19. },
  20. };
  21. user.getName();
  22. // 箭头函数主是要替代之前的函数表达式
  23. // 箭头函数没有自己的this,支持词法作用域/块级作用域
  24. </script>
  25. </body>
  26. </html>

4. 箭头函数语法

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>箭头函数语法</title>
  7. </head>
  8. <body>
  9. <script>
  10. // 1. 无参数
  11. let f1 = function () {
  12. console.log("f1()");
  13. };
  14. f1();
  15. // 箭头函数,没有参数,圆括号不能省
  16. f1 = () => console.log("->f1()");
  17. f1();
  18. // 进一步使用IIFE:立即执行函数简化。但越简化会越抽象
  19. // (() => console.log("->f1()"))();
  20. console.log("---------------");
  21. // 2. 单个参数
  22. let f2 = function (item) {
  23. console.log(`f2(${item})`);
  24. };
  25. f2("item");
  26. // 箭头函数
  27. f2 = (item) => console.log(`->f2(${item})`);
  28. f2("item");
  29. console.log("---------------");
  30. // 3. 多个参数
  31. let f3 = function (...items) {
  32. console.log("f3()", items);
  33. };
  34. f3(1, 2, 3, 4);
  35. // 箭头函数
  36. f3 = (...items) => {
  37. console.log(this);
  38. console.log("->f3()", items);
  39. };
  40. f3(5, 6, 7, 8);
  41. </script>
  42. </body>
  43. </html>

5. …rest/spread 剩余及扩展参数

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>...rest/spread</title>
  7. </head>
  8. <body>
  9. <script>
  10. // 1. ...rest(剩余参数),将多个参数归并到一个数组中, 用在函数声明的"参数列表中"
  11. let sum = (a, b) => a + b;
  12. console.log(sum(4, 5));
  13. // 累加
  14. sum = (...args) => args.reduce((prev, next) => prev + next, 0);
  15. console.log(sum(4, 5, 6, 7));
  16. // 遍历
  17. let f = (...items) => items.map((item) => console.log(item));
  18. f("apple", "pear", "orange");
  19. // 2. ...spread(扩展参数), 从一个集合中解析出一个个独立的元素,用在函数的调用的实际参数列表中
  20. f = (a, b, c) => console.log(a + b + c);
  21. f(3, 4, 5);
  22. f(...[3, 4, 5]);
  23. // 混合在一起
  24. // ...rest
  25. f = (a, ...items) => console.log(a, items);
  26. f(4, 5, 6, 7);
  27. // ...spread
  28. f(...[4, 5, 6], 7); // 这个方式跟前面是一样的。自己分散开了。
  29. </script>
  30. </body>
  31. </html>

6. 对象字面量的扩展

  • 所谓的对象字面量、数组字面量等其实就是对象、数组实例化的一种方法。

例如实例化一般分两种(https://www.cnblogs.com/zhuzhenwei918/p/6013363.html)

  1. 构造函数法,例如
  1. var person=new Object();
  2. person.name="zhuzhenwei";
  3. person.age=20;
  1. 对象字面量,例如
  1. var person={
  2. name"zhuzhenwei",
  3. age18
  4. };
  • 对象字面量有以下一点需要注意的地方:

    • 在末尾需加分号;表示结束。
    • 在一个属性定义之后用逗号分隔,最后一个属性不需要
    • 属性名可以加双引号,好处是我们可以包含错误的字符。并使用方括号表示法来访问对象的属性。
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>对象字面量的扩展</title>
  7. </head>
  8. <body>
  9. <script>
  10. // 1. 属性简化
  11. let createUser = (id, name, email) => ({
  12. id: id,
  13. name: name,
  14. email: email,
  15. });
  16. let user = createUser(1, "admin", "admin@php.cn");
  17. console.dir(user);
  18. // 当对象中的属性与属性值变量同名时,可省去变量值
  19. createUser = (id, name, email) => ({ id, name, email });
  20. user = createUser(2, "peter", "peter@php.cn");
  21. console.dir(user);
  22. // 2. 方法简化
  23. let site = {
  24. siteName: "php中文网",
  25. getSite: function () {
  26. return this.siteName;
  27. },
  28. };
  29. console.log(site);
  30. // es6方法简化
  31. let prop = "site Name";
  32. // 属性变量化处理(本来sitename是对象字面化中的一个属性名,现在通过一个变量来传递)
  33. site = {
  34. // siteName: "php.cn",
  35. prop: "php.cn",
  36. // : function 去掉
  37. getSite() {
  38. return this.siteName;
  39. },
  40. };
  41. console.log(site);
  42. let prefix = "user-";
  43. user = {
  44. [prefix + "name"]: "Trump",
  45. [`${prefix}email`]: "trump@php.cn",
  46. };
  47. console.log(user);
  48. </script>
  49. </body>
  50. </html>

7. 闭包原理

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>闭包原理</title>
  7. </head>
  8. <body>
  9. <script>
  10. // mdn: 闭包是可以访问自由变量的函数
  11. // c: 自由变量,相对于foo()中的变量而言
  12. let c = 50;
  13. function foo(a) {
  14. // 函数中有二类变量是自己的
  15. // 1. 函数参数: a
  16. // 2. 私有变量: b
  17. // 除此之外都是自由变量
  18. let b = 10;
  19. console.log(a, b);
  20. console.log(c);
  21. }
  22. console.log(foo(30));
  23. // <JavaScript权威指南>说过,从技术角度看,任何一个函数都 闭包
  24. // 实际开发中, 闭包需要满足二个条件
  25. // 1. 即使创建它的上下文已经销毁,它仍然存在(例如,内部函数从父函数中返回)
  26. // 2. 在代码中引用了自由变量
  27. // 简化一下
  28. // 1. 函数中必须要有一个子函数,且返回这个函数
  29. // 2. 在这个子函数中, 引用了父函数中的变量
  30. // o:从这个角度讲,闭包也可以理解为“自成系统”的函数
  31. </script>
  32. </body>
  33. </html>

8. 闭包的应用场景

  • 总算到了自己一直关心的,怎么去访问函数中的私有变量。之前在分页那块这方面留了一个尾巴。
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>闭包的应用场景</title>
  7. </head>
  8. <body>
  9. <script>
  10. // 1. 访问函数中的私有变量
  11. let foo = () => {
  12. // 私有变量
  13. let username = "peter-zhu";
  14. // 子函数(闭包), 当前的username相对于闭包(子函数get)来说是自由变量
  15. let get = () => username;
  16. // 必须返回这个闭包函数
  17. return get;
  18. };
  19. // console.log(username);
  20. let get = foo();
  21. console.log(get);
  22. console.log(get());
  23. console.log("---------------------");
  24. // 2. 快速创建多个全局可用的API
  25. // 要求这个脚本返回四个接口api
  26. let set, inc, dec, print;
  27. let manager = (n) => {
  28. let num = n;
  29. // 设置器
  30. set = (val) => (num = val);
  31. // 递增器
  32. inc = () => num++;
  33. // 递减器
  34. dec = () => num--;
  35. // 打印
  36. print = () => console.log(num);
  37. };
  38. // 初始化
  39. manager(10);
  40. print();
  41. inc();
  42. print();
  43. set(20);
  44. print();
  45. dec();
  46. print();
  47. // 例如点赞就是递增,取消关注可以用递减等。
  48. </script>
  49. </body>
  50. </html>

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议