- 函数也是对象
- 函数具备行为,可以被调用
- 用来减少代码量,复用,隔离变量,减少命名污染
- 普通的函数
- 构造函数
- IIFE(匿名函数自调用)
- 回调函数(事件的回调,定时器的回调)
- 理解this:
- this的指向问题
- 函数this不是函数定义的时候决定的
- 函数this指向谁看如何调用当前的函数
- this指向分类
- 函数自调用: window
- 构造函数(new function): 当前构造函数的实例对象
- 对象.方法(): 对象本身
- fun.call/apply(指定的对象): 指定的对象
1. 每个函数都有一个prototype属性,该属性指向的是原型对象(显示原型对象)
2. 每个实例对象身上都有一个__proto__属性,该属性指向的也是原型对象(隐式原型对象)
3. 构造函数的显示原型 === 当前构造函数实例对象的隐式原型对象
4. 原型对象的本质: 普通的Object实例
1. 查找对象的属性的时候现在自身找,如果自身没有沿着__proto__找原型对象
2. 如果原型对象上还没有,继续沿着__proto__,直到找到Object的原型对象对象
3. 如果还没有找到返回undefined
4. 原型链: 沿着__proto__查找的这条链就是原型链
1. js引擎在js代码正式执行之前会做一些预解析的工作
2. 找关键字: var, function
3. 找到var以后将var后边的变量提前声明,但是不赋值 var a;
4. 找到function以后定义对应的函数,也就是说函数在预解析的时候已经定义完毕
5. 预解析: 全局预解析,局部预解析
6. 注意:
- 全局预解析在定义函数的时候不关心函数是否被使用
- 函数局部预解析的时候如果内部函数没有被使用就不会提前定义
1. 理解:
- 执行上下文抽象的概念,代表了代码执行的环境,包含: 执行环境,变量对象,this,作用域链
2. 流程:
- js引擎在js代码正式执行之前会先创建一个执行环境(开发商批的地,工程队施工的环境)
- 进入该环境以后创建一个变量对象(打地基),该对象用于收集当前环境下的: 变量,函数,函数的参数,this
- 找关键字var ,function
- 确认this的指向
- 创建作用域链
3. 重点:
- 执行上下文是动态创建的
- 尤其是针对函数,每调用一次函数都会创建一次执行上下文
- 抽象的概念
- 用来决定代码执行的范围, 变量所属的范围
- 作用域是代码定义的时候决定的
- 作用域作用:
- 隔离变量
- 规定其之后的作用域链是什么样的,体现: [[scopes]]: 上一级作用域链
- 作用域链式一个数组结构
- 该结构内保存的是一个个的变量对象
- 作用域链什么时候创建的:在js代码正式执行之前创建的
- 函数嵌套
- 内部函数引用外部函数的局部变量
- 内部函数被使用,注意: 函数变量提升的时候如果内部函数没有被使用,在预解析的过程中不会定义内部函数
- 闭包是一个存在内部函数的引用关系
- 该引用指向的是外部函数的局部变量对象(前提是内部函数使用了外部函数的局部变量)
- 延长外部函数变量对象的生命周期
- 使用闭包能够间接的从函数外部访问函数内部的私有变量
- 优点: 延长外部函数变量对象的生命周期
- 缺点: 延长外部函数变量对象的生命周期(占内存,如果不及时清除容易造成内存溢出,泄漏)
- 及时清除闭包
- 让内部的函数成为垃圾对象 ---> 内部函数身上没有指针指向
1. 核心**
- 子类的原型 成为 父类的实例
- Child.prototype = new Parent()
2. 注意问题:
- 以上的写法会导致子类的构造器属性丢失
3. 解决问题
- Child.prototype.constructor = Child
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.showName = function () {
console.log(this.name);
}
var person1 = new Person('kobe', 43);
// 原型继承: 子类的原型 成为 父类的实例
// Child.prototype = {constructor: Child}
Child.prototype = new Person();
Child.prototype.constructor = Child;
// 定义一个child类
function Child(name, age) {
this.name = name;
this.age = age;
}
var child1 = new Child('xiaoming', 18);
console.log(child1);
child1.showName();
1. 核心**
- 让父类的方法在子类中执行
2. 注意问题:
- 如果父类的方法在子类中直接调用,会导致在window对象身上添加了不必要的属性
3. 解决问题:
- 使用call || apply
- Parent.call(子类的实例对象, 参数)
- Parent.call(this, 参数)
1. js是单线程的 ---> 主线程
2. 同步任务 || 异步任务
- 同步: 1. 阻塞的 2. 同步是没有回调的
- 异步: 1. 非阻塞 2. 异步有回调(用来通知当前异步任务执行的结果)
3. 定时器真的准时吗?不一样
- 特例:定时器任务的后边有运算量大的代码段
4. 事件轮询机制:
- 1. js任务都会在js的主线程执行
- 2. 当开启一个异步任务的时候会交给对应的管理模块去管理
- 3. 主线程继续执行后续的任务
- 4. 管理模块接管的对应的回调,它会在恰当的时机将对应的回调放入callback queue中
- 5. 当主线程上的所有同步任务执行完毕会通过 ‘轮询’的方式询问callback queue是否有可执行的回调
- 6. 假如没有会反复询问
- 7. 假如有可执行的回调将对应的回调钩到主线程执行
5. 开发注意事项;
- 不要在定时器任务之后放置运算量大的代码段;
1. 创建一个空对象
2. 将this指向该空对象
3. 执行函数
4. 将执行的结果返回