————————-基础总结深入

01.数据类型

01.数据类型的分类和判断

  • 基本(值)类型

    • Number ——- 任意数值 ———— typeof
    • String ——- 任意字符串 ——— typeof
    • Boolean —— true/false ——- typeof
    • undefined —- undefined ——- typeof/===
    • null ———— null ————— ===
  • 对象(引用)类型

    • Object ——-任意对象 typeof/instanceof
    • Array ——— 一种特别的对象(数值下标操作,内部数据是有序的)instanceof
    • Function —— 一种特别的对象(可以执行) typeof
  • 判断类型是否为undefine

      1. // 1.基本
      2. l l typeof返回数据类型的字符串表达var a
      3. console.log(a, typeof a, typeof a==='undefined'T // undefined 'undefined' t
      4. console.log(undefined==='undefined')//false
  • 详细讲解过程

    • ```html <!DOCTYPE html> <!—
  1. 分类
    • 基本(值)类型
      • String: 任意字符串
      • Number: 任意的数字
      • boolean: true/false
      • undefined: undefined
      • null: null
    • 对象(引用)类型
      • Object: 任意对象
      • Function: 一种特别的对象(可以执行)
      • Array: 一种特别的对象(数值下标, 内部数据是有序的)
  2. 判断
    • typeof:
      • 可以判断: undefined/ 数值 / 字符串 / 布尔值 / function
      • 不能判断: null与object object与array
    • instanceof:
      • 判断对象的具体类型
    • ===
      • 可以判断: undefined, null —>
``` ## 02.数据类型的常见问题 ### 01.undefined与null的区别? - undefined代表定义未赋值 - nulll定义并赋值了, 只是值为null ```javascript // 1. undefined与null的区别? var a console.log(a) // undefined a = null console.log(a) // null ``` ### 02.什么时候给变量赋值为null呢? - 初始赋值, 表明将要赋值为对象 - 结束前, 让对象成为垃圾对象(被垃圾回收器回收) ```javascript //起始 var b = null // 初始赋值为null, 表明将要赋值为对象 //确定对象就赋值 b = ['atguigu', 12] //最后 b = null // 让b指向的对象成为垃圾对象(被垃圾回收器回收) // b = 2 ``` ### 03.如何严格区别变量类型与数据类型? - 数据的类型 - 基本类型 - 对象类型 - 变量的类型(变量内存值的类型) - 基本类型: 保存就是基本类型的数据 - 引用类型: 保存的是地址值 ```javascript var c = function () { } console.log(typeof c) // 'function' typeof通过c的地址查询到栈空间的内存 从而判断是否是函数 ``` ### 04.汇总 ```html ``` # 02.数据,变量, 内存 ## 03.数据,变量, 内存的理解 - 什么是数据? - 存储在内存中代表特定信息的'东东', 本质上是0101... - 数据的特点: 可传递, 可运算 - 一切皆数据 - 内存中所有操作的目标: 数据 - 算术运算 - 逻辑运算 - 赋值 - 运行函数 2. 什么是内存? - 内存条通电后产生的可储存数据的空间(临时的) - 内存产生和死亡: 内存条(电路版)>通电>产生内存空间==>存储数据==>处理数据==>断电==>内存空间和数据都消失 - 一块小内存的2个数据 - 内部存储的数据 - 地址值 - 内存分类 - 栈: 全局变量/局部变量 - 堆: 对象 3. 什么是变量? - 可变化的量, 由变量名和变量值组成 - 每个变量都对应的一块小内存, 变量名用来查找对应的内存, 变量值就是内存中保存的数据 4. 内存,数据, 变量三者之间的关系 - 内存用来存储数据的空间 - 变量是内存的标识 ```html ``` ## 04.数据,变量, 内存的常见问题 ### 01.var a = xxx, a内存中到底保存的是什么? - xxx是基本数据, 保存的就是这个数据 - xxx是对象, 保存的是对象的地址值 - xxx是一个变量, 保存的xxx的内存内容(可能是基本数据, 也可能是地址值) ```html ``` ### 02.关于引用变量赋值问题? - 2个引用变量指向同一个对象, 通过一个变量修改对象内部数据, 另一个变量看到的是修改之后的数据 - 2个引用变量指向同一个对象, 让其中一个引用变量指向另一个对象, 另一引用变量依然指向前一个对象 - ```html ``` ### 03.在js调用函数时传递变量参数时, 是值传递还是引用传递? **传递的都是值(基本/地址值) 传递的是变量的内容** - 变量是基本数据类型 则传递数值 - 变量是引用数据类型 则传递的是地址 ```html ``` ### 04.JS引擎如何管理内存? ```html ``` # 03.对象 ## 01.对象的理解和使用 - **什么是对象?** - 多个数据的封装体 - 用来保存多个数据的容器 - 一个对象代表现实中的一个事物 2. **为什么要用对象?** - 统一管理多个数据 3. **对象的组成** - 属性: 属性名(字符串)和属性值(任意)组成 - 方法: 一种特别的属性(属性值是函数) 4. **如何访问对象内部数据?** - .属性名: 编码简单, 有时不能用 - ['属性名']: 编码麻烦, 能通用 ```html ``` ## 02.常见问题汇总 ### 01.访问对象内部数据什么时候必须使用['属性名']的方式? 1. 属性名包含特殊字符: - 空格 2. 属性名不确定 ```html ``` # 04.函数 ## 01.函数的理解和使用 - **什么是函数?** - 实现特定功能的n条语句的封装体 - 只有函数是可以执行的, 其它类型的数据不能执行 2. **为什么要用函数?** - 提高代码复用 - 便于阅读交流 3. **如何定义函数?** - 函数声明 - 表达式 4. **如何调用(执行)函数?** - test(): 直接调用 - obj.test(): 通过对象调用 - new test(): new调用 - test.call/apply(obj): 临时让test成为obj的方法进行调用 ```html ``` ## 02.回调函数 1. 什么函数才是回调函数?
1). 你定义的
2). 你没有调
3). 但最终它执行了(在某个时刻或某个条件下) 2. 常见的回调函数? - dom事件回调函数 ==>发生事件的dom元素 - 定时器回调函数 ===>window - ajax请求回调函数(后面讲) - 生命周期回调函数(后面讲) ```html

  1. <a name="01417456"></a>
  2. ## 03.IIFE(立即执行函数表达式)
  3. 1. 理解
  4. - 全称: Immediately-Invoked Function Expression
  5. 2. 作用
  6. - 隐藏实现
  7. - 不会污染外部(全局)命名空间
  8. - 用它来编码js模块
  9. ```html
  10. <!DOCTYPE html>
  11. <html lang="en">
  12. <head>
  13. <meta charset="UTF-8">
  14. <title>06_IIFE</title>
  15. </head>
  16. <body>
  17. <!--
  18. 1. 理解
  19. * 全称: Immediately-Invoked Function Expression
  20. 2. 作用
  21. * 隐藏实现
  22. * 不会污染外部(全局)命名空间
  23. * 用它来编码js模块
  24. -->
  25. <script type="text/javascript">
  26. (function () { //匿名函数自调用
  27. var a = 3
  28. console.log(a + 3)
  29. })()
  30. var a = 4
  31. console.log(a)
  32. ;(function () {
  33. var a = 1
  34. function test () {
  35. console.log(++a)
  36. }
  37. window.$ = function () { // 向外暴露一个全局函数
  38. return {
  39. test: test
  40. }
  41. }
  42. })()
  43. $().test() // 1. $是一个函数 2. $执行后返回的是一个对象 很关键
  44. </script>
  45. </body>
  46. </html>

