欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JS的闭包、访问器属性、类与对象的创建和解构、获取DOM元素的二个API学习小结

程序员文章站 2022-03-13 12:37:35
...

1.闭包(Closure)

我的理解闭包只是一个叫法,其实闭包就是个比较特殊的函数(老师说是高阶函数,不明觉厉),符合以下特征的就叫闭包:

  • 就是函数套函数
  • 内部函数调用外部函数的变量
    例:
  1. // 闭包
  2. // 定义英雄函数
  3. let Hero = function () {
  4. // 初始血量
  5. let Blood = 999;
  6. // 加血包
  7. let addBlood = function (addNum) {
  8. Blood = Blood + addNum;
  9. return Blood;
  10. };
  11. return addBlood;
  12. };
  13. // 大血包
  14. const big_blood_bag = 300;
  15. // 建立英雄龙
  16. let dragon = Hero();
  17. console.log(`获得大血包,加血${big_blood_bag},现在血量${dragon(big_blood_bag)}`);
  18. // 输出:获得大血包, 加血300, 现在血量1299;

JS的闭包、访问器属性、类与对象的创建和解构、获取DOM元素的二个API学习小结

程序运行过程:
JS的闭包、访问器属性、类与对象的创建和解构、获取DOM元素的二个API学习小结

JS的闭包、访问器属性、类与对象的创建和解构、获取DOM元素的二个API学习小结

  • 为什么要函数套函数呢?
      我的理解是隐藏变量,函数套函数就是要造出1个局部变量。例如上面代码,英雄的血量如果不用闭包,而用全局变量,万一不小心把变量改成负数,或与其他变量名重复,就完了。所以不能让别人直接访问。但是用局部变量别人又无法直接访问,并且局部函数运行完变量就消失了,因此就用闭包来间接访问,并且变量不会消失。闭包内部用return来与外部联系。

  有点难理解,上课老师经常提到优雅,什么时刻能到那个境界。

  • 闭包的应用
    当一个函数需要多个参数的时候,不一定一次性全部传入,可以分批传入
    1. // 闭包应用
    2. // 分批传入参数
    3. // 例:游戏连击
    4. let doubleKill = function (oneKill) {
    5. let reward = "黄金甲";
    6. return function (towKill) {
    7. reward += "、束神环";
    8. return function (threeKill) {
    9. reward += "、焚天雷";
    10. return `牛批!三连击!!!掉血${
    11. oneKill + towKill * 2 + threeKill * 3
    12. }!奖励${reward}`;
    13. };
    14. };
    15. };
    16. let oneKill = doubleKill(180);
    17. let towKill = oneKill(260);
    18. let threeKill = towKill(480);
    19. console.log(threeKill);
    20. // 显示: 牛批!三连击!!!掉血2140!奖励黄金甲、束神环、焚天雷
  • “柯里化”函数:就像上面这个例子,分批次获取数据。

2. 访问器属性

  • JS中对象就是一组变量名和对应的值集合,值可以是数据(对象中叫属性)也可以是函数(对象中叫方法)。如下:
  1. // 访问器属性
  2. // 定义坦克对象
  3. let tank = {
  4. // 穿甲弹
  5. ArmorPie: 50,
  6. // 装甲
  7. Armor: 10,
  8. // 开炮
  9. fire(Num) {
  10. if (!isNaN(Num) && Num > 0) {
  11. this.ArmorPie = this.ArmorPie - Num;
  12. return `开了${Num}炮,还乘${this.ArmorPie}颗穿甲弹。`;
  13. } else {
  14. return "没上弹!";
  15. }
  16. },
  17. // 防御
  18. defend(Whether) {
  19. if (Whether === "中弹") {
  20. this.Armor--;
  21. return `完了,中弹了,装甲还乘${this.Armor}片了。`;
  22. } else {
  23. return "幸运之神眷顾,没被打中!";
  24. }
  25. },
  26. };
  27. // 一般正常调用对象方法是这样的:
  28. console.log(tank.fire(6));
  29. // 显示: 开了6炮,还乘44颗穿甲弹。
  30. console.log(tank.defend());
  31. // 显示: 幸运之神眷顾,没被打中!
  32. console.log(tank.defend("中弹"));
  33. // 显示: 完了,中弹了,装甲还乘9片了。
  34. // 使用访问器属性是这样的
  35. // 把对象的方法改为如下:
  36. tank = {
  37. // 穿甲弹
  38. ArmorPie: 50,
  39. // 装甲
  40. Armor: 10,
  41. // 中弹
  42. ShotIn: "",
  43. // 上弹数
  44. FireNum: 0,
  45. // 开炮
  46. // 此处语法改为 get 方法名,用于读取数据
  47. get shot() {
  48. if (this.FireNum > 0) {
  49. return `开了${this.FireNum}炮,还乘${this.ArmorPie}颗穿甲弹。`;
  50. } else {
  51. return "没开炮!";
  52. }
  53. },
  54. // 上炮弹
  55. // 此处语法改为 set 方法名,用于写数据
  56. set shot(FireNum) {
  57. if (FireNum > 0) {
  58. this.FireNum = FireNum;
  59. this.ArmorPie = this.ArmorPie - FireNum;
  60. return `开了${this.FireNum}炮,还乘${this.ArmorPie}颗穿甲弹。`;
  61. } else {
  62. return "没上弹!";
  63. }
  64. },
  65. };
  66. console.log(tank.shot);
  67. // 显示:没开炮
  68. tank.shot = 3;
  69. console.log(tank.shot);
  70. // 显示:开了3炮,还乘47颗穿甲弹。

