一、Js逼格

  1. js是解释型语言:看一行翻译一行(有<>尖括号的都为解释型语言)

    优点:跨平台
    缺点:速度稍慢

  2. c++和c是编译型语言:通篇翻译,c最终生成 .obj文件

    优点:快
    缺点:不能跨平台

  3. Java既不是编译型语言,也不是解释型语言,他有一个Java虚拟机JVM

    Java—->javac——>编译———> .class ——->JVM———->解释执行

  4. JS是单线程的

    单线程:一个时间只能做一件事(同步:前一个事情做完了,才能做后面一件事)
    多线程:一个时间可以做多件事(异步:同时执行几件事)

  5. Javascript<====>ECMAscript

  6. JS三大部分:ECMAScript、BOM、DOM
  7. 浏览器组成
  • shell部分:浏览器上面文件,查看…可以点击的部分
  • 内核部分(1)、渲染引擎:解释html、css等代码

    1. (2) js引擎:解释JS代码<br /> 3)、其他模块
  1. 主流浏览器及其内核
  • IE trident
  • Chrome webkit/blink
  • firefox Gecko
  • Opera presto
  • Safari webkit

    二、JS基本语法

    2.1 变量类型

    (1)、原始值: Number(浮点型· ) Boolean String undefined(未赋值的数) null(占位置)
    (2) 、引用类型:Array Object function …Date RegExp
    image.png

    1. <script>
    2. // 原始值:stack(栈区-先进后出)
    3. var a=1;
    4. var b=a;
    5. a=10;
    6. console.log(a);//10
    7. console.log(b);//1
    8. // 引用值:heap(堆区)--栈中存放的为堆中的地址,push()方法改变的为原始的arr
    9. var arr=[1,2];
    10. var arr1=arr;
    11. arr.push(3);
    12. console.log(arr);// [1,2,3]
    13. console.log(arr1);// [1,2,3]
    14. // 引用值:这里是重新为arr2赋值,在堆区中重新开辟了一个存储空间,arr2指向的为新的存储空间,arr3指向的还是原来的存储空间
    15. var arr2=[1,2];
    16. var arr3=arr2;
    17. arr2=[1,3]
    18. console.log(arr2);// [1,3]
    19. console.log(arr3);// [1,2]
    20. </script>

    01.PNG02.PNG03.PNG

    2.2 运算符

    ```javascript // 运算符

    1. console.log(0 / 0); //NaN
    2. console.log(1 / 0); //Infinity
    3. console.log(-1 / 0); //-Infinity
    4. /**
    5. * 逻辑运算符
    6. * undefined,null,"",0,NaN,fakse----->false
    7. * 短路逻辑运算符:&& ||
    8. */
    9. // && 与运算符,如果前面为真,则直接返回后面的(第二个数|式子),如果第一个为假,则直接返回第一个
    10. var y1 = 1 + 1 && 1 - 1;
    11. console.log(y1); //0
    12. var y2 = 3 && 4;
    13. console.log(y2);//4
    14. var y2 = 0 && 4;
    15. console.log(y2);//0
    16. // || 或运算符,如果第一个为真,则直接返回第一个数或式子,第一个为假,直接返回第二个数或式子
    17. var h1 = 3 || 4; //4
    18. console.log(h1);
    19. var h2 = 2 > 1 || 2 > 3;
    20. console.log(h2); //true
    21. var h2 = 2 < 1 || 2 ;
    22. console.log(h2); //2
    23. // !非(先转为boolean值,再非运算)
    24. console.log(!123);//false
    25. console.log(!"xxx");//false
    26. console.log(!"");//true
    27. console.log(!!null);//false
  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/2544943/1611941724934-d4deb0e4-1d73-4fd4-8413-fe08f4b955e0.png#align=left&display=inline&height=452&margin=%5Bobject%20Object%5D&name=image.png&originHeight=452&originWidth=813&size=52559&status=done&style=none&width=813)
  2. <a name="8Bk7u"></a>
  3. ### 2.3 循环
  4. ```javascript
  5. //var score=parseInt(window.prompt('请输入一个数字'));
  6. //var score=parseInt(prompt('请输入一个数字'));
  7. var score = +prompt('请输入一个数字');
  8. /**
  9. *1.else--if语句必须是互斥的
  10. */
  11. if (score > 90 && score <= 100) {
  12. console.log("Alibaba");
  13. } else if (score > 80 && score <= 90) {
  14. console.log("tencent toutiao meituan");
  15. } else if (score > 70 && score <= 80) {
  16. console.log("baidu");
  17. } else if (score <= 60) {
  18. console.log("蘑菇街");
  19. } else {
  20. console.log("输入错误");
  21. }
  22. /**
  23. * 2.for循环语句
  24. * (1).var i=0;
  25. * (2).if(i<10){console.log('aaa');}
  26. * (3).i++
  27. * (4).重复执行(2)和(3)直到:i>=10
  28. */
  29. for (var i = 0; i < 10; i++) {
  30. console.log('aaa');
  31. }
  32. var i = 1;
  33. for (; i;) {
  34. document.write("a__");
  35. i++;
  36. if (i == 11) {
  37. i = 0;
  38. }
  39. }
  40. document.write('<hr/>')
  41. for (var i = 0; i < 100; i++) {
  42. if (i % 3 == 0 || i % 5 == 0 || i % 7 == 0) {
  43. document.write(i + " ")
  44. }
  45. }
  46. var j = 10;
  47. for (; j--;) {
  48. console.log(j);
  49. }
  50. document.write('<hr/>')
  51. /**
  52. * 3.while循环
  53. */
  54. var i = 0;
  55. while (i < 10) {
  56. document.write(i + " ")
  57. i++;
  58. }
  59. document.write('<hr/>')
  60. // 逢7打印
  61. var k = 0
  62. while (k < 100) {
  63. if (k % 7 == 0 || k % 10 == 7) {
  64. document.write(k + " ")
  65. }
  66. k++
  67. }
  68. /**
  69. * 4.do...while循环(无论条件是什么都会执行一次)
  70. */
  71. document.write('<hr/>')
  72. var k = 0
  73. do {
  74. document.write("哒 ")
  75. k++;
  76. } while (k < 10)