05.this上下文

  1. this是什么?
  • 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
  • 所有函数内部都有一个变量this
  • 它的值是调用函数的当前对象
  1. 如何确定this的值?
  • test(): window
  • p.test(): p
  • new test(): 新创建的对象
  • p.call(obj): obj
  • 1.以函数的形式调用时,this是windows
  • 2.以方法的形式调用时,this就是调用方法的对象
  • 3.以构造函数的形式调用时,this就是新创建的对象
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>07_函数中的this</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. this是什么?
  10. * 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
  11. * 所有函数内部都有一个变量this
  12. * 它的值是调用函数的当前对象
  13. 2. 如何确定this的值?
  14. * test(): window
  15. * p.test(): p
  16. * new test(): 新创建的对象
  17. * p.call(obj): obj
  18. -->
  19. <script type="text/javascript">
  20. function Person(color) {
  21. console.log(this)
  22. this.color = color;
  23. this.getColor = function () {
  24. console.log(this)
  25. return this.color;
  26. };
  27. this.setColor = function (color) {
  28. console.log(this)
  29. this.color = color;
  30. };
  31. }
  32. Person("red"); //this是谁?
  33. //此时是作为函数使用 调用者没有明确指定
  34. //window
  35. var p = new Person("yello"); //this是谁?
  36. //p指向后面生成的对象
  37. //p
  38. p.getColor(); //this是谁?
  39. //p调用的函数
  40. //p
  41. var obj = {};
  42. p.setColor.call(obj, "black"); //this是谁? obj
  43. var test = p.setColor;
  44. test(); //this是谁?
  45. //没有指定
  46. //window
  47. function fun1() {
  48. function fun2() {
  49. console.log(this);
  50. }
  51. fun2(); //this是谁? window
  52. }
  53. fun1();
  54. </script>
  55. </body>
  56. </html>

———————-补充

01.分号问题

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>01_分号问题</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. js一条语句的后面可以不加分号
  10. 2. 是否加分号是编码风格问题, 没有应该不应该,只有你自己喜欢不喜欢
  11. 3. 在下面2种情况下不加分号会有问题
  12. * 小括号开头的前一条语句
  13. * 中方括号开头的前一条语句
  14. 4. 解决办法: 在行首加分号
  15. 5. 强有力的例子: vue.js库
  16. 6. 知乎热议: https://www.zhihu.com/question/20298345
  17. -->
  18. <script type="text/javascript">
  19. var a = 3
  20. ;(function () {
  21. })()
  22. /*
  23. 错误理解
  24. var a = 3(function () {
  25. })();
  26. */
  27. var b = 4
  28. ;[1, 3].forEach(function () {
  29. })
  30. /*
  31. 错误理解
  32. var b = 4[3].forEach(function () {
  33. })
  34. */
  35. </script>
  36. </body>
  37. </html>

02.内存溢出与内存泄漏

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>02_内存溢出与内存泄露</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 内存溢出
  10. * 一种程序运行出现的错误
  11. * 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
  12. 2. 内存泄露
  13. * 占用的内存没有及时释放
  14. * 内存泄露积累多了就容易导致内存溢出
  15. * 常见的内存泄露:
  16. * 意外的全局变量
  17. * 没有及时清理的计时器或回调函数
  18. * 闭包
  19. -->
  20. <script type="text/javascript">
  21. // 1. 内存溢出
  22. var obj = {}
  23. for (var i = 0; i < 10000; i++) {
  24. obj[i] = new Array(10000000)
  25. console.log('-----')
  26. }
  27. // 2. 内存泄露
  28. // 意外的全局变量
  29. function fn() {
  30. a = new Array(10000000)
  31. console.log(a)
  32. }
  33. fn()
  34. // 没有及时清理的计时器或回调函数
  35. var intervalId = setInterval(function () { //启动循环定时器后不清理
  36. console.log('----')
  37. }, 1000)
  38. // clearInterval(intervalId)
  39. // 闭包
  40. function fn1() {
  41. var a = 4
  42. function fn2() {
  43. console.log(++a)
  44. }
  45. return fn2
  46. }
  47. var f = fn1()
  48. f()
  49. // f = null
  50. </script>
  51. </body>
  52. </html>

———————-函数高级

01原型与原型链

待看的参考文章:https://www.cnblogs.com/wangfupeng1988/p/3977924.html 王福朋

01.函数的原型

  1. 函数的prototype属性(图)
  • 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
  • 原型对象中有一个属性constructor, 它指向函数对象(构造函数与原型对象相互引用)
  • 创建函数定义的同时 函数内部会默认执行一条语句

    • this.prototype = {} 此处的this指向的是函数对象
    • 此条语句添加了一条属性 prototype
  1. 给原型对象添加属性(一般都是方法)
  • 默认的方法都为空值(数据) 只包含一个prototype和一个construct属性

  • 作用: 函数的所有实例对象自动拥有原型中的属性(方法)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>01_原型(prototype)</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 函数的prototype属性(图)
  10. * 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
  11. * 原型对象中有一个属性constructor, 它指向函数对象
  12. 2. 给原型对象添加属性(一般都是方法)
  13. * 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
  14. -->
  15. <script type="text/javascript">
  16. // 1.每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
  17. console.log(Date.prototype, typeof Date.prototype)//打印 object+许多方法 "obejct"
  18. function Fun () {//alt + shift +r(重命名rename)
  19. }
  20. console.log(Fun.prototype) // 1.1 默认指向一个Object空对象(没有我们的属性)
  21. // 原型对象中有一个属性constructor, 它指向函数对象
  22. console.log(Date.prototype.constructor===Date)//true
  23. console.log(Fun.prototype.constructor===Fun)//true
  24. //给原型对象添加属性(一般是方法) ===>实例对象可以访问
  25. Fun.prototype.test = function () {
  26. console.log('test()')
  27. }
  28. var fun = new Fun()
  29. fun.test()
  30. </script>
  31. </body>
  32. </html>

02.显式原型(类似类)与隐式原型(实例对象)

  1. 每个函数function都有一个prototype,即显式原型(属性)
  2. 每个实例对象都有一个proto,可称为隐式原型(属性)
  3. 对象的隐式原型的值为其对应构造函数的显式原型的值 存储的是同一个对象地址

    • 创建实例对象时默认执行这一条函数 this.protope=Fn.prototype
    • 构造函数的显式原型对象先产生 实例的隐式原型对象后产生
  4. 内存结构(图)

    • 01.JavaScript高级 - 图1
  5. 总结:
  • 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
  • 对象的proto属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
  • 程序员能直接操作显式原型, 但不能直接操作隐式原型 (ES6之前)
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>02_显式原型与隐式原型</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 每个函数function都有一个prototype,即显式原型(属性)
  10. 2. 每个实例对象都有一个__proto__,可称为隐式原型(属性)
  11. 3. 对象的隐式原型的值为其对应构造函数的显式原型的值
  12. 4. 内存结构(图)
  13. 5. 总结:
  14. * 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
  15. * 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
  16. * 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
  17. -->
  18. <script type="text/javascript">
  19. //定义构造函数
  20. function Fn() { // 内部语句: this.prototype = {}
  21. }
  22. // 1. 每个函数function都有一个prototype,即显式原型属性, 默认指向一个空的Object对象
  23. console.log(Fn.prototype)
  24. // 2. 每个实例对象都有一个__proto__,可称为隐式原型
  25. //创建实例对象
  26. var fn = new Fn() // 内部语句: this.__proto__ = Fn.prototype
  27. console.log(fn.__proto__)
  28. // 3. 对象的隐式原型的值为其对应构造函数的显式原型的值
  29. console.log(Fn.prototype===fn.__proto__) // true
  30. //给显式原型添加方法 不能直接操作隐式原型(ES6之前)
  31. Fn.prototype.test = function () {
  32. console.log('test()')
  33. }
  34. //通过实例调用原型的方法
  35. fn.test()//对象先找内部方法 没有再从隐式原型中寻找方法
  36. </script>
  37. </body>
  38. </html>