3. 类与对象的创建和成员引用

  1. // 1. 构造函数
  2. // 先创建类
  3. let phone = function (cpu, px) {
  4. this.cpu = cpu;
  5. this.px = px;
  6. };
  7. // 用构造函数创建对象,通过构造函数可以创建多个对象;
  8. const p30 = new phone("麒麟990", "4k");
  9. const mi9 = new phone("高通980", "2k");
  10. console.log(p30);
  11. // 显示:phone { cpu: '麒麟990', px: '4k' }
  12. console.log(mi9);
  13. // 显示:phone { cpu: '高通980', px: '2k' }
  14. // 对象的方法一般是公共的、可调用的,通过方法操作当前对象的属性
  15. // 任何一个函数都有一个属性, 叫原型 prototype,普通函数的原型没用
  16. // 只有将原型当成构造函数创建对象时,才用到原型
  17. console.log(phone.prototype);
  18. // 显示:phone {} 这时是没有意义的
  19. // 用来创建对象的方法
  20. phone.prototype.call = function (num) {
  21. return `正在拨打${num}。`;
  22. };
  23. // 用原型创建方法后,可被所有实例使用
  24. console.log(p30.call("13877888877"));
  25. console.log(mi9.call("13311112222"));
  26. // 创建静态成员,将属性直接挂载到构造函数
  27. p30.screen = "6寸";
  28. console.log(p30.screen);
  29. // 创建私有成员:在对象内声明变量
  30. phone = function (cpu, px, rom) {
  31. let romnum = "8G";
  32. this.cpu = cpu;
  33. this.px = px;
  34. };
  35. const p50 = new phone("麒麟990", "4k", "12G");
  36. console.log(p50);
  37. // 传统的基于构造函数的类与对象, 语法上非常的复杂;
  38. // ES6中 用 class 可以包装以上操作
  39. // ES6 用class创建对象
  40. class TV {
  41. // 公共字段
  42. logo = "logo";
  43. scr_size = "scr_size";
  44. // 私有成员
  45. #core_cpu = "";
  46. // 构造方法
  47. constructor(logo, scr_size, cpu) {
  48. this.logo = logo;
  49. this.scr_size = scr_size;
  50. this.#core_cpu = cpu;
  51. }
  52. // 公共方法,即原型
  53. getInfo() {
  54. return `电视品牌为${this.logo},屏幕尺寸${this.scr_size},配置cpu${
  55. this.#core_cpu
  56. }`;
  57. }
  58. // 静态成员
  59. static on_off = "off";
  60. }
  61. const HuaWei_TV = new TV("华为智慧屏", "65寸", "麒麟520");
  62. console.log(HuaWei_TV.getInfo());
  63. // 显示:电视品牌为华为智慧屏,屏幕尺寸65寸,配置cpu麒麟520
  64. // 继承:可以扩展对象功能,即增加属性、方法
  65. class intelligence_TV extends TV {
  66. #packa = "";
  67. // 构造器必须将父类的复制过来
  68. constructor(logo, scr_size, cpu, AI, packaging) {
  69. // 用super 来引用原属性赋值
  70. super(logo, scr_size, cpu);
  71. // 新增属性
  72. this.AI = AI;
  73. this.#packa = packaging;
  74. }
  75. // 重写父类方法
  76. getInfo() {
  77. // 用super 引用原方法
  78. return `${super.getInfo()},采用最新智能AI-${this.AI},封装工艺${
  79. this.#packa
  80. }`;
  81. }
  82. 也可以用属性访问器;
  83. set packa(packaging) {
  84. this.#packa = packaging;
  85. console.log(this.#packa);
  86. }
  87. get packa() {
  88. console.log(this.#packa);
  89. return this.#packa;
  90. }
  91. }
  92. const HuaWei_ES55 = new intelligence_TV(
  93. "华为智慧屏",
  94. "55寸",
  95. "麒麟520",
  96. "小艾",
  97. "2D封装"
  98. );
  99. console.log(HuaWei_ES55.getInfo());
  100. // 显示:电视品牌为华为智慧屏,屏幕尺寸55寸,配置cpu麒麟520,采用最新智能AI-小艾,封装工艺2D封装
  101. // 用属性访问器访问
  102. HuaWei_ES55.packa = "5D立体封装";
  103. console.log(HuaWei_ES55.packa);

4. 数组与对象的解构

  1. // 数组解构
  2. // 语法:模板 = 数组
  3. let [hero , skill]=["超人","飞天、神力、神速"];
  4. console.log(hero , skill);
  5. // 更新
  6. [hero , skill]=["闪电侠" , "神速"];
  7. console.log(hero , skill);
  8. // 防止参数不足情况,使用默认值
  9. [hero , skill , sex = "男"]=["闪电侠" , "神速"];
  10. console.log(hero,skill,sex);
  11. // 参数过多情况如下用 ... 多余的放在数组n中
  12. let [a , b , ...n]=[1, 2, 3, 4, 5, 6, 7];
  13. console.log(a, b, n);
  14. // 二数交换
  15. let a1 = "超人";
  16. let b1 = "闪电侠";
  17. [a1 , b1] = [b1 , a1];
  18. console.log(a1 , b1);
  19. // 对象解构
  20. // 对象模板 = 对象字面量;
  21. let { hero, skill, sex } = { hero: "蚁人", skill: "变小", sex: "男" };
  22. console.log(hero, skill, sex);
  23. // 更新操作。注意:大括号不能出现在等号左边,使用括号转为表达式
  24. ({ hero, skill, sex }) = { hero: "蚁人", skill: "变小", sex: "男" };
  25. // 注意:当左边模板中的变量与前面命名冲突,使用别名
  26. let { hero:hero_name, skill:hero_skill, sex:hero_sex } = { hero: "琴", skill: "操控元素", sex: "女" };
  27. console.log(hero_name, hero_skill, hero_sex);
  28. // 克隆对象 类似参数过多用 ... 压到1个变量
  29. let {...super_hero} = {
  30. hero: "蚁人",
  31. skill: "变小",
  32. change(){
  33. return `${this.hero}现在${this.skill}`
  34. } };
  35. console.log(super_hero);
  36. // 对象解构应用:用来传递参数,即参数用对象模板,调用时用模板字面量赋值
  37. function show({ hero, skill, sex }){
  38. return hero+skill+sex
  39. }
  40. console.log(show({ hero: "蚁人", skill: "变小", sex: "男" }));

5. JS引入到浏览器中

  • JS是在浏览器(前端)中运行的
  • node.js 是在服务器(后端)上运行的
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>JS引入到浏览器</title>
  8. </head>
  9. <body>
  10. <!-- 1. 写到元素的事件属性中 -->
  11. <button onclick="alert('开始')">弹窗</button>
  12. <!-- 2. 用script引入js脚本 -->
  13. <button onclick="alt(this)">保存</button>
  14. <script>
  15. function alt(ev) {
  16. ev.textContent = "保存成功";
  17. }
  18. </script>
  19. <!-- 3. 引入外部脚本 -->
  20. <button onclick="show()">显示</button>
  21. <script src="show.js"></script>
  22. </body>
  23. </html>

6. 获取DOM元素

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>获取dom元素</title>
  8. </head>
  9. <body>
  10. <ul class="list">
  11. <li class="item">项目1</li>
  12. <li class="item">项目2</li>
  13. <li class="item">项目3</li>
  14. <li class="item">项目4</li>
  15. <li class="item">项目5</li>
  16. </ul>
  17. <script>
  18. // 最常用的两个API,基本可以满足使用
  19. // 1. 选择一组元素,语法 querySelectorAll("css选择器")
  20. // 2. 选择一个元素,语法 querySelector("css选择器")
  21. // 例:将所有li字体颜色设置为红色
  22. const Li = document.querySelectorAll(".item");
  23. // console.log(Li);
  24. for (let i = 0, length = Li.length; i < length; i++) {
  25. Li[i].style.color = "red";
  26. }
  27. // 将第一、三个字号改为2rem
  28. // console.log(document.querySelector(".item"));
  29. document.querySelector(".item").style.fontSize = "2rem";
  30. document.querySelector(".item:nth-of-type(3)").style.fontSize = "2rem";
  31. </script>
  32. </body>
  33. </html>