美文网首页
面向对象及事件循环

面向对象及事件循环

作者: A_走在冷风中 | 来源:发表于2021-09-07 20:35 被阅读0次

一、面向对象

1.1 普通函数与构造函数

函数还是之前的函数,唯一的区别就是首字母大写

function Foo(m, n) {
  let ret = m + n
  this.m = m
  this.n = n
  return ret
}

// 01 普通函数调用
let ret = Foo(10, 20)
console.log(ret)

// 02 构造函数执行
let res = new Foo(20, 20)
console.log(res)

1.1.1 普通函数

  • 正常调用,不需要 new 关键字
  • 执行过程遵循堆栈 + 作用域及作用域链查找的运行机制

1.1.2 构造函数

  • 使用 new 关键字调用
  • 与普通函数类似,同样会创建私有上下文,然后进栈执行
  • 执行 new 操作时,浏览器会创建一个空间表示空以象与 this 关联
  • 函数体内如果没有 return 或者说 return 的是基本数据类型,默认返回对象实例
  • 函数体内如果返回引用类型,那么就以自己返回为主
  • 函数此时叫做类, 返回的结果叫做对象实例

1.1.3 new 操作符

  • 正常情况下使用 new 完成对象实例创建,如果当前类不需要传递参数,则可以不加括号运行
  • new Foo , 没有加小括号的时候说明 Foo 不需要传参,称之为无参列表
  • new Foo 与 new Foo() 的优先级不同,前者为 19, 后者为 20
  • 每一次 new 都会将函数重新执行,生成一个新的执行上下文,创建一个新的实例对象,因此两个实例对象不一样

1.2 原型及原型链

原理图

1.2.1 名词说明

  • prototype 属性
    • 每一个函数(除了箭头函数)数据类型, 都自带一个 prototype 属性,指向原型对象(Function 除外)
    • 每个原型对象自带一个 constructor 属性,指向当前构造函数本身
    • 函数数据类型
      • 普通函数、箭头函数、生成器函数
      • 构造函数(自定义类)
      • 内置函数(内置构造函数)
  • proto 属性
    • 每一个对象数据类型,都自带一个 proto 属性(隐式原型)
    • 该属性的值指向所属类的原型对象 prototype
    • 对象数据类型
      • 普通对象,数组对象,正则对象,日期对象
      • prototype 原型对象
      • 实例对象
      • 函数本身也是对象
  • Object 类
    • 所有对象都是 Object 内置类的实例
    • Object 也是一个函数, 同样具有 prototype 属性,指向自己的原型对象
    • 它的原型也是一个对象, 因此具有 proto 属性
    • Object 原型对象的 proto 指向 Null (内部设计)

1.2.2 原型链查找机制

  1. 首先查找自己的私有属性,私有中如果存在则使用私有
  2. 私有中如果不存在,则默认基于 proto 找所属类的原型对象
  3. 如果原型对象上没有,则基于原型对象的 proto 继续向上查找,直到找到 Object.prototype 为止

1.2.3 示例代码

function Foo() {
  this.m = 10
  this.n = 24
  this.getM = function () {
    console.log(this.m)
  }
}
Foo.prototype.getM = function () {
  console.log(this.m)
}

Foo.prototype.getN = function () {
  console.log(this.n)
}

let foo1 = new Foo
let foo2 = new Foo
console.log(foo1.getM === foo2.getM)  
console.log(foo1.getN === foo2.getN)
console.log(foo1.__proto__.getN === Foo.prototype.getN)  
console.log(foo1.__proto__.getM === foo2.getM) 
console.log(foo1.getM === Foo.prototype.getM) 
console.log(foo1.constructor) 
console.log(Foo.prototype.__proto__.constructor) 
foo1.getM()  
foo1.__proto__.getM() 
foo2.getN()  
Foo.prototype.getN() 

1.3 重写 new 方法

1.3.1 new 做了什么

  1. 创建实例对象
  2. 执行构造函数, 将 this 指向实例对象
  3. 处理返回值

1.3.2 模拟 new 实现

function Person(name) {
  this.name = name
}
Person.prototype.slogan = function () {
  console.log('前端开发')
}
Person.prototype.sayName = function () {
  console.log(`我们的名称是${this.name}`)
}
//* 原生的写法
// let p1 = new Person('syy')
// p1.slogan()
// p1.sayName()

function _new(Ctor, ...params) {
  //01 创建实例对象
  // let obj = {}
  // obj.__proto__ = Ctor.prototype
  let obj = Object.create(Ctor.prototype)

  // 02 调用构造函数, 改变this 指向
  let ret = Ctor.call(obj, ...params)

  // 03 处理返回结果
  if (ret !== null && /^(object|function)$/.test(typeof ret)) return ret
  return obj
}

let p2 = _new(Person, 'abc')
p2.slogan()
p2.sayName()
console.log(p2 instanceof Person)

1.4 Function 与 Object

Function 与 Object

1.4.1 函数多种角色

  1. 函数
    1. 普通函数调用(堆栈执行及作用域)
    2. 构造函数实例(原型及原型链)
  2. 对象
    1. 键值对
  3. 三种角色之间没有必然的联系,但是最核心的理念是函数就是函数,函数是一等公民

