js对象高级和线程机制(四)

122 阅读5分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

对象的创建模式

Object构造函数模式

  • 套路: 先创建空Object对象, 再动态添加属性/方法
  • 适用场景: 起始时不确定对象内部数据
  • 问题: 语句太多
var obj = {};
obj.name = 'Tom'
obj.setName = function(name){this.name=name}

对象字面量模式

  • 套路: 使用{}创建对象, 同时指定属性/方法
  • 适用场景: 起始时对象内部数据是确定的
  • 问题: 如果创建多个对象, 有重复代码
var obj = {
    name : 'Tom',
    setName : function(name){this.name = name}
}

工厂模式

  • 套路: 通过工厂函数动态创建对象并返回
  • 适用场景: 需要创建多个对象
  • 问题: 对象没有一个具体的类型, 都是Object类型
function createPerson(name, age) { //返回一个对象的函数===>工厂函数
  var obj = {
    name: name,
    age: age,
    setName: function (name) {
      this.name = name
    }
  }

  return obj
}

// 创建2个人
var p1 = createPerson('Tom', 12)
var p2 = createPerson('Bob', 13)

// p1/p2是Object类型

自定义构造函数模式

  • 套路: 自定义构造函数, 通过new创建对象
  • 适用场景: 需要创建多个类型确定的对象
  • 问题: 每个对象都有相同的数据, 浪费内存
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.setName = function(name){this.name=name;};
}
new Person('tom', 12);

构造函数+原型的组合模式

  • 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
  • 适用场景: 需要创建多个类型确定的对象
function Person(name, age) { //在构造函数中只初始化一般函数
  this.name = name
  this.age = age
}
Person.prototype.setName = function (name) {
  this.name = name
}

var p1 = new Person('Tom', 23)

继承模式

原型链继承 : 得到方法

  1. 套路
  • 定义父类型构造函数
  • 给父类型的原型添加方法
  • 定义子类型的构造函数
  • 创建父类型的对象赋值给子类型的原型
  • 将子类型原型的构造属性设置为子类型
  • 给子类型原型添加方法
  • 创建子类型的对象: 可以调用父类型的方法
  1. 关键
  • 子类型的原型为父类型的一个实例对象
//父类型
function Supper() {
  this.supProp = 'Supper property'
}
Supper.prototype.showSupperProp = function () {
  console.log(this.supProp)
}

//子类型
function Sub() {
  this.subProp = 'Sub property'
}

// 子类型的原型为父类型的一个实例对象
Sub.prototype = new Supper()
// 让子类型的原型的constructor指向子类型
Sub.prototype.constructor = Sub
Sub.prototype.showSubProp = function () {
  console.log(this.subProp)
}

var sub = new Sub()
sub.showSupperProp()
// sub.toString()
sub.showSubProp()

console.log(sub)  // Sub

借用构造函数继承 : 得到属性(假的)

  1. 套路:
  • 定义父类型构造函数
  • 定义子类型构造函数
  • 在子类型构造函数中调用父类型构造
  1. 关键:
  • 在子类型构造函数中通用call()调用父类型构造函数
function Parent(xxx){this.xxx = xxx}
Parent.prototype.test = function(){};
function Child(xxx,yyy){
  Parent.call(this, xxx);//借用构造函数   this.Parent(xxx)
}
var child = new Child('a', 'b');  //child.xxx为'a', 但child没有test()

原型链+借用构造函数的组合继承

  1. 利用原型链实现对父类型对象的方法继承
  2. 利用super()借用父类型构建函数初始化相同属性
function Parent(xxx){this.xxx = xxx}
Parent.prototype.test = function(){};
function Child(xxx,yyy){
  Parent.call(this, xxx);//借用构造函数   this.Parent(xxx)
}
Child.prototype = new Parent(); //得到test()
var child = new Child(); //child.xxx为'a', 也有test()

new一个对象背后做了些什么?

  • 创建一个空对象
  • 给对象设置__proto__, 值为构造函数对象的prototype属性值this.__proto__ = Fn.prototype
  • 执行构造函数体(给对象添加属性/方法)

线程与进程

进程:

  • 程序的一次执行, 它占有一片独有的内存空间
  • 可以通过windows任务管理器查看进程

线程:

  • 是进程内的一个独立执行单元
  • 是程序执行的一个完整流程
  • 是CPU的最小的调度单元

关系

  • 一个进程至少有一个线程(主)
  • 程序是在某个进程中的某个线程执行的

浏览器内核模块组成

主线程

  • js引擎模块 : 负责js程序的编译与运行
  • html,css文档解析模块 : 负责页面文本的解析
  • DOM/CSS模块 : 负责dom/css在内存中的相关处理
  • 布局和渲染模块 : 负责页面的布局和效果的绘制(内存中的对象)

分线程

  • 定时器模块 : 负责定时器的管理
  • DOM事件模块 : 负责事件的管理
  • 网络请求模块 : 负责Ajax请求

js线程

  • js是单线程执行的(回调函数也是在主线程)
  • H5提出了实现多线程的方案: Web Workers
  • 只能是主线程更新界面

定时器问题:

  • 定时器并不真正完全定时
  • 如果在主线程执行了一个长时间的操作, 可能导致延时才处理

事件处理机制

  • 代码分类
    • 初始化执行代码: 包含绑定dom事件监听, 设置定时器, 发送ajax请求的代码
    • 回调执行代码: 处理回调逻辑
  • js引擎执行代码的基本流程:
    • 初始化代码===>回调代码
  • 模型的2个重要组成部分:
    • 事件管理模块
    • 回调队列
  • 模型的运转流程
    • 执行初始化代码, 将事件回调函数交给对应模块管理
    • 当事件发生时, 管理模块会将回调函数及其数据添加到回调列队中
    • 只有当初始化代码执行完后(可能要一定时间), 才会遍历读取回调队列中的回调函数执行

H5 Web Workers

  • 可以让js在分线程执行
  • Worker
    var worker = new Worker('worker.js');
    worker.onMessage = function(event){event.data} : 用来接收另一个线程发送过来的数据的回调
    worker.postMessage(data1) : 向另一个线程发送数据
    
  • 问题:
    • worker内代码不能操作DOM更新UI
    • 不是每个浏览器都支持这个新特性
    • 不能跨域加载JS

最后

本文作为本人学习总结之用,同时分享给大家
因为个人技术有限,如果有发现错误或存在疑问之处,欢迎指出或指点!不胜感谢!