03.原型链

  1. 原型链(图解) 本质上是用于查找实例对象的属性 实际上是由隐形原型组成的链
  • 访问一个对象的属性时,

    • 先在自身属性中查找,找到返回
    • 如果没有, 再沿着proto这条链向上查找, 找到返回
    • 如果最终没找到, 返回undefined
  • 别名: 隐式原型链
  • 作用: 查找对象的属性(方法)
  • 注意 对实例对象的属性赋值不会调用原型链 只有查找属性时会调用原型链
  1. 构造函数/原型/实体对象的关系(图解)
    01.JavaScript高级 - 图2

  2. 构造函数/原型/实体对象的关系2(图解)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>03_原型链</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 原型链(图解)
  10. * 访问一个对象的属性时,
  11. * 先在自身属性中查找,找到返回
  12. * 如果没有, 再沿着__proto__这条链向上查找, 找到返回
  13. * 如果最终没找到, 返回undefined
  14. * 别名: 隐式原型链
  15. * 作用: 查找对象的属性(方法)
  16. 2. 构造函数/原型/实体对象的关系(图解)
  17. 3. 构造函数/原型/实体对象的关系2(图解)
  18. -->
  19. <script type="text/javascript">
  20. // console.log(Object)
  21. //console.log(Object.prototype)
  22. console.log(Object.prototype.__proto__)
  23. function Fn() {
  24. this.test1 = function () {
  25. console.log('test1()')
  26. }
  27. }
  28. console.log(Fn.prototype)
  29. Fn.prototype.test2 = function () {
  30. console.log('test2()')
  31. }
  32. var fn = new Fn()
  33. fn.test1()
  34. fn.test2()
  35. console.log(fn.toString())
  36. console.log(fn.test3)
  37. // fn.test3() //test3() is not a function
  38. /*
  39. 1. 函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
  40. */
  41. console.log(Fn.prototype instanceof Object) // true
  42. console.log(Object.prototype instanceof Object) // false
  43. console.log(Function.prototype instanceof Object) // true
  44. /*
  45. 2. 所有函数都是Function的实例(包含Function)
  46. */
  47. console.log(Function.__proto__===Function.prototype)
  48. /*
  49. 3. Object的原型对象是原型链尽头
  50. */
  51. console.log(Object.prototype.__proto__) // null
  52. </script>
  53. </body>
  54. </html>

04.原型链的属性问题

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>04_原型链_属性问题</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 读取对象的属性值时: 会自动到原型链中查找
  10. 2. 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
  11. 3. 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
  12. -->
  13. <script type="text/javascript">
  14. function Fn() {
  15. }
  16. Fn.prototype.a = 'xxx'
  17. var fn1 = new Fn()
  18. console.log(fn1.a, fn1)
  19. var fn2 = new Fn()
  20. fn2.a = 'yyy'
  21. console.log(fn1.a, fn2.a, fn2)
  22. function Person(name, age) {
  23. this.name = name
  24. this.age = age
  25. }
  26. Person.prototype.setName = function (name) {
  27. this.name = name
  28. }
  29. var p1 = new Person('Tom', 12)
  30. p1.setName('Bob')
  31. console.log(p1)
  32. var p2 = new Person('Jack', 12)
  33. p2.setName('Cat')
  34. console.log(p2)
  35. console.log(p1.__proto__===p2.__proto__) // true 都指向构造函数的宣誓原型
  36. </script>
  37. </body>
  38. </html>

05.探索instanceof

  1. instanceof是如何判断的?
  • 表达式: A instanceof B
  • 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false
  1. Function是通过new自己产生的实例
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>05_探索instanceof</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. instanceof是如何判断的?
  10. * 表达式: A instanceof B
  11. * 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false
  12. 2. Function是通过new自己产生的实例
  13. -->
  14. <script type="text/javascript">
  15. /*
  16. 案例1
  17. */
  18. function Foo() { }
  19. var f1 = new Foo()
  20. console.log(f1 instanceof Foo) // true
  21. console.log(f1 instanceof Object) // true
  22. /*
  23. 案例2
  24. */
  25. console.log(Object instanceof Function) // true
  26. console.log(Object instanceof Object) // true
  27. console.log(Function instanceof Function) // true
  28. console.log(Function instanceof Object) // true
  29. function Foo() {}
  30. console.log(Object instanceof Foo) // false
  31. </script>
  32. </body>
  33. </html>

06.面试题

  • 测试题1

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>06_面试题</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9. /*
  10. 测试题1
  11. */
  12. function A () {
  13. }
  14. A.prototype.n = 1
  15. var b = new A()
  16. A.prototype = { //此刻修改的是函数的显示原型对象 原来的实例依旧引用的之前创建的空对象 没有被销毁 只是后续定义的实例链接的对象不再一致
  17. n: 2,
  18. m: 3
  19. }
  20. var c = new A()
  21. console.log(b.n, b.m, c.n, c.m) //1 undefine 2 3
  22. /*
  23. 测试题2
  24. */
  25. function F (){}
  26. Object.prototype.a = function(){
  27. console.log('a()')
  28. }
  29. Function.prototype.b = function(){
  30. console.log('b()')
  31. }
  32. var f = new F()
  33. f.a()
  34. // f.b()
  35. F.a()
  36. F.b()
  37. console.log(f)
  38. console.log(Object.prototype)
  39. console.log(Function.prototype)
  40. </script>
  41. </body>
  42. </html>

02.执行上下文与执行上下文栈

01.变量提升与函数提升

  1. 变量声明提升
  • 通过var定义(声明)的变量, 在定义语句之前就可以访问到
  • 值: undefined
  1. 函数声明提升
  • 通过function声明的函数, 在之前就可以直接调用
  • 值: 函数定义(对象)
  1. 问题: 变量提升和函数提升是如何产生的?
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>01_变量提升与函数提升</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 变量声明提升
  10. * 通过var定义(声明)的变量, 在定义语句之前就可以访问到
  11. * 值: undefined
  12. 2. 函数声明提升
  13. * 通过function声明的函数, 在之前就可以直接调用
  14. * 值: 函数定义(对象)
  15. 3. 问题: 变量提升和函数提升是如何产生的?
  16. -->
  17. <script type="text/javascript">
  18. console.log('-----')
  19. /*
  20. 面试题 : 输出 undefined
  21. */
  22. var a = 3
  23. function fn () {
  24. console.log(a)//优先寻找函数内部作用域
  25. var a = 4//变量提升 但是赋值操作还未进行
  26. }
  27. fn()
  28. console.log(b) //undefined 变量提升
  29. fn2() //可调用 函数提升(必须使用函数申明的方式)
  30. // fn3() //不能 变量提升
  31. var b = 3
  32. function fn2() {
  33. console.log('fn2()')
  34. }
  35. var fn3 = function () {
  36. console.log('fn3()')
  37. }
  38. </script>
  39. </body>
  40. </html>