2.4 数组和对象

  1. 1.typeof判断数据类型:number string boolean object undefined function
  2. 注意:数组也是对象object, null也是对象object
  3. 2.类型转换
  4. 2.1null转数字为0undefined转数字为NaN(但是为数字类型)
  5. 2.2 parseInt(数,进制{2-36})以‘进制{2-36}’为基底,转为十进制
  6. parseFloat
  7. 2.3 String把任意类型转为字符串
  8. 2.4 Boolean()把除了 "",null,undefined,falseNaN0 转为true
  9. 2.5 toString()转为字符串,注意:undefinednull不能用toString()转字符串
  10. xxx.toString(2,8,10,16)以10进制为基底,转为目标进制
  11. 3.隐式转换
  12. 3.1 isNaN()判断是不是数字,判断之前用Number()转化
  13. 3.2 ++和--(运算之前用Number()转化)
  14. 3.3 +和-(都会把运算的值转为数字Number)
  15. 当+两侧有一个是字符串就调用String(),把两个都转为字符串
  16. 3.4 * / % - 隐式转换为Number
  17. 3.5 < > = <= >= (当有一个比较的为数字时,隐式转为数字,当两边都为字符串,比较AISC码值)
  18. 3.6 == != (Number隐式转换)
  19. console.log(1 == "1"); //true
  20. console.log(1 == true); //true
  21. console.log(false > true);//false (false=0,true=Number(true)=1)
  22. console.log(2 > 1 > 3);// 2>1=true=1 1>3=false
  23. console.log(undefined==null);//true
  24. console.log(undefined===null);//false
  25. //不能用NaN去验证NaN(不等)
  26. console.log(NaN==NaN);//false
  27. //注意:typeof()返回的为字符串
  28. console.log(typeof(undefined));//undefined
  29. //当使用一个没有定义的变量时,会报错,在typeof中不会报错
  30. //经过typeof()判断后会返回一个(字符串)
  31. console.log(typeof(aa));//undefined
  32. console.log(typeof(typeof(a)));//string

三、函数


1. 代码要求高内聚,低耦合(少的重复,重复部分抽取出来,写为函数)
1. 函数中,形参和实参的个数可以不相同
1. 函数参数—-arguments是,保存所有的实参,是一个数组,不能用forEach遍历
1. 函数名.length为形参长度,arguments.length为实参长度
  1. /**
  2. * 1.函数声明
  3. */
  4. function test1() {
  5. console.log(test1.name);//test1
  6. }
  7. /**
  8. * 2.命名函数表达式
  9. */
  10. var test2 = function abc() {
  11. console.log(test2.name);//abc
  12. }
  13. /**
  14. * 3.匿名函数表达式-----函数表达式
  15. */
  16. var test3 = function () {
  17. console.log(test3.name);//test3
  18. }
  19. test1();
  20. test2();
  21. test3();
  22. console.log(test2);//ƒ abc() {console.log(test2.name);}
  23. //console.log(abc);//abc is not defined
  24. /**
  25. * 4.函数参数---arguments是,保存所有的实参,是一个数组,不能用forEach遍历
  26. */
  27. function test4(a,b){
  28. console.log(arguments);
  29. for(var i=0;i<arguments.length;i++){
  30. console.log(arguments[i]);
  31. }
  32. console.log(test4.length,"形参长度");//2
  33. }
  34. test4(1,2,3,4,5,6);//Arguments(6) [1, 2, 3, 4, 5, 6, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  35. function func(a,b){
  36. b=3;
  37. console.log(b);
  38. console.log(arguments[1],"arguments");//3
  39. }
  40. // 注意:实参有几个,形参就有几个,b和arguments[1]值相等,但是不是同一个东西,有一个映射关系
  41. // func(1,2);//3 "arguments"
  42. // 实参只有一个,则b为undefined,修改b时,arguments[1],不会再跟着变,应为arguments数组只有【1】
  43. func(1);//undefined "arguments"

3.1 函数练习

  1. /**
  2. * 3.输入一个数字,取反 并 转为汉字的形式
  3. */
  4. function resver(num) {
  5. var num=prompt("输入数字");
  6. // 注意:从页面传过来的均为字符串,可遍历,取反,倒着遍历
  7. var str=''
  8. for(var i=num.length-1;i>=0;i--){
  9. // str+=num[i]
  10. str+=transform(num[i])
  11. }
  12. console.log(str);
  13. }
  14. // 把取反的转为汉字
  15. function transform(num){
  16. switch(num){
  17. case "1":return "一";break;
  18. case "2":return "二";break;
  19. case "3":return "三";break;
  20. case "4":return "四";break;
  21. }
  22. }
  23. resver()

3.2 递归


