JS基础

js基础

一.垃圾回收机制

  1. 全局变量一般不会被回收,局部变量执行完毕就回收

  2. 内存生命周期:内存分配------内存使用------内存回收

  3. 引用 计数法:跟踪引用的次数(ie 浏览器),嵌套引用(相互引用)失效

  4. 标记清除法:主流浏览器使用,从根部(全局变量)定期扫描,找不到就清除

二.闭包

  1. 内层函数引用外层函数的变量就会形成闭包

  2. 变量私有化

  3. 闭包会导致内存泄漏

三.原型和原型链

  1. 每个函数都有一个prototype(显示原型)属性,prototype属性指向的对象就是构造函数的原型对象,prototype中的有个constructor属性对象构造函数
  2. 通过new一个构造函数得到实例对象,实例对象的__proto__指向了原型对象,实例对象的__proto__===构造函数的prototype。proto(也叫隐式原型)不是语言本身的特性,是浏览器厂商添加的私有属性,所有获取实例对象的原型对象,可使用Object.getPrototypeOf()方法
  3. 实例对象.hasOwnProperty("name") 判断是否为实例本身的属性
  4. 实例对象的__proto__===构造函数的原型对象(prototype).proto ===Object的原型对象.proto===null

四.js六种继承方式

1. 原型链继承:将子类构造函数的原型对象(prototype)指向另一个构造函数的实例

JS 复制代码
function Person() { 
    this.head = 1 this.hand = 2 
 } 

function YellowRace() { } 
YellowRace.prototype = new Person()
const hjy = new YellowRace() 
console.log(hjy.head) // 1 console.log(hjy.hand) // 2

这种继承方式的弊端:

  • 创建hjy实例时不能传参,也就是YellowRace构造函数本身不接受参数。

  • 当原型上的属性是引用数据类型时,所有实例都会共享这个属性,即某个实例对这个属性重写会影响其他实例。

2.盗用构造函数(也叫对象伪装或者经典继承):通过子类调用父类的构造函数实现上下文的绑定