02.执行上下文

  1. 代码分类(位置)
  • 全局代码
  • 函数(局部)代码
  1. 全局执行上下文
  • 在执行全局代码前将window确定为全局执行上下文
  • 对全局数据进行预处理

    • var定义的全局变量==>undefined, 添加为window的属性
    • function声明的全局函数==>赋值(fun), 添加为window的方法
    • this==>赋值(window)
  • 开始执行全局代码
  1. 函数执行上下文
  • 创建的时机: 在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的, 存在于栈中)
  • 对局部数据进行预处理

    • 形参变量==>赋值(实参)==>添加为执行上下文的属性
    • arguments==>赋值(实参列表), 添加为执行上下文的属性
    • var定义的局部变量==>undefined, 添加为执行上下文的属性
    • function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
    • this==>赋值(调用函数的对象)
  • 开始执行函数体代码
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>02_执行上下文</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 代码分类(位置)
  10. * 全局代码
  11. * 函数(局部)代码
  12. 2. 全局执行上下文
  13. * 在执行全局代码前将window确定为全局执行上下文
  14. * 对全局数据进行预处理
  15. * var定义的全局变量==>undefined, 添加为window的属性
  16. * function声明的全局函数==>赋值(fun), 添加为window的方法
  17. * this==>赋值(window)
  18. * 开始执行全局代码
  19. 3. 函数执行上下文
  20. * 在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的, 存在于栈中)
  21. * 对局部数据进行预处理
  22. * 形参变量==>赋值(实参)==>添加为执行上下文的属性
  23. * arguments==>赋值(实参列表), 添加为执行上下文的属性
  24. * var定义的局部变量==>undefined, 添加为执行上下文的属性
  25. * function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
  26. * this==>赋值(调用函数的对象)
  27. * 开始执行函数体代码
  28. -->
  29. <script type="text/javascript">
  30. console.log(a1, window.a1)
  31. window.a2()
  32. console.log(this)
  33. var a1 = 3
  34. function a2() {
  35. console.log('a2()')
  36. }
  37. console.log(a1)
  38. </script>
  39. </body>
  40. </html>

03.执行上下文栈

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>03_执行上下文栈</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象
  10. 2. 在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
  11. 3. 在函数执行上下文创建后, 将其添加到栈中(压栈)
  12. 4. 在当前函数执行完后,将栈顶的对象移除(出栈)
  13. 5. 当所有的代码执行完后, 栈中只剩下window
  14. -->
  15. <script type="text/javascript">
  16. var a = 10
  17. var bar = function (x) {
  18. var b = 5
  19. foo(x + b)
  20. }
  21. var foo = function (y) {
  22. var c = 5
  23. console.log(a + c + y)
  24. }
  25. bar(10)
  26. // bar(10)
  27. </script>
  28. </body>
  29. </html>

04.执行上下文栈面试题

面试题1

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>04_执行上下文栈2</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 依次输出什么? 注意这里是函数的嵌套 内部函数的作用域和外部的不同 传入的参数和全局变量一致,传入的参数作为中间变量
  10. gb: undefined
  11. fb: 1
  12. fb: 2
  13. fb: 3
  14. fe: 3
  15. fe: 2
  16. fe: 1
  17. ge: 1
  18. 2. 整个过程中产生了几个执行上下文? 5 1个windows 4个函数
  19. -->
  20. <script type="text/javascript">
  21. console.log('gb: '+ i)
  22. var i = 1
  23. foo(1)
  24. function foo(i) {
  25. if (i == 4) {
  26. return
  27. }
  28. console.log('fb:' + i)
  29. foo(i + 1) //递归调用: 在函数内部调用自己
  30. console.log('fe:' + i)
  31. }
  32. console.log('ge: ' + i)
  33. </script>
  34. </body>
  35. </html>

面试题2

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>05_面试题</title>
  6. <link rel="stylesheet" href="xxx.css">
  7. <style>
  8. </style>
  9. </head>
  10. <body>
  11. <div style=""></div>
  12. <script type="text/javascript">
  13. /*
  14. 测试题1: 先执行变量提升, 再执行函数提升 另一种说法 函数申明会覆盖变量申明
  15. */
  16. function a() {}
  17. var a
  18. console.log(typeof a) // 'function'
  19. /*
  20. 测试题2: 即使在if语句中的变量申明 也会进行变量提升 所以这里的 b in window为true if语句进不去
  21. */
  22. if (!(b in window)) {
  23. var b = 1
  24. }
  25. console.log(b) // undefined
  26. /*
  27. 测试题3:
  28. */
  29. var c = 1
  30. function c(c) {
  31. console.log(c)
  32. var c = 3
  33. }
  34. c(2) // 报错
  35. </script>
  36. </body>
  37. </html>

03.作用域与作用域链

01.作用域

  1. 理解
  • 就是一块”地盘”, 一个代码段所在的区域
  • 它是静态的(相对于上下文对象), 在编写代码时就确定了
  1. 分类
  • 全局作用域
  • 函数作用域
  • 没有块作用域(ES6有了) 一个大括号代表一个块作用域
  1. 作用
  • 隔离变量,不同作用域下同名变量不会有冲突
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>01_作用域</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 理解
  10. * 就是一块"地盘", 一个代码段所在的区域
  11. * 它是静态的(相对于上下文对象), 在编写代码时就确定了
  12. 2. 分类
  13. * 全局作用域
  14. * 函数作用域
  15. * 没有块作用域(ES6有了)
  16. 3. 作用
  17. * 隔离变量,不同作用域下同名变量不会有冲突
  18. -->
  19. <script type="text/javascript">
  20. /* //没块作用域
  21. if(true) {
  22. var c = 3
  23. }
  24. console.log(c)*/
  25. var a = 10,
  26. b = 20
  27. function fn(x) {
  28. var a = 100,
  29. c = 300;
  30. console.log('fn()', a, b, c, x)//fn() 100 20 300 10
  31. function bar(x) {
  32. var a = 1000,
  33. d = 400
  34. console.log('bar()', a, b, c, d, x)//'bar()'1000 20,300,400,100
  35. }
  36. bar(100)
  37. bar(200)
  38. }
  39. fn(10)
  40. </script>
  41. </body>
  42. </html>

02.作用域与全局上下文的区别与联系

区别1

  • 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
  • 全局执行上下文环境是在全局作用域确定之后, js代码马上执行之前创建
  • 函数执行上下文是在调用函数时, 函数体代码执行之前创建

区别2

  • 作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化
  • 执行上下文是动态的, 调用函数时创建, 函数调用结束时就会自动释放

联系

  • 执行上下文(对象)是从属于所在的作用域
  • 全局上下文环境==>全局作用域
  • 函数上下文环境==>对应的函数使用域

01.JavaScript高级 - 图3

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>02_作用域与执行上下文</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 区别1
  10. * 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
  11. * 全局执行上下文环境是在全局作用域确定之后, js代码马上执行之前创建
  12. * 函数执行上下文是在调用函数时, 函数体代码执行之前创建
  13. 2. 区别2
  14. * 作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化
  15. * 执行上下文是动态的, 调用函数时创建, 函数调用结束时就会自动释放
  16. 3. 联系
  17. * 执行上下文(对象)是从属于所在的作用域
  18. * 全局上下文环境==>全局作用域
  19. * 函数上下文环境==>对应的函数使用域
  20. -->
  21. <script type="text/javascript">
  22. var a = 10,
  23. b = 20
  24. function fn(x) {
  25. var a = 100,
  26. c = 300;
  27. console.log('fn()', a, b, c, x)
  28. function bar(x) {
  29. var a = 1000,
  30. d = 400
  31. console.log('bar()', a, b, c, d, x)
  32. }
  33. bar(100)
  34. bar(200)
  35. }
  36. fn(10)
  37. </script>
  38. </body>
  39. </html>