1. 根据给定的题目找规律,列出函数 关系式
1. 根据题目 找到递归的出口(已知条件)
1. 递归:自己调用自己本身(函数)
  1. // 1. 阶乘
  2. function jie(n) {
  3. if (n == 1 || n == 0) {
  4. return 1;//递归出口
  5. }
  6. return jie(n - 1) * n;
  7. }
  8. console.log(jie(6));
  9. // 2. 输出斐波那契数列
  10. function f(n) {
  11. if(n==1 || n==2){
  12. return 1;//递归出口
  13. }
  14. if(n>2){
  15. return f(n-1)+f(n-2)
  16. }
  17. }
  18. console.log(f(5));

四、预编译

**先生成GO,再生成AO,执行函数时,先找自己AO,自己没有再找GO**

| JS三部曲:
1. 语法分析
1. 预编译(解释执行前,先通篇扫描一下,看看有没有语法错误)
(1)、函数声明整体提升 function test(){ console.log(“a”);}
(2)、变量的声明提升 var a; ,变量的赋值不提升 a=1;
3. 解释执行
注意:
1. 任何变量未经声明就赋值为全局变量,a=10;(全局的:window.a=10)
1. 一切声明的全局变量,全是window属性(var a=10;——->window.a=10)
1. window是一个全局的域,var a=10; 相当于 window {a:10}
**预编译发生在函数执行的前一刻:**
1. 创建AO对象(执行上下文)
1. 找形参和变量声明,将变量和形参名作为AO的属性名,值为undefined,var test=function(){} 变量声明
1. 将实参值和形参值相统一
1. 在函数体里找函数声明,值赋予函数体 function test(){ }
全局的预编译:
1. 创建Go对象(window==Go)
1. 同上
| | | | —- | —- | —- | | |

  1. function test() {
  2. // 在这里,123先赋值给b,但是b是未经声明的,所以b是全局的,但是var a=b;时,a声明了,是函数局部的
  3. //var a=b=123; window{b:123}
  4. var a = b = 123;
  5. }
  6. test();
  7. console.log(window.b); //123
  8. console.log(window.a); //undefined
  9. console.log(b); //123 ---> window.b
  10. //console.log(a); //a is not defined,a是局部的,不是window所有
  11. /**
  12. * AO{ GO{
  13. * a:undefined b:123
  14. * } }
  15. */
  16. /*------------------------------------------------------------*/
  17. /**
  18. * 1.创建AO对象
  19. * AO{
  20. * a:function a() {},
  21. * b:undefined,
  22. * d:function d(){}
  23. * }
  24. * 声明已经完成,后面读取过程中,赋值即可
  25. */
  26. function fn(a) {
  27. console.log(a); //function a() {}
  28. var a = 123;
  29. console.log(a); //123
  30. //函数声明
  31. function a() {};
  32. console.log(a); //123
  33. //变量声明
  34. var b = function () {};
  35. console.log(b); // function () {}
  36. function d() {};
  37. }
  38. fn(1)
  39. /*-------------------------------------------------------*/
  40. /**
  41. * AO{
  42. * a:1,
  43. * b:function b() {},
  44. * c:undefined,
  45. * d:function d() {}
  46. * }
  47. */
  48. function test1(a, b) {
  49. console.log(a); //1
  50. c = 0;
  51. var c;
  52. a = 3;
  53. b = 2;
  54. console.log(b); //2
  55. function b() {}
  56. function d() {}
  57. console.log(b); //2
  58. }
  59. test1(1);
  60. /*-----------------------------------------------------*/
  61. function test2(a, b) {
  62. console.log(a); //function a(){}
  63. console.log(b); //undefined
  64. var b = 234;
  65. console.log(b); //234
  66. a = 123;
  67. console.log(a); //123
  68. function a() {};
  69. var a;
  70. b = 123;
  71. var b = function () {};
  72. console.log(a); //123
  73. console.log(b); //function (){}
  74. }
  75. test2(1)
  76. /*-------------------------------------------------------------*/
  77. /**
  78. * Go{
  79. * a:function a(){}
  80. * }
  81. */
  82. var a = 123;
  83. function a() {}
  84. console.log(a, "全局"); //123
  85. /*----------------------先GO,再AO-----------------------------*/
  86. console.log(mytest); //ƒ mytest() {....}
  87. function mytest(mytest) {
  88. console.log(mytest); //ƒ mytest() {}
  89. var mytest = 234;
  90. console.log(mytest); //234
  91. function mytest() {}
  92. }
  93. mytest(1);
  94. var mytest = 123;
  95. /*-----------------------------函数:先AO,没找到再GO----------------------------*/
  96. /**
  97. * AO{ GO{
  98. * a:undefined,
  99. * fn:function fn(){....}
  100. * } }
  101. */
  102. var global = 100;
  103. function fn() {
  104. console.log(global);
  105. }
  106. fn();
  107. /*-----------------------------------------------------*/
  108. /**
  109. * AO{ GO{
  110. * g:undefined g:undefined,
  111. * fn:function fn(){....}
  112. * } }
  113. * AO有自己的g,则不会去找全局的g
  114. */
  115. g = 100;
  116. function fng() {
  117. console.log(g); //undefined
  118. g = 200;
  119. console.log(g); //200
  120. var g = 300;
  121. }
  122. fng();
  123. var g;
  124. /*-----------------------------------------------------------*/
  125. function ff() {
  126. console.log(b);//undedined
  127. if (a) {
  128. var b = 100;//预编译与if语句无关,只看变量声明
  129. }
  130. c = 234;
  131. console.log(c);//234
  132. }
  133. var a;
  134. ff();
  135. a = 10;
  136. console.log(c);//234

