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 方法之前执行
相关推荐
WeiXiao_Hyy14 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡31 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone36 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king2 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳2 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵3 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星3 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js