03.作用域链

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>03_作用域链</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 理解
  10. * 多个上下级关系的作用域形成的链, 它的方向是从下向上的(从内到外)
  11. * 查找变量时就是沿着作用域链来查找的
  12. 2. 查找一个变量的查找规则
  13. * 在当前作用域下的执行上下文中查找对应的属性, 如果有直接返回, 否则进入2
  14. * 在上一级作用域的执行上下文中查找对应的属性, 如果有直接返回, 否则进入3
  15. * 再次执行2的相同操作, 直到全局作用域, 如果还找不到就抛出找不到的异常
  16. -->
  17. <script type="text/javascript">
  18. var a = 1
  19. function fn1() {
  20. var b = 2
  21. function fn2() {
  22. var c = 3
  23. console.log(c)
  24. console.log(b)
  25. console.log(a)
  26. console.log(d)
  27. }
  28. fn2()
  29. }
  30. fn1()
  31. </script>
  32. </body>
  33. </html>

04.面试题

面试题1

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>04_作用域_面试题</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9. var x = 10;
  10. function fn() {
  11. console.log(x);
  12. }
  13. function show(f) {
  14. var x = 20;
  15. f();
  16. }
  17. show(fn);//作用域产生与代码的编写方式 而不是函数的调用方式 在fn()中找变量x时其 其会直接访问它上层的全局作用域 所以输出为10
  18. </script>
  19. </body>
  20. </html>

面试题2

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>04_作用域_面试题2</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9. var fn = function () {
  10. console.log(fn)
  11. }
  12. fn()
  13. var obj = {
  14. fn2: function () {
  15. console.log(fn2)
  16. //console.log(this.fn2)
  17. }
  18. }
  19. obj.fn2()
  20. </script>
  21. </body>
  22. </html>

04.闭包

01.引入

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>00_引入</title>
  6. </head>
  7. <body>
  8. <button>测试1</button>
  9. <button>测试2</button>
  10. <button>测试3</button>
  11. <!--
  12. 需求: 点击某个按钮, 提示"点击的是第n个按钮"
  13. -->
  14. <script type="text/javascript">
  15. var btns = document.getElementsByTagName('button')
  16. //遍历加监听
  17. /*
  18. for (var i = 0,length=btns.length; i < length; i++) {
  19. var btn = btns[i]
  20. btn.onclick = function () {
  21. alert('第'+(i+1)+'个')
  22. }
  23. }*/
  24. /*
  25. for (var i = 0,length=btns.length; i < length; i++) {
  26. var btn = btns[i]
  27. //将btn所对应的下标保存在btn上
  28. btn.index = i
  29. btn.onclick = function () {
  30. alert('第'+(this.index+1)+'个')
  31. }
  32. }*/
  33. //利用闭包
  34. for (var i = 0,length=btns.length; i < length; i++) {
  35. (function (j) {
  36. var btn = btns[j]
  37. btn.onclick = function () {
  38. alert('第'+(j+1)+'个')
  39. }
  40. })(i)
  41. }
  42. </script>
  43. </body>
  44. </html>

02.理解闭包

  1. 如何产生闭包?
  • 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包
  1. 闭包到底是什么?
  • 使用chrome调试查看
  • 理解一: 闭包是嵌套的内部函数(绝大部分人)
  • 理解二: 包含被引用变量(函数)的对象(极少数人)
  • 注意: 闭包存在于嵌套的内部函数中
  1. 产生闭包的条件?
  • 函数嵌套
  • 内部函数引用了外部函数的数据(变量/函数)
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>01_理解闭包</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 如何产生闭包?
  10. * 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包
  11. 2. 闭包到底是什么?
  12. * 使用chrome调试查看
  13. * 理解一: 闭包是嵌套的内部函数(绝大部分人)
  14. * 理解二: 包含被引用变量(函数)的对象(极少数人)
  15. * 注意: 闭包存在于嵌套的内部函数中
  16. 3. 产生闭包的条件?
  17. * 函数嵌套
  18. * 内部函数引用了外部函数的数据(变量/函数)
  19. -->
  20. <script type="text/javascript">
  21. function fn1 () {
  22. var a = 2
  23. var b = 'abc'
  24. function fn2 () { //执行函数定义就会产生闭包(不用调用内部函数)
  25. console.log(a)
  26. }
  27. // fn2()
  28. }
  29. fn1()
  30. function fun1() {
  31. var a = 3
  32. var fun2 = function () {
  33. console.log(a)
  34. }
  35. }
  36. fun1()
  37. </script>
  38. </body>
  39. </html>

03.常见的闭包

  1. 将函数作为另一个函数的返回值
  2. 将函数作为实参传递给另一个函数调用
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>02_常见的闭包</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 将函数作为另一个函数的返回值
  10. 2. 将函数作为实参传递给另一个函数调用
  11. -->
  12. <script type="text/javascript">
  13. // 1. 将函数作为另一个函数的返回值
  14. function fn1() {
  15. var a = 2
  16. function fn2() {
  17. a++
  18. console.log(a)
  19. }
  20. return fn2
  21. }
  22. var f = fn1()
  23. f() // 3
  24. f() // 4
  25. // 2. 将函数作为实参传递给另一个函数调用
  26. function showDelay(msg, time) {
  27. setTimeout(function () {
  28. alert(msg)
  29. }, time)
  30. }
  31. showDelay('atguigu', 2000)
  32. </script>
  33. </body>
  34. </html>

再接上一条3*.执行第二个fn,也就是再执行一次fn2函数,此时a在自己中找不到,就去外部函数中找,外部栈中由于第2步变为3存在里面,这时fn2中a就为3,这也解释了此时闭包中a=3,然后a自增变4

这里有人会说fn1不是第一次执行完之后里面的变量全部死亡了吗,怎么执行fn2的时候还能在fn1中找到a,这里是由于fn1执行的时候也函数提升了,此时a相当于在全局作用域栈中f

01.JavaScript高级 - 图4

04.闭包的作用

  1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
  2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

问题:

  1. 函数执行完后, 函数内部声明的局部变量是否还存在? 一般是不存在, 存在于闭中的变量才可能存在
  2. 在函数外部能直接访问函数内部的局部变量吗? 不能, 但我们可以通过闭包让外部操作它

fn1()执行完由于是函数释放成为垃圾对象,当f=fn1时由于是赋值操作把地址赋值给了所以现在是f和fn1都指向一个内存空间,所以fn1执行完不能释放因为f还指向这个内存空间

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>03_闭包的作用</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
  10. 2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
  11. 问题:
  12. 1. 函数执行完后, 函数内部声明的局部变量是否还存在? 一般是不存在, 存在于闭中的变量才可能存在
  13. 2. 在函数外部能直接访问函数内部的局部变量吗? 不能, 但我们可以通过闭包让外部操作它
  14. -->
  15. <script type="text/javascript">
  16. function fn1() {
  17. var a = 2
  18. function fn2() {
  19. a++
  20. console.log(a)
  21. // return a
  22. }
  23. function fn3() {
  24. a--
  25. console.log(a)
  26. }
  27. return fn3
  28. }
  29. var f = fn1()
  30. f() // 1
  31. f() // 0
  32. </script>
  33. </body>
  34. </html>