4.1 练习题

  1. /**
  2. * 1.str隐式类型转换
  3. * 2.false==1是一个判断,结果为boolean值
  4. * 3.typeof(a),a没有定义,返回“undefined”,(-true)=-1,
  5. * ( +undefined)转为数字为NaN,但(+""),则&&两边均为字符串,变为boolean值为true
  6. * 4."11" * 2转为数字
  7. * 5.(!!" ")字符串转为boolean为true,这不是空串,(!!"")空串转为false,!!false还为false
  8. * ‘||’两边有一个为true,后面不在执行
  9. */
  10. var str = false + 1;
  11. console.log(str);//1
  12. var demo = false == 1;
  13. console.log(demo);//false
  14. if (typeof (a) && -true + (+undefined) + "") {
  15. console.log("精彩知识");//精彩知识
  16. }
  17. if (11 + "11" * 2 == 33) {
  18. console.log("精彩知识");//精彩知识
  19. }
  20. !!" " + !!"" - !!false || console.log("不能打印哦");

五、作用域和作用域链

Snipaste_2021-01-21_23-56-02.pngSnipaste_2021-01-21_23-59-58.png

  1. /**
  2. * a先被定义,a.[[scope]]中存在一个全局的执行上下文 GO
  3. * a被执行时生成一个a的执行时期上下文,AO,放在作用域链a.[[scope]]的顶端
  4. * a执行时b被创建,b.[[scope]]中包含的是a()的AO和GO
  5. * b被执行时产生b自己的执行上下文,放在b.[[scope]]的顶端
  6. */
  7. function a() {
  8. function b() {
  9. var b = 123;
  10. }
  11. var a=123;
  12. b();
  13. }
  14. var glbo=100;
  15. a();

Snipaste_2021-01-22_00-14-43.pngSnipaste_2021-01-22_00-15-37.pngSnipaste_2021-01-22_00-17-45.pngSnipaste_2021-01-22_00-20-22.pngSnipaste_2021-01-22_00-48-02.pngSnipaste_2021-01-22_00-47-21.png

5.1 闭包

闭包:当内部函数被保存到外部时,将会生成闭包。(不论是return 还 把函数赋值给全局变量)
危害:闭包会导致原有作用域链不释放,造成内存泄漏—->占内存空间
作用:(1).实现共有变量 eg:累加器
(2).可做缓存(存储结构) eg:eater
(3).实现封装,属性私有化 eg:Person()
(4).模块化开发,防止污染全局变量
  1. /**
  2. * 1. a定义和执行时a.[[scope]]产生--> aAO 和 GO,a执行时把b的副保存到了demo,此时a执行完切断与aAO连线,不会切断其他函数与aAO连线
  3. * 2. b定义时的环境为a执行时环境:b.[[scope]]产生--->aAO 和 GO(b引用aAO,但a执行完,他与的aAO的线已切断)
  4. * 3. b执行时产生自己的上下文bAO,当b执行完成后bAO释放,再次执行时再生成一个新的bAO
  5. * 但是每一个bAO都引用的为aAO中的变量,aAO没有释放
  6. */
  7. function a(){
  8. var num=100;
  9. function b(){
  10. num++;
  11. console.log(num);
  12. }
  13. return b;
  14. }
  15. var demo=a();
  16. demo();//101
  17. demo();//102
  18. var demoaa;
  19. function tt() {
  20. var abc = 100;
  21. function a() {
  22. console.log(abc);
  23. }
  24. demoaa = a;
  25. }
  26. tt();
  27. demoaa();

Snipaste_2021-01-22_08-57-21.png1Snipaste_2021-01-23_09-38-58.png

  1. /**
  2. * 1. a定义和执行时a.[[scope]]产生--> aAO 和 GO,a执行时把b的副保存到了demo,此时a执行 完切断与aAO连线,不会切断其他函数与aAO连线
  3. * 2. b定义时的环境为a执行时环境:b.[[scope]]产生--->aAO 和 GO(b引用aAO,但a执行完,他与 的aAO的线已切断)
  4. * 3. b执行时产生自己的上下文bAO,当b执行完成后bAO释放,再次执行时再生成一个新的bAO
  5. * 但是每一个bAO都引用的为aAO中的变量,aAO没有释放
  6. */
  7. function a() {
  8. var num = 100;
  9. function b() {
  10. num++;
  11. console.log(num);
  12. }
  13. return b;
  14. }
  15. var demo = a();
  16. demo(); //101
  17. demo(); //102
  18. /**
  19. * 2.闭包实现累加器
  20. */
  21. function add() {
  22. var count = 0;
  23. function demo() {
  24. count++;
  25. console.log(count);
  26. }
  27. return demo;
  28. }
  29. var counter = add();
  30. counter(); //1
  31. counter(); //2
  32. counter(); //3
  33. counter(); //4
  34. counter(); //5
  35. /**
  36. * 2.闭包可以实现缓存(1)
  37. */
  38. function test() {
  39. var num = 1;
  40. function a() {
  41. num++;
  42. console.log(num);
  43. }
  44. function b() {
  45. num--;
  46. console.log(num);
  47. }
  48. return [a, b]
  49. }
  50. var myArr = test();
  51. // 他们都在操作test里面的num,a()和b()用的闭包时同一个testAO,连线都在testAO
  52. myArr[0](); //2
  53. myArr[1](); //1
  54. /**
  55. * 闭包可以实现缓存(2)
  56. */
  57. function eater() {
  58. var food = "";
  59. var obj = {
  60. eat: function () {
  61. console.log('我喜欢吃' + food);
  62. food=""
  63. },
  64. addFood: function (myfood) {
  65. food = myfood
  66. }
  67. }
  68. // 对象obj里面的两个函数,也和food形成了闭包,他们可以操作eaterAO中的food
  69. return obj;
  70. }
  71. var eater1 = eater();
  72. eater1.addFood("苹果");
  73. eater1.eat();//我喜欢吃苹果