JS 复制代码
function Person(eyes) { this.eyes = eyes this.colors = ['white', 'yellow', 'black'] } 
function YellowRace() { Person.call(this, 'black') // 调用构造函数并传参 } 
const hjy = new YellowRace() hjy.colors.push('green') 
console.log(hjy.colors) // ['white', 'yellow', 'black', 'green'] console.log(hjy.eyes) // black
const laowang = new YellowRace() 
console.log(laowang.colors) // ['white', 'yellow', 'black'] console.log(laowang.eyes) // black
  • 必须在构造函数中定义方法,通过盗用构造函数继承的方法本质上都变成了实例自己的方法,不是公共的方法,因此失去了复用性。
  • 子类不能访问父类原型上定义的方法,因此所有类型只能使用构造函数模式,原因如上图所示,YellowRace构造函数、hjy和laowang实例都没有和Person的原型对象产生联系

3.组合继承:先通过盗用构造函数实现上下文绑定和传参,然后再使用原型链继承的手段将子构造函数的prototype指向父构造函数的实例

JS 复制代码
function Person(eyes) {
  this.eyes = eyes
  this.colors = ['white', 'yellow', 'black']
}

Person.prototype.getEyes = function () {
  return this.eyes
}

function YellowRace() {
  Person.call(this, 'black') // 调用构造函数并传参
}
YellowRace.prototype = new Person() // 再次调用构造函数
const hjy = new YellowRace()
hjy.colors.push('green')
const laowang = new YellowRace()
console.log(hjy.colors) // ['white', 'yellow', 'black', 'green']
console.log(laowang.colors) // ['white', 'yellow', 'black']
console.log(hjy.getEyes()) // black

组合继承还是有一个小小的缺点,那就是在实现的过程中调用了两次Person构造函数,有一定程度上的性能浪费。这个缺点在最后的寄生式组合继承可以改善。

4.原型式继承:Object.create()

JS 复制代码
const object = function (o) {
  function F() { }
  F.prototype = o
  return new F()
}

缺点:

  1. 不能传参,使用手写的object()不能传,但使用Object.create()是可以传参的。

  2. 原对象中的引用类型的属性会被新对象共享。

5.寄生式继承

JS 复制代码
function inherit(o) {

  let clone = Object.create(o)
  clone.sayHi = function () { // 增强对象
    console.log('Hi')
  }
  return clone
}

const hjy = {
  eyes: 'black',
  colors: ['white', 'yellow', 'black']
}

const laowang = inherit(hjy)
console.log(laowang.eyes) // black
console.log(laowang.colors) // ['white', 'yellow', 'black']
laowang.sayHi() //

6.寄生式组合继承:通过盗用构造函数继承属性,但使用混合式原型链继承方法。基本思路就是使用寄生式继承来继承父类的原型对象,然后将返回的新对象赋值给子类的原型对象。

JS 复制代码
function inherit(Son, Father) {
  const prototype = Object.create(Father.prototype) // 获取父类原型对象副本
  prototype.constructor = Son // 将获取的副本的constructor指向子类,以此增强副本原型对象
  Son.prototype = prototype // 将子类的原型对象指向副本原型对象
}

function Person(eyes) {
  this.eyes = eyes
  this.colors = ['white', 'yellow', 'black']
}

Person.prototype.getEyes = function () {

  return this.eyes

}

function YellowRace() {

  Person.call(this, 'black') // 调用构造函数并传参

}

inherit(YellowRace, Person) // 寄生式继承,不用第二次调用构造函数
const hjy = new YellowRace()
hjy.colors.push('green')
const laowang = new YellowRace()
console.log(hjy.colors) // ['white', 'yellow', 'black', 'green']
console.log(laowang.colors) // ['white', 'yellow', 'black']
console.log(hjy.getEyes()) // black

原型与实例的关系可以用两种方式来确定:instanceof操作符和isPrototypeOf()方法。

JS 复制代码
function Perosn(name) {
  this.name = name
}

const hjy = new Perosn('滑稽鸭')
const laowang = {
  name: '老王'
}

console.log(hjy instanceof Perosn) // true
console.log(laowang instanceof Perosn) // false

五.事件模型

1.事件流都会经历三个阶段

  • 事件捕获阶段(capture phase)
  • 处于目标阶段(target phase)
  • 事件冒泡阶段(bubbling phase)

2.事件模型

原始事件模型(DOM0):

  • html直接绑定的事件 <div onclick="fun1()">
  • js事件绑定document.getElementByid("app").onCLick=function(){]

特性:

  • 只支持冒泡,不支持捕获
  • 同一个类型的事件只能绑定一次
  • 速度快

标准事件模型

  • 添加事件 document.getElementById('app').addEventListener('click',function(e){},false) addEventListener第一个参数事件名称不带on
    第二个参数处理函数
    第三个参数可省略默认为false(冒泡传递),true为捕获传递
  • 删除事件 removeEventListener(eventType, handler, useCapture)
  • e.stopPropagation :阻止事件冒泡,不阻止默认事件。当前元素绑定多个事件都可以执行
  • e.stopImmediatePropagation():阻止事件冒泡,不阻止默认事件。后面绑定的事件不可执行。
  • e. preventDefault():不阻止魔炮,阻止默认事件(连接跳转、表单等)
  • html直接绑定事件reture false 阻止冒泡,阻止默认事件
html 复制代码
<a href="http://www.baidu.com">
        <div id="click" style="width:100px;height:100px;background-color: rgb(18, 56, 246);" onclick="return false">
          clickme</div>
      </a>

IE事件模型(基本不用)

  • 绑定事件:attachEvent(eventType, handler)
  • 删除事件:detachEvent(eventType, handler)

六.js阻塞html解析,异步加载defer和async区别

html 解析器运行于主线程中,如果遇到<script> 标签后会阻塞,直到脚本从网络中下载并被执行,也就是说<script> 标签的脚本会阻塞浏览器的渲染

页面生命周期时间

  • DOMContentLoaded:页面已经完全加载了 html 并且构建了 dom 树,但样式和 img 这样的资源还没有加载完
  • load:浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等。
  • beforeunload/unload:当用户正在离开页面时。

异步加载

  • async 执行时机:下载完后,立即执行
  • defer 下载完后,在 dom 解析完之后、触发 DOMContentLoaded 方法之前执行
相关推荐
J不A秃V头A24 分钟前
Vue3:编写一个插件(进阶)
前端·vue.js
司篂篂1 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客1 小时前
pinia在vue3中的使用
前端·javascript·vue.js
宇文仲竹2 小时前
edge 插件 iframe 读取
前端·edge
Kika写代码2 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构
天下无贼!3 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
Jiaberrr3 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
赵啸林3 小时前
npm发布插件超级简单版
前端·npm·node.js
我码玄黄3 小时前
THREE.js:网页上的3D世界构建者
开发语言·javascript·3d
罔闻_spider3 小时前
爬虫----webpack
前端·爬虫·webpack