05.闭包的生命周期

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>04_闭包的生命周期</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 产生: 在嵌套内部函数定义执行完时就产生了(不是在调用)
  10. 2. 死亡: 在嵌套的内部函数成为垃圾对象时
  11. -->
  12. <script type="text/javascript">
  13. function fn1() {
  14. //此时闭包就已经产生了(函数提升, 内部函数对象已经创建了)
  15. var a = 2
  16. function fn2 () {
  17. a++
  18. console.log(a)
  19. }
  20. return fn2
  21. }
  22. var f = fn1()
  23. f() // 3
  24. f() // 4
  25. f = null //闭包死亡(包含闭包的函数对象成为垃圾对象)
  26. </script>
  27. </body>
  28. </html>

06.闭包的应用 自定义模板

模板1

  1. function myModule() {
  2. //私有数据
  3. var msg = 'My atguigu'
  4. //操作数据的函数
  5. function doSomething() {
  6. console.log('doSomething() '+msg.toUpperCase())
  7. }
  8. function doOtherthing () {
  9. console.log('doOtherthing() '+msg.toLowerCase())
  10. }
  11. //向外暴露对象(给外部使用的方法)
  12. return {
  13. doSomething: doSomething,
  14. doOtherthing: doOtherthing
  15. }
  16. }

模板2

  1. (function () {
  2. //私有数据
  3. var msg = 'My atguigu'
  4. //操作数据的函数
  5. function doSomething() {
  6. console.log('doSomething() '+msg.toUpperCase())
  7. }
  8. function doOtherthing () {
  9. console.log('doOtherthing() '+msg.toLowerCase())
  10. }
  11. //向外暴露对象(给外部使用的方法)
  12. window.myModule2 = {
  13. doSomething: doSomething,
  14. doOtherthing: doOtherthing
  15. }
  16. })()

调用1

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>05_闭包的应用_自定义JS模块</title>
  6. </head>
  7. <body>
  8. <!--
  9. 闭包的应用2 : 定义JS模块
  10. * 具有特定功能的js文件
  11. * 将所有的数据和功能都封装在一个函数内部(私有的)
  12. * 只向外暴露一个包信n个方法的对象或函数
  13. * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
  14. -->
  15. <script type="text/javascript" src="myModule.js"></script>
  16. <script type="text/javascript">
  17. var module = myModule()
  18. module.doSomething()
  19. module.doOtherthing()
  20. </script>
  21. </body>
  22. </html>

调用2

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>05_闭包的应用_自定义JS模块2</title>
  6. </head>
  7. <body>
  8. <!--
  9. 闭包的应用2 : 定义JS模块
  10. * 具有特定功能的js文件
  11. * 将所有的数据和功能都封装在一个函数内部(私有的)
  12. * 只向外暴露一个包信n个方法的对象或函数
  13. * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
  14. -->
  15. <script type="text/javascript" src="myModule2.js"></script>
  16. <script type="text/javascript">
  17. myModule2.doSomething()
  18. myModule2.doOtherthing()
  19. </script>
  20. </body>
  21. </html>

07.闭包的缺点及解决

  1. 缺点
  • 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
  • 容易造成内存泄露
  1. 解决
  • 能不用闭包就不用
  • 及时释放
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>06_闭包的缺点及解决</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 缺点
  10. * 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
  11. * 容易造成内存泄露
  12. 2. 解决
  13. * 能不用闭包就不用
  14. * 及时释放
  15. -->
  16. <script type="text/javascript">
  17. function fn1() {
  18. var arr = new Array[100000]
  19. function fn2() {
  20. console.log(arr.length)
  21. }
  22. return fn2
  23. }
  24. var f = fn1()
  25. f()
  26. f = null //让内部函数成为垃圾对象-->回收闭包
  27. </script>
  28. </body>
  29. </html>

08.闭包面试题1

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>07_面试题1</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9. //代码片段一
  10. var name = "The Window";
  11. var object = {
  12. name : "My Object",
  13. getNameFunc : function(){
  14. return function(){
  15. return this.name;
  16. };
  17. }
  18. };
  19. alert(object.getNameFunc()()); //? the window 执行函数的对象是windows
  20. //代码片段二
  21. var name2 = "The Window";
  22. var object2 = {
  23. name2 : "My Object",
  24. getNameFunc : function(){
  25. var that = this;
  26. return function(){
  27. return that.name2;
  28. };
  29. }
  30. };
  31. alert(object2.getNameFunc()()); //? my object 闭包(内部函数引用外部函数变量) that指向的是Object
  32. </script>
  33. </body>
  34. </html>

09.闭包面试题2

没讲

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>07_面试题2</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9. function fun(n,o) {
  10. console.log(o)
  11. return {
  12. fun:function(m){
  13. return fun(m,n)
  14. }
  15. }
  16. }
  17. var a = fun(0)
  18. a.fun(1)
  19. a.fun(2)
  20. a.fun(3)//undefined,0,0,0
  21. var b = fun(0).fun(1).fun(2).fun(3)//undefined,0,1,2
  22. var c = fun(0).fun(1)
  23. c.fun(2)
  24. c.fun(3)//undefined,0,1,1
  25. </script>
  26. </body>
  27. </html>

———————-对象高级

01.对象创建模式

01._Object构造函数模式

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>01_Object构造函数模式</title>
  6. </head>
  7. <body>
  8. <!--
  9. 方式一: Object构造函数模式
  10. * 套路: 先创建空Object对象, 再动态添加属性/方法
  11. * 适用场景: 起始时不确定对象内部数据
  12. * 问题: 语句太多
  13. -->
  14. <script type="text/javascript">
  15. /*
  16. 一个人: name:"Tom", age: 12
  17. */
  18. // 先创建空Object对象
  19. var p = new Object()
  20. //var p = {}
  21. p = {} //此时内部数据是不确定的
  22. // 再动态添加属性/方法
  23. p.name = 'Tom'
  24. p.age = 12
  25. p.setName = function (name) {
  26. this.name = name
  27. }
  28. //测试
  29. console.log(p.name, p.age)//Tom
  30. p.setName('Bob')
  31. console.log(p.name, p.age)//Bob 12
  32. </script>
  33. </body>
  34. </html>

02._对象字面量的方式

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>02_对象字面量</title>
  6. </head>
  7. <body>
  8. <!--
  9. 方式二: 对象字面量模式
  10. * 套路: 使用{}创建对象, 同时指定属性/方法
  11. * 适用场景: 起始时对象内部数据是确定的
  12. * 问题: 如果创建多个对象, 有重复代码
  13. -->
  14. <script type="text/javascript">
  15. var p = {
  16. name: 'Tom',
  17. age: 12,
  18. setName: function (name) {
  19. this.name = name
  20. }
  21. }
  22. //测试
  23. console.log(p.name, p.age)
  24. p.setName('JACK')
  25. console.log(p.name, p.age)
  26. var p2 = { //如果创建多个对象代码很重复
  27. name: 'Bob',
  28. age: 13,
  29. setName: function (name) {
  30. this.name = name
  31. }
  32. }
  33. </script>
  34. </body>
  35. </html>