image.png
**闭包实现私有化变量**
Snipaste_2021-01-27_00-25-55.png

5.2 立即执行函数


1. 立即执行函数:此函数没有声明,在一次执行过后立即释放。适合做初始化工作(只能执行一次)
1. 立即执行函数可以有 参数 和 返回值
1. 立即执行函数 也有执行时期上下文,可进行预编译
1. 模式:(function(){ }());—->W3C模式 (function (){ })();
1. 只有函数表达式才能被执行符号()执行
1. 被执行符号()执行的表达式,他的名字会被自动忽略—>undefined(表达式)/xxx is not defined(声明转表达式)
1. ‘ + / - / ! ‘可以把一个函数声明转为一个函数表达式,用执行符号执行
1. 立即执行函数原理:
- function test(){} 是一个函数声明,当用括号括起来后变为函数表达式,用执行符号直接执行
- (function (){}()) 这样写是因为数学运算先看外面大括号,执行符号放在里外是一样的
- 表达式执行后函数名字被忽略,所以写不写名字test效果一样
  1. /*----------------------------(1):函数声明------------------------------------*/
  2. function test1() {
  3. console.log("aaaa");
  4. //}()---->这样写是报错的,这是执行一个函数声明
  5. }
  6. test1(); //这样可执行,这是执行一个函数表达式;test==123...
  7. /*--------------------------(2):函数表达式-----------------------------------*/
  8. var test2 = function () {
  9. console.log("bbb");
  10. }() //可立即被执行,这是一个匿名函数表达式
  11. console.log(test1 + "----test1"); //function test1(){...}
  12. console.log(test2 + "----test2"); //undefined--->此时变为 var test2;
  13. /*----------------------(3): + - ! 把声明转为表达式-------------------------*/
  14. + function test3() {
  15. console.log("aaaa");
  16. }();
  17. console.log(test3 + "----test3"); //test3 is not defined
  18. /*---------------------(4):执行原理---------------------------------*/
  19. (function test4(){
  20. console.log("111234");
  21. })();

5.3 闭包和立即执行函数问题

注意:函数执行完了会被销毁不是函数本身不见了,而是切断了与作用域链 AO 之间的联系
(1).for循环产生十个匿名函数表达式,被保存在test()函数的外部,此时这十个函数表达式分别和test()形成了闭包,有同一个testAO,他们共用一个i,且i在for循环后值变为10,因此在调用这十个函数时,他们访问的都为testAO**里面的i,且i=10;所以会打印十个10**

  1. function test() {
  2. //一个数组里面有10个函数 arr[function(){},function(){}...]
  3. var arr = [];
  4. for (var i = 0; i < 10; i++) {
  5. //for循环执行十次,产生十个独立的函数,这十个函数分别和test()形成闭包,共用test()里面的i
  6. //当test()执行完才会执行arr[i]绑定的函数,此时i已经变为10
  7. arr[i] = function () {
  8. console.log(i);
  9. }
  10. }
  11. return arr;
  12. }
  13. var myArr1 = test();
  14. for (var j = 0; j < myArr1.length; j++) {
  15. myArr1[j]();
  16. }

(2).若想要不是每次都输出十个10,而是输出1~9,则需要借助立即执行函数来实现,即for循环产生十个立即执行函数,立即执行函数入参为i,且立即执行函数又和arr[i]=function(){…}形成了闭包,此时arr[i]执行时使用的i为立即执行函数中的i,这个i为产生立即执行函数时,传入的参数,他们分别为1~9,所以输出结果1~9(其实此时的作用域链为:arr[i]AO—立即执涵AO—testAO—GO)

  1. function test() {
  2. //一个数组里面有10个函数 arr[function(){},function(){}...]
  3. var arr = [];
  4. for (var i = 0; i < 10; i++) {
  5. /**
  6. * 1. for循环执行十次,产生十个立即执行函数,这十个函数分别和test()形成闭包
  7. * 2. 立即执行函数是立即执行的,把for循环当前i作为参数,执行立即函数里面的arr[i]赋值语句,产生函 数表达式
  8. * 3. 每个立即函数里面的arr[i]=...和立即执行函数执行闭包,使用立即执行函数里的 参数i
  9. */
  10. (function (j) {
  11. arr[j] = function () {
  12. console.log(j);
  13. }
  14. })(i);
  15. }
  16. return arr;
  17. }
  18. var myArr1 = test();
  19. for (var j = 0; j < myArr1.length; j++) {
  20. myArr1[j]();//1 2 3 4 5 6 7 8 9
  21. }

六、对象、包装类

image.png

6.1 对象

