JavaScript高级|青训营笔记

72 阅读8分钟

这是我参与「第四届青训营 」笔记创作活动的的第9天

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

1). 基本(值)类型

Number ----- 任意数值 -------- typeof
String ----- 任意字符串 ------ typeof
Boolean ---- true/false ----- typeof
undefined --- undefined ----- typeof/===
null -------- null ---------- ===

2). 对象(引用)类型

Object ----- typeof/instanceof
Array ------ instanceof
Function ---- typeof/instanceof

2. 数据,变量, 内存的理解

1). 什么是数据?

在内存中可读的, 可传递的保存了特定信息的'东东'
一切皆数据, 函数也是数据
在内存中的所有操作的目标: 数据

2). 什么是变量?

在程序运行过程中它的值是允许改变的量
一个变量对应一块小内存, 它的值保存在此内存中  

3). 什么是内存?

内存条通电后产生的存储空间(临时的)
一块内存包含2个方面的数据
    内部存储的数据
    地址值数据
内存空间的分类
    栈空间: 全局变量和局部变量
    堆空间: 对象 

4). 内存,数据, 变量三者之间的关系

内存是容器, 用来存储不同数据
变量是内存的标识, 通过变量我们可以操作(读/写)内存中的数据  

3. 对象的理解和使用

1). 什么是对象?

多个数据(属性)的集合
用来保存多个数据(属性)的容器

2). 属性组成:

属性名 : 字符串(标识)
属性值 : 任意类型

3). 属性的分类:

一般 : 属性值不是function  描述对象的状态
方法 : 属性值为function的属性  描述对象的行为

4). 特别的对象

数组: 属性名是0,1,2,3之类的索引
函数: 可以执行的

5). 如何操作内部属性(方法)

.属性名
['属性名']: 属性名有特殊字符/属性名是一个变量

4. 函数的理解和使用

1). 什么是函数?

用来实现特定功能的, n条语句的封装体
只有函数类型的数据是可以执行的, 其它的都不可以

2). 为什么要用函数?

提高复用性
便于阅读交流

3). 函数也是对象

function instanceof Object===true
函数有属性: prototype
函数有方法: call()/apply()
可以添加新的属性/方法

4). 函数的四种不同角色

一般函数 : 直接调用
构造函数 : 通过new调用
方法: 通过对象调用
对象 : 通过.调用内部的属性/方法

5). 函数中的this

  1. 理解this:
     - 关键字
     - 变量
  2. this的指向问题
     - 函数this不是函数定义的时候决定的
     - 函数this指向谁看如何调用当前的函数
  3. this指向分类
     - 函数自调用: window
     - 构造函数(new function): 当前构造函数的实例对象
     - 对象.方法(): 对象本身
     - fun.call/apply(指定的对象): 指定的对象

6). 匿名函数自调用:

(function(){
  //实现代码
})()
专业术语为: IIFE (Immediately Invoked Function Expression) 立即调用函数表达式                       

7). 回调函数的理解

什么函数才是回调函数?
    你定义的
    你没有调用
    但它最终执行了(在一定条件下或某个时刻)
常用的回调函数
    dom事件回调函数
    定时器回调函数
    ajax请求回调函数(后面讲解)
    生命周期回调函数(后面讲解)

1. 原型与原型链

1). 什么是原型对象:

1. 每个函数都有一个prototype属性,该属性指向的是原型对象(显示原型对象)
2. 每个实例对象身上都有一个__proto__属性,该属性指向的也是原型对象(隐式原型对象)
3. 构造函数的显示原型 === 当前构造函数实例对象的隐式原型对象
4. 原型对象的本质: 普通的Object实例

2). 什么是原型链

1. 查找对象的属性的时候先在自身找,如果自身没有沿着__proto__找原型对象
2. 如果原型对象上还没有,继续沿着__proto__,直到找到Object的原型对象
3. 如果还没有找到返回undefined
4. 原型链: 沿着__proto__查找属性(方法)的这条链就是原型链

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

1). 变量提升与函数提升

1. js引擎在js代码正式执行之前会做一些预解析的工作
2. 找关键字: varfunction
3. 找到var以后将var后边的变量提前声明,但是不赋值 var a;
4. 找到function以后定义对应的函数,也就是说函数在预解析的时候已经定义完毕
5. 预解析: 全局预解析,局部预解析
6. 注意:
    - 全局预解析在定义函数的时候不关心函数是否被使用
    - 函数局部预解析的时候如果内部函数没有被使用就不会提前定义