1.4.2 经典语录

  1. Function 是一等公民,在 JS 中存在多种角色,普通函数, 构造函数,对象
  2. 每一个对象都存在 --proto-- 属性, 指向所属类的原型对象(隐式原型,原型链属性)
  3. 每一个函数都存在 prototype 属性, 指向它的原型对象
  4. 所有函数都是 Function 内置类的实例,且 Function 本身也是一个函数
  5. 所有对象都是 Object 的实例,且 Object 本身也是一个函数
  6. Function 与 Object 是二大并行的基类,虽然最终查找落脚点都是 Object 身上
  7. Function.prototype 原型对象是一个匿名函数,但虽然它是一个函数,它的处理机制和原型对象是一样的,它的 --proto-- 属性指向所属类的原型对象,也就是 Object.prototype

1.4.3 无 prototype 属性

  1. Function.prototype 原型是一个匿名函数,但是它没有 prototype 属性
  2. 对象中使用 ES6 语法定义函数 const obj = {say(){}} , say方法不具备
  3. 箭头函数
  4. 不具备 prototype 属性的函数是不能执行 new 操作的

1.5 This 规律

在浏览器平台下运行 JS , 非函数当中的 this 一般都指向 window 
因此这里讨论的是函数执行过程中的 this 
需要注意:ES6+ 的箭头函数中是没有自己 this 的,处理机制就是使用上下文当中的 this 

1.5.1 this 是什么

  1. this 就是当前函数执行的主体(谁执行了函数), 不等于执行上下文或者当前作用域
  2. syy 在拉勾教育讲前端
    1. 讲前端是一个动作(函数)
    2. 拉勾教育(执行上下文)
    3. syy 主体,本次函数在当前执行上下文中执行的 this 指向

1.5.2 常见 this 场景

  1. 事件绑定
  2. 普通函数
  3. 构造函数
  4. 箭头函数
  5. 基于 call bind apply 强制改变 this 指向

1.5.3 规律

  1. 事件绑定
    1. 不论是 DOM2 还是 DOM0 级事件绑定,事件触发时 this 一般都是被操作的元素
  2. 普通函数
    1. 函数执行时查看前端是否有点,如果有点,则点前面的就是执行主体, 没有点就是 window , 严格模式下是 undefined
    2. 特殊情况
      1. 匿名函数中的 this 是 window 或者 undefined
      2. 回调函数中的 this 一般也是 window 或者 undefined
      3. 小括号语法
        1. 如果小括号只有一项,则相当于没加
        2. 如果小括号当中有多项,则取出最后一项,此时相当于拷贝函数,所以调用时主体是 window

1.5.4 练习

(function () {
  console.log(this)
})()

let arr = [1, 3, 5, 7]
obj = {
  name: '拉勾教育'
}
arr.map(function (item, index) {
  console.log(this)
}, obj)
------------------------------------------------------
//? 普通函数调用
let obj = {
  fn: function () {
    console.log(this, 111)
  }
}
let fn = obj.fn;
fn()  // window
obj.fn();  // obj
(10, fn, obj.fn)();
------------------------------------------------------
var a = 3, 
  obj = { a: 5 }
obj.fn = (function () { 
  this.a *= ++a
  return function (b) {
    this.a *= (++a) + b
    console.log(a)
  }
})();
var fn = obj.fn  
obj.fn(6)
fn(4)
console.log(obj.a, a)

二、异步编程与事件环

2.1 名词说明

2.1.1 进程与线程

  1. 进程可以看做是一个应用程序(例如打开浏览器或者浏览器打开一个界面)
  2. 线程是程序当中具体做事情的人, 每个线程同一时刻只能做一件事情
  3. 一个进程当中可以包含多个线程

2.1.2 同步与异步

  1. 同步编程:一件一件的做事情,上一件没有做完,下一件事情不会被处理(单线程)
  2. 异步编程:上一件事情没有处理完,可以直接处理下一件事情(多线程)
  3. JS 基于单线程的 EventLoop 机制也可以实现异步编程

2.1.3 JS 中异步操作

  1. promise(then)
  2. aync await (generator)
  3. requestAnimationFrame
  4. 定时器操作
  5. ajax 网络请求
  6. 事件绑定

2.1.4 JS 单线程

浏览器平台下的 JS 代码是由 JS 引擎执行的, 所以它是单线程的

浏览器是多线程: GUI 渲染线程、JS引擎线程、事件触发线程、定时器触发线程、异步 http请求线程

  1. JS 中大部分代码都是同步编程
  2. JS 可以基于单线程的 EventLoop (事件循环机制) 实现出异步效果

2.2 EventLoop 模型

事件循环模型图