|
1. 当删除(delete obj.xxx)一个对象属性后,该属性值为undefined
1. 对象的定义(this指的是当前对象)
(1).字面量形式:var obj={name:”xx”,age:20,…}
(2).自定义构造函数:function Student(name,age){ this.name=name, this.age=age}
3. 构造函数内部原理:
(1).在函数体最前面隐式加上函数体 this={}
(2).执行自家写的 this.name=name,this.age=age ,把他们加入this对象
(3).在函数体结尾隐式返回:return th**is**;
(注意:如果我们自己显示的在函数体结尾返回一个 对象或数组,则new出的值为 对象为数组;如果自己 显示返回表达式/变量,则返回的为隐式的this) | | | | —- | —- | —- | | |

  1. /*------------------------(1).字面量创建对象——-----------------------------*/
  2. var obj={
  3. name:"小希",
  4. age:20,
  5. myhobby:"",
  6. eat:function(){
  7. console.log("我爱吃饭");
  8. },
  9. like:function(hobby){
  10. this.myhobby=hobby;
  11. console.log("我喜欢---"+this.myhobby);
  12. }
  13. }
  14. console.log(obj.name+"---before");
  15. obj.gender="女";
  16. obj.like("足球");
  17. obj.age=30;
  18. delete obj.name;//当删除一个对象属性后,该属性值为undefined
  19. console.log(obj.name+"---del");
  20. console.log(obj);
  21. /*------------------------(1).自定义构造函数创建对象——-----------------------------*/
  22. function Person(name, age) {
  23. //1.当new一个对象隐式 var this={}
  24. //2. AO{name:"",age:""}
  25. this.name = name;
  26. this.age = age;
  27. //3.隐式返回:return this;
  28. // return {per:"人"}
  29. // return [1,2,3]
  30. // return 123;
  31. }
  32. // var p = Person("张三", 22); //p为undefined
  33. var p = new Person("张三", 22);
  34. console.log(p);

image.png

6.2 包装类


1. 只有对象才有属性和方法,new Number(123),new String(‘www’),new Boolean(true)这样new出来的都是对象,可以添加属性和方法,number类型对象可以参与运算(number2),但运算完后又变成了表达式形式(number类型)
1. 注意:undefined和null不可有属性和方法
1. *字面量形式的number,string,boolean值是一定没有属性和方法的
,但是我们给他们添加属性和方法也不会报错,但访问的时候,添加的属性值为undefined———>系统帮我们隐式转换了包装类
1. 包装类:new Number() new String() new Boolean()
  1. var num = 123;
  2. //1.系统帮我们把字面量包装:new Number(123).len=4; 执行完这一步后,这个对象立即deldet销毁
  3. num.len = 4;
  4. //2.访问时包装:new Number(123).len;这个new出来的对象与上面不同,上面被销毁了,新的里面没有len 属性
  5. console.log(num.len); //undefined
  6. console.log(num.lengtn); //undefined
  7. var str = "abxc";
  8. //系统包装类:new String('abxc').length=2;但执行后就立即销毁了,所以再访问str.length仍为真实长度
  9. str.length=2;
  10. console.log(str);//abxc
  11. // 字面量没有属性和方法,但是length属性是字符串对象自带的,转为:new String("abxc").length=4
  12. console.log(str.length); //4

七、原型、原型链

image.png
Snipaste_2021-01-25_00-26-26.png
image.png

  1. Person1.prototype={
  2. name:'a',
  3. //sayName里面的方法,谁调用他,this就是谁
  4. sayName:function (){
  5. console.log(this.name);
  6. }
  7. }
  8. function Person1(){
  9. this.name='b'// console.log(per1.name);----->b
  10. }
  11. var per1=new Person1();
  12. console.log(per1.name);//a Person1自身没有name时

|
1. var obj={}——>系统自动转换new Object()
1. var obj=new Object()两者效果相同,都有原型,建议使用字面量形式创建对象
1. obj.proto———->Object.prototype(原型指向)
1. 绝大多数对象都会继承自 Object.prototype——————->不是所有
1. 创建对象另一种方式:var p=Object.create(原型|null),当里面为null时,是没有原型的;当为原型时,继承原型
image.png | | | | —- | —- | —- | | |

image.png

7.1 toString()方法

  1. var num=123;
  2. console.log(num.toString());//"123" new Number(num).toString()
  3. //num的原型 Number.prototype----->Number.prototype.__proto__----->Object.Prototype(原型链)
  4. //Number.prototype本身有toString()属性,是对从Object.Prototype继承来的toString()的重写
  5. //Number.prototype={toString:function(){ }}

7.2 call/apply(重点)

**借用别人的函数实现自己的功能**

7.2.1 call

  1. /*
  2. function test(){
  3. }
  4. test();---------------------->实质:test.call()
  5. */
  6. function Person1(name, age) {
  7. //this==obj call改变了this的指向,此时利用Person构造函数,obj既有name又有age(利用别人的方法实现自己的功能)
  8. this.name = name; //obj.name=name
  9. this.age = age; // obj.age=age
  10. }
  11. var person1 = new Person1("小", 12);
  12. var obj = {
  13. }
  14. Person1.call(obj, '李', 10); //没有new的时候this是window,call之后this变成了obj
  15. console.log(obj); // {name:"李",age:10}
  16. /*---------------------------------------------------------------------------------------*/
  17. function Student1(name, age) {
  18. //构造函数隐式在函数体前面加:var this={}
  19. this.name = name
  20. this.age = age
  21. }
  22. function Student2(name, age, phone, gender) {
  23. //构造函数隐式在函数体前面加:var this={}
  24. //利用call改变指向,利用Students实现一部分功能,相当于在this中添加属性
  25. Student1.call(this, name, age)
  26. this.phone = phone;
  27. this.gender = gender;
  28. }
  29. var s = new Student2("桂", 21, "110-1101", '男');
  30. // Student1.call(s,"桂",21);
  31. console.log(s);
  32. /*---------------------------------------------------------------------------------------*/
  33. function Wheel(wheelSize,style){
  34. this.wheelSize=wheelSize
  35. this.style=style
  36. }
  37. function Sit(c,sitColor){
  38. this.c=c
  39. this.sitColor=sitColor
  40. }
  41. function Model(height,width){
  42. this.width=width
  43. this.height=height
  44. }
  45. function Car(wheelSize,style,c,sitColor,height,width){
  46. Wheel.call(this,wheelSize,style)
  47. Sit.call(this,c,sitColor)
  48. Model.call(this,height,width)
  49. }
  50. var car = new Car(100,"big","like","red",200,700)
  51. console.log(car);