03.工厂模式

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>03_工厂模式</title>
  6. </head>
  7. <body>
  8. <!--
  9. 方式三: 工厂模式
  10. * 套路: 通过工厂函数动态创建对象并返回
  11. * 适用场景: 需要创建多个对象
  12. * 问题: 对象没有一个具体的类型, 都是Object类型
  13. -->
  14. <script type="text/javascript">
  15. function createPerson(name, age) { //返回一个对象的函数===>工厂函数
  16. var obj = {
  17. name: name,
  18. age: age,
  19. setName: function (name) {
  20. this.name = name
  21. }
  22. }
  23. return obj
  24. }
  25. // 创建2个人
  26. var p1 = createPerson('Tom', 12)
  27. var p2 = createPerson('Bob', 13)
  28. // p1/p2是Object类型
  29. function createStudent(name, price) {
  30. var obj = {
  31. name: name,
  32. price: price
  33. }
  34. return obj
  35. }
  36. var s = createStudent('张三', 12000)
  37. // s也是Object
  38. </script>
  39. </body>
  40. </html>

04._自定义构造函数模式

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>04_自定义构造函数模式</title>
  6. </head>
  7. <body>
  8. <!--
  9. 方式四: 自定义构造函数模式
  10. * 套路: 自定义构造函数, 通过new创建对象
  11. * 适用场景: 需要创建多个类型确定的对象
  12. * 问题: 每个对象都有相同的数据, 浪费内存
  13. -->
  14. <script type="text/javascript">
  15. //定义类型
  16. function Person(name, age) {
  17. this.name = name
  18. this.age = age
  19. this.setName = function (name) {
  20. this.name = name
  21. }
  22. }
  23. var p1 = new Person('Tom', 12)
  24. p1.setName('Jack')
  25. console.log(p1.name, p1.age)
  26. console.log(p1 instanceof Person)
  27. function Student (name, price) {
  28. this.name = name
  29. this.price = price
  30. }
  31. var s = new Student('Bob', 13000)
  32. console.log(s instanceof Student)
  33. var p2 = new Person('JACK', 23)
  34. console.log(p1, p2)
  35. </script>
  36. </body>
  37. </html>

05_构造函数+原型的组合模式

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>05_构造函数+原型的组合模式</title>
  6. </head>
  7. <body>
  8. <!--
  9. 方式六: 构造函数+原型的组合模式
  10. * 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
  11. * 适用场景: 需要创建多个类型确定的对象
  12. -->
  13. <script type="text/javascript">
  14. function Person(name, age) { //在构造函数中只初始化一般函数
  15. this.name = name
  16. this.age = age
  17. }
  18. Person.prototype.setName = function (name) {
  19. this.name = name
  20. }
  21. var p1 = new Person('Tom', 23)
  22. var p2 = new Person('Jack', 24)
  23. console.log(p1, p2)
  24. </script>
  25. </body>
  26. </html>

02.继承模式

01.原型链继承

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>01_原型链继承</title>
  6. </head>
  7. <body>
  8. <!--
  9. 方式1: 原型链继承
  10. 1. 套路
  11. 1. 定义父类型构造函数
  12. 2. 给父类型的原型添加方法
  13. 3. 定义子类型的构造函数
  14. 4. 创建父类型的对象赋值给子类型的原型
  15. 5. 将子类型原型的构造属性设置为子类型
  16. 6. 给子类型原型添加方法
  17. 7. 创建子类型的对象: 可以调用父类型的方法
  18. 2. 关键
  19. 1. 子类型的原型为父类型的一个实例对象
  20. -->
  21. <script type="text/javascript">
  22. //父类型
  23. function Supper() {
  24. this.supProp = 'Supper property'
  25. }
  26. Supper.prototype.showSupperProp = function () {
  27. console.log(this.supProp)
  28. }
  29. //子类型
  30. function Sub() {
  31. this.subProp = 'Sub property'
  32. }
  33. // 子类型的原型为父类型的一个实例对象
  34. Sub.prototype = new Supper()
  35. // 让子类型的原型的constructor指向子类型
  36. Sub.prototype.constructor = Sub
  37. Sub.prototype.showSubProp = function () {
  38. console.log(this.subProp)
  39. }
  40. var sub = new Sub()
  41. sub.showSupperProp()
  42. // sub.toString()
  43. sub.showSubProp()
  44. console.log(sub) // Sub
  45. </script>
  46. </body>
  47. </html>

01.JavaScript高级 - 图5

02.借用构造函数继承

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>02_借用构造函数继承</title>
  6. </head>
  7. <body>
  8. <!--
  9. 方式2: 借用构造函数继承(假的)
  10. 1. 套路:
  11. 1. 定义父类型构造函数
  12. 2. 定义子类型构造函数
  13. 3. 在子类型构造函数中调用父类型构造
  14. 2. 关键:
  15. 1. 在子类型构造函数中通用call()调用父类型构造函数
  16. -->
  17. <script type="text/javascript">
  18. function Person(name, age) {
  19. this.name = name
  20. this.age = age
  21. }
  22. function Student(name, age, price) {
  23. Person.call(this, name, age) // 相当于: this.Person(name, age)
  24. /*this.name = name
  25. this.age = age*/
  26. this.price = price
  27. }
  28. var s = new Student('Tom', 20, 14000)
  29. console.log(s.name, s.age, s.price)
  30. </script>
  31. </body>
  32. </html>

03.组合继承

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>03_组合继承</title>
  6. </head>
  7. <body>
  8. <!--
  9. 方式3: 原型链+借用构造函数的组合继承
  10. 1. 利用原型链实现对父类型对象的方法继承
  11. 2. 利用super()借用父类型构建函数初始化相同属性
  12. -->
  13. <script type="text/javascript">
  14. function Person(name, age) {
  15. this.name = name
  16. this.age = age
  17. }
  18. Person.prototype.setName = function (name) {
  19. this.name = name
  20. }
  21. function Student(name, age, price) {
  22. Person.call(this, name, age) // 为了得到属性
  23. this.price = price
  24. }
  25. Student.prototype = new Person() // 为了能看到父类型的方法
  26. Student.prototype.constructor = Student //修正constructor属性
  27. Student.prototype.setPrice = function (price) {
  28. this.price = price
  29. }
  30. var s = new Student('Tom', 24, 15000)
  31. s.setName('Bob')
  32. s.setPrice(16000)
  33. console.log(s.name, s.age, s.price)
  34. </script>
  35. </body>
  36. </html>

———————-线程机制与事件机制

01_进程与线程

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>01_进程与线程</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 进程:程序的一次执行, 它占有一片独有的内存空间
  10. 2. 线程: CPU的基本调度单位, 是程序执行的一个完整流程
  11. 3. 进程与线程
  12. * 一个进程中一般至少有一个运行的线程: 主线程
  13. * 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的
  14. * 一个进程内的数据可以供其中的多个线程直接共享
  15. * 多个进程之间的数据是不能直接共享的
  16. 4. 浏览器运行是单进程还是多进程?
  17. * 有的是单进程
  18. * firefox
  19. * 老版IE
  20. * 有的是多进程
  21. * chrome
  22. * 新版IE
  23. 5. 如何查看浏览器是否是多进程运行的呢?
  24. * 任务管理器==>进程
  25. 6. 浏览器运行是单线程还是多线程?
  26. * 都是多线程运行的
  27. -->
  28. </body>
  29. </html>

02_浏览器内核

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>02_浏览器内核</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 什么是浏览器内核?
  10. * 支持浏览器运行的最核心的程序
  11. 2. 不同的浏览器可能不太一样
  12. * Chrome, Safari: webkit
  13. * firefox: Gecko
  14. * IE: Trident
  15. * 360,搜狗等国内浏览器: Trident + webkit
  16. 3. 内核由很多模块组成
  17. * html,css文档解析模块 : 负责页面文本的解析
  18. * dom/css模块 : 负责dom/css在内存中的相关处理
  19. * 布局和渲染模块 : 负责页面的布局和效果的绘制
  20. * 布局和渲染模块 : 负责页面的布局和效果的绘制
  21. * 定时器模块 : 负责定时器的管理
  22. * 网络请求模块 : 负责服务器请求(常规/Ajax)
  23. * 事件响应模块 : 负责事件的管理
  24. -->
  25. </body>
  26. </html>