2.2.1 代码执行顺序

  1. 浏览器加载界面之后会开启一个线程来执行 JS,称之叫 JS引擎(主线程)
  2. JS引擎会自上而下的执行 JS 代码,此过程会遇到(定时器,网络请求,事件绑定,promise....)
  3. 遇到上述代码执行之后,浏览器会开启一个 Event Queue(任务|事件)队列 优先级队列结构
  4. 在队列当中存在二个任务队列:微任务 microtask | 宏任务 macrotask
  5. 最终会将遇到的异步任务存放到 Event Queue 队列当中(未执行)
  6. 主线程会继续向下执行同步代码,直到所有同步执行完就会处理异步任务
  7. 进入 Event Queue 当中查找异步任务,找到之后放入主线程中执行(此时主线程又被占用)
  8. 执行完一个异步任务之后,主线程再次空闲,此时再进入 Event Queue 查找余下的异步任务

2.2.2 异步任务执行顺序

  1. 先执行微任务(只要有微任务就不会处理宏任务)
  2. 微任务(一般是谁先放置谁先执行)
  3. 宏任务(一般是谁先到达的谁先执行)

2.2.3 整体顺序

  1. 同步任务
  2. 异步微任务
  3. 异步宏任务
- 如果同步任务执行过程中遇到可执行的异步任务,此时依然需要等到同步任务执行完
- 如果同步任务执行完,还没有可执行的异步任务,此时也只能等待 
- 不论何时放入的微任务,只要异步微任务存在,就永远不会执行异步宏任务

2.2.4 setTimeout

  1. 设置定时器这个操作是同步的
  2. 放置在 Event Queue 中的任务是异步宏任务
  3. 函数调用返回数字,表示当前是第几个定时器
  4. 等待时间设置为 0 时,也不是立即执行,浏览器存在最快的反应时间
  5. 定时器的等待时间到了之后,它的代码可能还不会执行(处于异步队列中,同步任务还未完成执行)

2.2.5 练习

setTimeout(() => {
  console.log('1')
}, 30)

console.log(2)

setTimeout(() => {
  console.log(3)
}, 20)

console.log(4)

console.time('AA')
// 消耗95ms
for (let i = 0; i < 88888888; i++) { }
console.timeEnd('AA')

console.log(5)

setTimeout(() => {
  console.log(6)
}, 18)

console.log(7)

setTimeout(() => {
  console.log(8)
}, 25)

console.log(9)
async function async1() {
  console.log('async1 执行了')
  await async2()
  console.log('async1 结束了')
}

async function async2() {
  console.log('async2')
}

console.log('同步代码执行了')

setTimeout(() => {
  console.log('setTimeout')
}, 0)

async1()

new Promise((resolve) => {
  console.log('promise1')
  resolve()
}).then(() => {
  console.log('promise2')
})

console.log('同步代码结束了')
function fn1() {
  console.log('fn1 start')
  return new Promise((resolve) => {
    resolve('zcegg1')
  })
}
function fn2() {
  console.log('fn2 start')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('zcegg2')
    }, 10)
  })
}
console.log('a')
setTimeout(async () => {
  console.log('b')
  await fn1()
  console.log('c')
}, 20)
for (let i = 0; i < 88888888; i++) { }  // 90ms  
console.log('d')
fn1().then((result) => {
  console.log('f')
})
fn2().then((result) => {
  console.log('g')
})
setTimeout(() => {
  console.log('h')
}, 0)
console.log('end')

相关文章

  • 面向对象及事件循环

    一、面向对象 1.1 普通函数与构造函数 函数还是之前的函数,唯一的区别就是首字母大写 1.1.1 普通函数 正常...

  • 面向对象及事件循环

    一、面向对象 1.1 普通函数与构造函数 函数还是之前的函数,唯一的区别就是首字母大写 1.1.1 普通函数 正常...

  • iOS基础面试题(基础概念篇)

    人在面试途中,都是套路啊!!!。 本文包括: OC的面向对象 运行时Runtime 运行循环RunLoop 事件响...

  • 构造函数及jQuery基础

    闭包存循环索引 面向对象 单体创建对象 工厂模式 构造函数 继承 jQuery部分选择器 增删样式 点击事件 获取索引值

  • TypeScript面向对象

    面向对象 面向对象:想进行执行某个事件,就去找事件对应的对象,把事情落实到对象身上 在程序中一切皆是对象,对象包含...

  • lesson 5 面向对象及原型链 2021-04-29

    课程标题 面向对象及原型链 课程目标 面向对象思想 原型及原型链 继承 知识点 面向对象思想 原型链的指向 new...

  • Objective-C

    OC的面向对象 运行时Runtime 运行循环RunLoop 事件响应链 引用计数 生命周期 与其他语言的区别 O...

  • Python--类和对象学习

    一、面向对象编程概述 1、面向对象编程(OOP) 面向对象:以具体的事物(对象)为单位,考虑它的属性(特征)及动作...

  • JavaScript 设计模式

    面向对象 为什么使用面向对象 程序的执行是结构化的,顺序、判断、循环构成程序 面向对象让数据结构化 对于计算机,结...

  • 面向对象中,包和类的设计原则

    什么是面向对象技术 面向对象技术是一种以对象为基础,以事件或消息来驱动对象执行处理的程序设计技术 面向对象有哪些特...

网友评论

      本文标题:面向对象及事件循环

      本文链接:https://www.haomeiwen.com/subject/qgqbwltx.html