7.2.2 apply

apply与call基本相同,apply在传参数时传一个arguments(一个实参数组)
call在传参数时,实参按照形参个数一个一个去传
  1. function Wheel(wheelSize,style){
  2. this.wheelSize=wheelSize
  3. this.style=style
  4. }
  5. function Sit(c,sitColor){
  6. this.c=c
  7. this.sitColor=sitColor
  8. }
  9. function Model(height,width){
  10. this.width=width
  11. this.height=height
  12. }
  13. function Car(wheelSize,style,c,sitColor,height,width){
  14. Wheel.apply(this,[wheelSize,style])//前提是必须 new Car()这个对象,否则this为window无意义
  15. Sit.apply(this,[c,sitColor])
  16. Model.apply(this,[height,width])
  17. }
  18. var car = new Car(100,"big","like","red",200,700)
  19. console.log(car);

7.3 继承的演变

7.3.1 继承原型链

7.3.2 call/apply改变指向的继承

7.3.3 共享原型继承

  1. Person2.prototype.lastName = "桂"
  2. function Person2() {}
  3. function Son() {}
  4. // 封装函数实现继承(A,B)是A继承B
  5. function extend(Target, Origin) {
  6. Target.prototype = Origin.prototype
  7. }
  8. extend(Son, Person2);
  9. var son = new Son();
  10. console.log(son.lastName); //'桂'
  11. var person2 = new Person2();
  12. console.log(person2.lastName); //'桂'
  13. /**
  14. * 弊端:不能给Son的原型添加自己的方法,给Son添加Persona2也存在,他们共享原型,指向同一个空间
  15. * 解决:圣杯模式
  16. */

Snipaste_2021-01-26_23-20-07.png

7.3.4 圣杯模式继承

  1. function inherit(Target, Origin) {
  2. function F() {}
  3. F.prototype = Origin.prototype
  4. Target.prototype = new F()
  5. //当形成继承链c.__proto__---->new F().__proto__--->Father.prototype后,c.constructor变成f Father(){}
  6. //把c.constructor的构造函数原型改回来
  7. Target.prototype.constructor=Target
  8. //获取Target真正继承自谁的信息
  9. Target.prototype.uber=Origin.prototype
  10. }
  11. Father.prototype.name = "哈哈"
  12. function Father() {
  13. }
  14. function Child() {
  15. }
  16. inherit(Child, Father);
  17. var c = new Child();
  18. var f = new Father();
  19. console.log(c.name, f.name); //哈哈 哈哈
  20. Child.prototype.male = "女"
  21. console.log(c.male, f.male); //女 undefined

Snipaste_2021-01-26_23-58-32.png
Snipaste_2021-01-26_23-55-05.png
/
image.png

7.4 命名空间

闭包的第四点用途-—-命名空间:模块化开发,防止全局污染问题
两种方案:(1).对象里面放对象 (2).闭包
  1. var name="all"
  2. var myGxt=(function(){
  3. var name="gxt"
  4. function callName(){
  5. console.log(name);
  6. }
  7. //立即执行函数,时自己立即执行的,且里面的变量形成了私有空间,不会与外部的变量冲突,在立即执行函数完成立即销毁
  8. return function(){
  9. callName();
  10. }
  11. }())
  12. var myFxh=(function(){
  13. var name="fxh"
  14. function callName(){
  15. console.log(name);
  16. }
  17. //立即执行函数,时自己立即执行的,且里面的变量形成了私有空间,不会与外部的变量冲突,在立即执行函数完成立即销毁
  18. return function(){
  19. callName();
  20. }
  21. }())
  22. myGxt();//gxt
  23. myFxh();//fxh
  24. //当许多人一起开发时,可能出现变量的命名冲突,解决办法:命名空间(闭包)
  25. /* var obj={
  26. department1:{
  27. gxt:{
  28. name:"hhh",
  29. age:123
  30. }
  31. },
  32. department2:{
  33. fxh:{
  34. name:"xxx",
  35. age:30
  36. }
  37. }
  38. }
  39. var gxt=obj.department1.gxt;
  40. console.log(gxt.name)
  41. 这样使用,不会有全局污染,但是使用麻烦,可以用更简单的闭包
  42. */

7.4.1 实现函数的连续调用

  1. //实现方法的连续调用,return this;在对象中,this指当前对象deng
  2. var deng={
  3. smock:function (){
  4. console.log("吸烟");
  5. return this;
  6. },
  7. drink:function (){
  8. console.log("喝酒");
  9. return this;
  10. },
  11. perm:function (){
  12. console.log("烫头");
  13. return this;
  14. }
  15. }
  16. deng.smock().drink().perm();

7.4.2 属性调用两种方式

等同于 this.wife—->默认转为this[“wife”]

  1. // 属性的拼接问题
  2. var wife={
  3. wife1:{name:"a"},
  4. wife2:{name:"b"},
  5. wife3:{name:"c"},
  6. wife4:{name:"d"},
  7. // 传过来一个num,根据num来打印数据
  8. chooseWife:function(num){
  9. console.log(this['wife'+num]);//等同于 this.wife--->默认转为this["wife"]
  10. }
  11. }
  12. wife.chooseWife(1)

