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

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

cool442
cool442原创
2022年01月15日 15:51:12571浏览

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;

程序运行过程:

  • 为什么要函数套函数呢?
      我的理解是隐藏变量,函数套函数就是要造出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>
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议