Code前端首页关于Code前端联系我们

JS 理论精要

terry 2年前 (2023-09-07) 阅读数 255 #Vue

JS 事件循环机制

  • 同步任务队列
  • 异步任务队列
    • 宏任务包括:setTimeout, setInterval, setImmediate, I/O, UI rendering
    • 微任务包括:process.nextTick, promise.then, MutationObserver
  1. 同步和异步任务进入不同的执行位置,同步进入主线程,异步进入事件表并注册函数
  2. 当指定的事情完成后(强调),事件表会将此功能移动到事件队列
  3. 主线程中的任务执行完后为空,去事件队列中读取对应的函数,进入主线程执行
  4. 不断重复上述过程,通常称为事件循环(eventloop)。

js面向对象的理解

  • 对象:一切都是对象
  • 类:对象的细分
  • 示例:课堂上的具体事物

js 为什么是单线程而不是多线程

  • 进程:CPU资源分配的最小单位; (是能够拥有资源并独立运作的最小单位)
  • 线程:是CPU调度的最小单位; (线程是基于进程的程序运行单元,一个进程中可以有多个线程)

浏览器是一个多进程
放在浏览器中,每次打开一个标签页,其实都是一个新的进程,在这个进程中有ui渲染线程,js引擎线程,http请求线程等等。因此,浏览器是一个多进程。

JavaScript 的主要目的是与用户交互并操作 DOM。这就决定了它只能是单线程的,否则会造成非常复杂的同步问题。例如,假设JavaScript同时有两个线程,一个线程向某个DOM节点添加内容,另一个线程删除这个节点,那么浏览器应该以哪个线程为基础呢?

为了利用多核CPU的计算能力,HTML5提出了Web Worker标准,该标准允许JavaScript脚本创建多个线程,但子线程完全由主线程控制,不得操作DOM。因此,这个新标准并没有改变 JavaScript 的单线程本质。

js垃圾处理机制

内存管理:“可达性” ,指的是可以以任何方式访问或使用的值,它们保证存储在内存中。

  1. 具有一组固有的可实现值,由于明显的原因无法删除,这些值称为根。示例:
  • 局部变量和局部函数的参数
  • 当前嵌套调用链中其他函数的变量和参数
  • 全局变量
  • 还有其他一些,里面
  1. 如果引用或引用链可以达到根 的任何其他值,则认为该值是可访问的。

垃圾回收器,它监视所有对象,并删除那些不可访问的对象

  1. 什么是污垢?
    一般来说,没有被引用的对象是垃圾,必须删除。有一个例外。如果一些对象引用形成一个环并互相转向,但根无法访问它们,那么这些对象也是垃圾,必须删除。
  2. 如何控制乱扔垃圾?
    1. 标记-清除算法 标记-清除GC
    2. 垃圾收集器获取根并“标记”(记住)它们。
    3. 然后访问它并“标记”其中的所有引用。
    4. 然后它访问标记的对象并标记它们的引用。所有访问过的对象都会被记住,这样同一个对象以后就不会被访问两次。
    5. 依此类推,直到有未访问的引用(可通过 root 访问)。
    6. 除标记的对象外,所有对象均被删除。
     ![标记删除](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/502fe53626d44e998b49b24ae69d5176~tplv-k3u1fbpfcp-zoom-1.image)
     
    1. 标记紧凑型 标记紧凑型
    2. 参考编号
    3. GC复制算法
    4. 保守GC
    5. 世代回收
    6. 增量GC
js继承

如果要继承,必须提供一个父类(从谁继承,给出继承的属性)

  1. 原型链继承:让新实例的原型等于父类的实例。
  • 特点
    1. 实例可以继承的属性包括:实例构造函数的属性、父类构造函数的属性、父类原型的属性。 (新实例不会继承父类实例的属性!)
    1. 新实例无法向父类构造函数传递参数。
    2. 继承是单一的。
    3. 所有新实例共享父类实例的属性。 (原型属性是共享的。如果一个实例更改原型属性,则另一实例的原型属性也会更改!)
  1. 信用构造函数(类继承):用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))

特点
1。只继承父类构造函数的属性,不继承父类原型的属性。
2。修复了原型链继承的缺陷1、2、3。
3。您可以继承多个构造函数属性(调用更多)。
4。子实例中可以向父实例传递参数。