7.4.3 for —in—遍历对象的注意点


1. for key in obj 遍历的时候,必须使用obj[key],因为obj.key底层转为obj[‘key’],系统认为访问的时key这个属性,因此打印undefined
1. for—in—会遍历原型中的属性,但指会打印自己的原型,如:Object.property系统中的原型中属性不会打印

7.4.4 hasOwnProperty()和in对象都有


1. hasOwnProperty(),用来判断对象的属性是否属于自己,会过滤出原型链中的属性不打印
1. in可以判断原型中的属性返回true
1. hasOwnProperty可判断原型中属性返回false
  1. var testObj={
  2. name:"gxt",
  3. age:12,
  4. gender:"男",
  5. __proto__:{
  6. //一般原型中的属性也可用for..in..遍历,不想打印原型中属性,用hasOwnProperty过滤
  7. lastName:"fxh"
  8. //__proto__指向 Object.prototype
  9. }
  10. }
  11. Object.prototype.abc="123"
  12. for(var key in testObj){
  13. if(testObj.hasOwnProperty(key)){
  14. console.log(testObj[key]);//此时不打印lastName
  15. }
  16. }
  17. for(var key in testObj){
  18. if(!testObj.hasOwnProperty(key)){
  19. console.log(key+"---"+testObj[key]);//此时不打印lastName和abc
  20. }
  21. }

7.4.5 instanceOf


1. A instanceOf B:判断 A对象 是不是 B构造函数构造出来的
1. 看A原型链上 有没有 B原型
  1. function Perso() {
  2. }
  3. var pp = new Perso()
  4. console.log(pp instanceof Perso); //true
  5. console.log(pp instanceof Object); //true
  6. console.log([] instanceof Object); //true
  7. console.log([] instanceof Array); //true

7.4.6 识别{}或[]的三种方式

image.pngimage.pngimage.png

  1. Object.prototype.toString.call([])
  2. Object.prototype.toString=function(){
  3. //toString是一个函数,里面有this,谁调用这个函数,this就是谁
  4. //对象调用,this就是Object---->一定会使用this
  5. //1.识别this
  6. //2. 返回相应结果
  7. }
  8. Object.prototype.toString.call([])//这方法的执行,改变了toString里面的this指向,使其指向Array
  9. obj.toString();//这时toString里面的this时obj

八、this指向问题


1. 预编译过程中,this指向window
1. 全局作用域里this—->window
1. call/apply可以改变函数运行时this指向
1. obj.func(); func(); 里面的this指向obj,谁调用函数,函数里this指向谁

image.png
image.pngimage.png

九、arguments

9.1 arguments.callee

arguments.callee指向函数自身的引用,eg:立即执行函数是没有函数名的,但递归函数的使用必须要函数名,因此可以使用arguments.callee来解决

image.pngimage.png

  1. var num=(function(n){
  2. if(n==1){
  3. return 1;
  4. }
  5. return n*arguments.callee(n-1)
  6. }(20))
  7. console.log(num);//2432902008176640000

9.2 caller

caller不是arguments的属性,arguments只有callee和length属性;caller是函数自己的属性

  1. //在哪个环境调用demo函数,这个caller就是谁
  2. function test(){
  3. demo();
  4. }
  5. function demo(){
  6. console.log(demo.caller);
  7. }
  8. test();//f test(){ demo(); }

十、浅拷贝和深拷贝

10.1 浅拷贝

  1. //不管属性的类型是什么,直接通过key--value一次性拷贝过来
  2. var obj = {
  3. name: '罗迹',
  4. age: 20,
  5. like: '许沐',
  6. eat:['苹果','葡萄','香蕉']
  7. }
  8. var objCopy = {}
  9. // 实现浅克隆
  10. function copy(origin, target) {
  11. //如果没有传第二个参数时
  12. var target = target || {};
  13. for (var key in origin) {
  14. target[key] = origin[key]
  15. }
  16. return target;
  17. }
  18. console.log(copy(obj, objCopy));

image.png

10.2 深拷贝

  1. var obj = {
  2. name: '罗迹',
  3. age: 20,
  4. like: '许沐',
  5. eat: ['苹果', '葡萄', '香蕉'],
  6. hobbit: {
  7. name: "哈哈",
  8. gender: '男',
  9. xxx: ["a", "b", "c"]
  10. }
  11. }
  12. var objCopy = {}
  13. // 深克隆
  14. /**
  15. * 1.先判断是不是原始值,还是引用值,{}和[]tyoeof都为object
  16. * 2.hasOwnProperty判断是不是原型链上的属性4
  17. * 3.判断每一个object类型的是{}还是[],利用Object.prototype.toString.call([])==[onject Array]
  18. * 4.对于{}和[]递归调用
  19. */
  20. function deepCopy(origin, target) {
  21. var target = target || {};
  22. var toStr = Object.prototype.toString;
  23. for (var key in origin) {
  24. // 属于该对象自身的属性才继续下一步判断
  25. if (origin.hasOwnProperty(key)) {
  26. // 如果为引用值,继续判断
  27. if (origin[key] !== null && typeof (origin[key]) == "object") {
  28. if (toStr.call(origin[key] == "[object Array]")) {
  29. target[key] = []
  30. } else {
  31. target[key] = {}
  32. }
  33. // 递归调用
  34. deepCopy(origin[key], target[key])
  35. } else {
  36. // 原始值,直接赋值
  37. target[key] = origin[key]
  38. }
  39. }
  40. }
  41. return target;
  42. }
  43. console.log('深克隆', deepCopy(obj, objCopy));

十二、三目运算符

image.png