2). 理解

1. 理解: 
    - 执行上下文抽象的概念,代表了代码执行的环境,包含: 执行环境,变量对象,this,作用域链
2. 流程:
    - js引擎在js代码正式执行之前会先创建一个执行环境(开发商批的地,工程队施工的环境)
    - 进入该环境以后创建一个变量对象(打地基),该对象用于收集当前环境下的: 变量,函数,函数的参数,this
        - 找关键字var ,function
    - 确认this的指向
    - 创建作用域链
3. 重点:
    - 执行上下文是动态创建的
    - 尤其是针对函数,每调用一次函数都会创建一次执行上下文
执行上下文栈: 用来管理产生的多个执行上下文

3). 分类:

全局: window
函数: 对程序员来说是透明的

4). 生命周期

全局 : 准备执行全局代码前产生, 当页面刷新/关闭页面时死亡
函数 : 调用函数时产生, 函数执行完时死亡

5). 包含哪些属性:

全局 : 
    用var定义的全局变量  ==>undefined
    使用function声明的函数   ===>function
    this   ===>window
函数
    用var定义的局部变量  ==>undefined
    使用function声明的函数   ===>function
    this   ===> 调用函数的对象, 如果没有指定就是window 
    形参变量   ===>对应实参值
    arguments ===>实参列表的伪数组

6). 执行上下文创建和初始化的过程

全局:
    在全局代码执行前最先创建一个全局执行上下文(window)
    收集一些全局变量, 并初始化
    将这些变量设置为window的属性
函数:
    在调用函数时, 在执行函数体之前先创建一个函数执行上下文
    收集一些局部变量, 并初始化
    将这些变量设置为执行上下文的属性

3. 作用域与作用域链

1). 理解:

作用域:    
   - 抽象的概念
   - 用来决定代码执行的范围, 变量所属的范围
   - 作用域是代码定义的时候决定的
   - 作用域作用:
     - 隔离变量
     - 规定其之后的作用域链是什么样的,体现: [[scopes]]: 上一级作用域链
作用域链: 
   - 作用域链是一个链表结构
   - 该结构内保存的是一个个的变量对象
   - 作用域链什么时候创建的:在js代码正式执行之前创建的

2). 分类:

全局
函数
js没有块作用域(在ES6之前)
eval()作用域

3). 作用

作用域: 隔离变量, 可以在不同作用域定义同名的变量不冲突
作用域链: 查找变量

4). 区别作用域与执行上下文

作用域: 静态的, 编码时就确定了(不是在运行时), 一旦确定就不会变化了
执行上下文: 动态的, 执行代码时动态创建, 当执行结束消失
联系: 执行上下文环境是在对应的作用域中的

4. 闭包

1). 闭包形成的条件:

   - 函数嵌套
   - 内部函数引用外部函数的局部变量
   - 内部函数被使用,注意: 函数变量提升的时候如果内部函数没有被使用,在预解析的过程中不会定义内部函数

2). 什么是闭包:

   - 闭包是一个存在内部函数的引用关系
   - 该引用指向的是外部函数的局部变量对象(前提是内部函数使用了外部函数的局部变量)

3). 写一个闭包程序

function fn1() {
  var a = 2;
  function fn2() {
    a++;
    console.log(a);
  }
  return fn2;
}
var f = fn1();
f();
f();

4). 闭包的作用:

   - 延长外部函数变量对象的生命周期
   - 使用闭包能够间接的从函数外部访问函数内部的私有变量

5). 闭包应用:

循环遍历加监听: 给多个li加点击监听, 读取当前下标
模块化: 封装一些数据以及操作数据的函数, 向外暴露一些行为
JS框架(jQuery)大量使用了闭包

6). 闭包的优缺点:

   - 优点: 延长外部函数变量对象的生命周期
   - 缺点: 延长外部函数变量对象的生命周期(占内存,如果不及时清除容易造成内存溢出,泄漏)
     解决: 及时清除闭包 : f = null; //让内部函数对象成为垃圾对象( 内部函数身上没有指针指向)

7). 闭包的生命周期:

   - 产生:在嵌套的内部函数定义执行完时就产生(不是在调用)
   - 死亡:在嵌套的内部函数成为垃圾对象时

5. 内存溢出与内存泄露

1). 内存溢出

一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误

2). 内存泄露

占用的内存没有及时释放
内存泄露积累多了就容易导致内存溢出
常见的内存泄露:
    意外的全局变量
    没有及时清理的计时器或回调函数
    闭包