缺点
1。只能继承父类构造函数的属性。
2。无法实现构造函数重用。 (每次使用都要重新调用)
3。每个新实例都有一个父类构造函数的副本,该副本是臃肿的。

  1. 组合继承(组合原型链继承和借用构造函数继承)(常用)结合了两种模式的优点,传参和复用
  • 特点
    1. 可以继承父类原型上的属性,传递参数并复用。
    2. 引入的每个新实例的构造函数属性都是私有的。
  • 缺点:父类构造函数被调用两次(消耗内存),子类构造函数替换原型上的父类构造函数。
  1. 原型继承
    • 重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了一个实例或者一个可以随意添加属性的对象。 object.create()就是这个原理。
    • 特点:类似于复制对象并用函数包装它。
      1. 所有实例都继承原型的属性。
      2. 无法实现重复利用。 (稍后会添加新的实例属性)
  2. 寄生遗传
  • 重点:是给原型继承披上一层外壳。
  • 优点:没有创建自定义类型,因为它只是一个返回对象(this)的外壳,这个函数自然会创建一个新对象。
  • 缺点:原型未使用,无法重复使用。
  1. 寄生组合遗传(常用)
  • 寄生:在函数中返回一个对象,然后调用
  • 组合:1.函数的原型等于另一个实例。 2.在函数中使用apply或者call引入另一个构造函数,可以传递参数 
  • 重点:修复了构图继承问题
// 父类---------------------------
function Person(name){ //给构造函数添加参数
  this.name=name
  this.sayName =function(){
    alert(this.name)
  }
}
Person.prototype.age = 18; //给构造函数添加了原型属性

// 原型链继承---------------------------
function Per(){
  this.name = 'panpan';  
}
Per.prototype= new Person(); //重点
var per1 = new Per();
console.log(per1.age); // 18

// instanceof判断元素是否在另一个元素的原型链上
console.log(per1 instanceof Person); //true
// 借用构造函数继承---------------------
function Con(){
  Person.call(this,'ava'); //重点
  this.age = 21
}
var con1 = new Con()
console.log(con1.name) //ava
console.log(con1.age) //21
console.log(con1 instanceof Person) //false

// 组合原型链继承和借用构造函数继承
function SubType(name){
  Person.call(this,name); //借用构造函数模式
}
SubType.prototype= new Person();  //原型链继承
var sub = new SubType('lian')
console.log(sub.name) //lian  继承构造函数属性
console.log(sub.age) //18    继承父类原型属性

// 原型式继承---------------------------
// 先封装1个函数容器,用来输出对象和承载继承的原型
function content(obj){
  function F(){}
  F.prototype=obj; //继承传入的参数
  return new F() //返回函数对象
}
var sup = new Person();   //拿到父类的实例
var sup1 = content(sup)
console.log(sup1.age) //18 继承父类函数属性

// 寄生式继承----------------------
// 给原型式继承再套个壳子传递参数
function subObject(obj){
  var sub = content(obj)
  obj.name= 'pan';
  return sub
}
//声明后成了可增添属性的对象
var sup2 = subObject(sup)
console.log(typeof subObject) //function
console.log(typeof sup2) //object
console.log(sup2.name) //pan

// 寄生组合式继承---------------------
// 寄生
function content(obj){
  function F(){}
  F.prototype=obj; //继承传入的参数
  return new F() //返回函数对象
}
// content就是F实例的另一种表达
var con = content(Person.prototype)
// con实例(F实例)的原型链继承了父类函数的原型
// 上述更像原型链继承,只不过继承了原型属性

// 组合
function Sub(){
  Person.call(this) // 继承父类构造函数属性
} //解决组合式2次调用构造函数属性的缺点
// 重点
Sub.prototype = con; //继承con实例
con.constructor = Sub;  //一定要修复实例
var sub1 = new Sub();
// Sub实例继承了构造函数属性、父类实例、con的函数属性
console.log(sub1.age)
 

锁定

闭包主要用于设计私有方法和变量。闭包的优点是避免污染全局变量。缺点是闭包会保留在内存中并增加内存使用量。使用不当很容易造成内存泄漏。在js中,函数就是闭包,只有函数才有作用域的概念

闭包具有三个属性:

  1. 功能嵌套功能
  2. 函数可以引用外部参数和变量
  3. 参数和变量不会被F垃圾回收机制回收

new 运算符 它到底有什么作用?

  1. 创建一个空对象,这个变量引用该对象,同时也继承了函数的原型。
  2. 属性和方法被添加到它引用的对象中。
  3. 新创建的对象被 this 引用,并且 this 在最后隐式返回。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门