03_定时器引发的思考

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>03_定时器引发的思考</title>
  6. </head>
  7. <body>
  8. <button id="btn">启动定时器</button>
  9. <!--
  10. 1. 定时器真是定时执行的吗?
  11. * 定时器并不能保证真正定时执行
  12. * 一般会延迟一丁点(可以接受), 也有可能延迟很长时间(不能接受)
  13. 2. 定时器回调函数是在分线程执行的吗?
  14. * 在主线程执行的, js是单线程的
  15. 3. 定时器是如何实现的?
  16. * 事件循环模型(后面讲)
  17. -->
  18. <script type="text/javascript">
  19. document.getElementById('btn').onclick = function () {
  20. var start = Date.now()
  21. console.log('启动定时器前...')
  22. setTimeout(function () {
  23. console.log('定时器执行了', Date.now()-start)
  24. }, 200)
  25. console.log('启动定时器后...')
  26. // 做一个长时间的工作
  27. for (var i = 0; i < 1000000000; i++) {
  28. }
  29. }
  30. </script>
  31. </body>
  32. </html>

04_JS是单线程的

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>04_JS是单线程的</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. 如何证明js执行是单线程的?
  10. * setTimeout()的回调函数是在主线程执行的
  11. * 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
  12. 2. 为什么js要用单线程模式, 而不用多线程模式?
  13. * JavaScript的单线程,与它的用途有关。
  14. * 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
  15. * 这决定了它只能是单线程,否则会带来很复杂的同步问题
  16. 3. 代码的分类:
  17. * 初始化代码
  18. * 回调代码
  19. 4. js引擎执行代码的基本流程
  20. * 先执行初始化代码: 包含一些特别的代码 回调函数(异步执行)
  21. * 设置定时器
  22. * 绑定事件监听
  23. * 发送ajax请求
  24. * 后面在某个时刻才会执行回调代码
  25. -->
  26. <script type="text/javascript">
  27. setTimeout(function () {
  28. console.log('timeout 2222')
  29. alert('22222222')
  30. }, 2000)
  31. setTimeout(function () {
  32. console.log('timeout 1111')
  33. alert('1111111')
  34. }, 1000)
  35. setTimeout(function () {
  36. console.log('timeout() 00000')
  37. }, 0)
  38. function fn() {
  39. console.log('fn()')
  40. }
  41. fn()
  42. console.log('alert()之前')
  43. alert('------') //暂停当前主线程的执行, 同时暂停计时, 点击确定后, 恢复程序执行和计时
  44. console.log('alert()之后')
  45. </script>
  46. </body>
  47. </html>

05_事件循环模型

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>05_事件循环模型</title>
  6. </head>
  7. <body>
  8. <button id="btn">测试</button>
  9. <!--
  10. 1. 所有代码分类
  11. * 初始化执行代码(同步代码): 包含绑定dom事件监听, 设置定时器, 发送ajax请求的代码
  12. * 回调执行代码(异步代码): 处理回调逻辑
  13. 2. js引擎执行代码的基本流程:
  14. * 初始化代码===>回调代码
  15. 3. 模型的2个重要组成部分:
  16. * 事件(定时器/DOM事件/Ajax)管理模块
  17. * 回调队列
  18. 4. 模型的运转流程
  19. * 执行初始化代码, 将事件回调函数交给对应模块管理
  20. * 当事件发生时, 管理模块会将回调函数及其数据添加到回调列队中
  21. * 只有当初始化代码执行完后(可能要一定时间), 才会遍历读取回调队列中的回调函数执行
  22. -->
  23. <script type="text/javascript">
  24. function fn1() {
  25. console.log('fn1()')
  26. }
  27. fn1()
  28. document.getElementById('btn').onclick = function () {
  29. console.log('点击了btn')
  30. }
  31. setTimeout(function () {
  32. console.log('定时器执行了')
  33. }, 2000)
  34. function fn2() {
  35. console.log('fn2()')
  36. }
  37. fn2()
  38. </script>
  39. </body>
  40. </html>

06Web Workers测试

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>06_Web Workers_测试</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. H5规范提供了js分线程的实现, 取名为: Web Workers
  10. 2. 相关API
  11. * Worker: 构造函数, 加载分线程执行的js文件
  12. * Worker.prototype.onmessage: 用于接收另一个线程的回调函数
  13. * Worker.prototype.postM ssage: 向另一个线程发送消息
  14. 3. 不足
  15. * worker内代码不能操作DOM(更新UI)
  16. * 不能跨域加载JS
  17. * 不是每个浏览器都支持这个新特性
  18. -->
  19. <input type="text" placeholder="数值" id="number">
  20. <button id="btn">计算</button>
  21. <script type="text/javascript">
  22. // 1 1 2 3 5 8 f(n) = f(n-1) + f(n-2)
  23. function fibonacci(n) {
  24. return n<=2 ? 1 : fibonacci(n-1) + fibonacci(n-2) //递归调用
  25. }
  26. // console.log(fibonacci(7))
  27. var input = document.getElementById('number')
  28. document.getElementById('btn').onclick = function () {
  29. var number = input.value
  30. var result = fibonacci(number)
  31. alert(result)
  32. }
  33. </script>
  34. </body>
  35. </html>

06Web Workers测试2

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>06_Web Workers_测试</title>
  6. </head>
  7. <body>
  8. <!--
  9. 1. H5规范提供了js分线程的实现, 取名为: Web Workers
  10. 2. 相关API
  11. * Worker: 构造函数, 加载分线程执行的js文件
  12. * Worker.prototype.onmessage: 用于接收另一个线程的回调函数
  13. * Worker.prototype.postMessage: 向另一个线程发送消息
  14. 3. 不足
  15. * worker内代码不能操作DOM(更新UI)
  16. * 不能跨域加载JS
  17. * 不是每个浏览器都支持这个新特性
  18. -->
  19. <input type="text" placeholder="数值" id="number">
  20. <button id="btn">计算</button>
  21. <script type="text/javascript">
  22. var input = document.getElementById('number')
  23. document.getElementById('btn').onclick = function () {
  24. var number = input.value
  25. //创建一个Worker对象
  26. var worker = new Worker('worker.js')
  27. // 绑定接收消息的监听
  28. worker.onmessage = function (event) {
  29. console.log('主线程接收分线程返回的数据: '+event.data)
  30. alert(event.data)
  31. }
  32. // 向分线程发送消息
  33. worker.postMessage(number)
  34. console.log('主线程向分线程发送数据: '+number)
  35. }
  36. // console.log(this) // window
  37. </script>
  38. </body>
  39. </html>

H5 Web Workers(多线程).png)

  1. function fibonacci(n) {
  2. return n<=2 ? 1 : fibonacci(n-1) + fibonacci(n-2) //递归调用
  3. }
  4. console.log(this)
  5. this.onmessage = function (event) {
  6. var number = event.data
  7. console.log('分线程接收到主线程发送的数据: '+number)
  8. //计算
  9. var result = fibonacci(number)
  10. postMessage(result)
  11. console.log('分线程向主线程返回数据: '+result)
  12. // alert(result) alert是window的方法, 在分线程不能调用
  13. // 分线程中的全局对象不再是window, 所以在分线程中不可能更新界面
  14. }