• javascript高级(4)


    目录

    Object构造函数组成

    原型链继承

    面试题(闭包)

    进程(process)

    线程(thread)

    JS是单线程执行的

    浏览器的事件循环(轮询)模型

    H5 Web Workers(多线程)


    Object构造函数组成

    套路:先创建空Object对象,再动态添加属性/方法

    适用场景:起始时不确定对象内部数据

    问题:语句太多

    1. var p = new Object();
    2. p.name = "Tom";
    3. p.age = 12;
    4. p.setName = function (name) {
    5. this.name = name;
    6. };
    7. p.setName("jack");
    8. console.log(p.name, p.age);

    方式二:对象字面量模式

    套路:使用{}创建对象,同时指定属性/方法

    适用场景:起始时对象内部数据是确定的

    问题:如果创建多个对象,有重复代码

    1. var p = {
    2. name: "Tom",
    3. age: 12,
    4. setName: function (name) {
    5. this.name = name;
    6. },
    7. };
    8. // 测试
    9. console.log(p.name, p.age);
    10. p.setName("jack");
    11. console.log(p.name, p.age);

    方法三:工厂模式

    套路:通过工厂函数动态创建对象并返回

    适用场景:需要创建多个对象

    问题:对象没有一个具体的类型,都是object类型

    1. function createPerson(name,age){//返回一个对象的函数==>工厂函数
    2. var obj={
    3. name:name,
    4. age:age,
    5. setName:function(name){
    6. this.name=name
    7. }
    8. }
    9. return obj
    10. }
    11. var p1=createPerson('tom',12)
    12. var p2=createPerson('bob',13)

    方法四: 自定义构造函数模式

    套路:自定义构造函数,通过new创建对象

    适用场景:需要创建多个类型确定的对象

    问题:每个对象都有相同的数据,浪费内存

    1. function Person(name,age){
    2. this.name=name,
    3. this.age=age,
    4. this.setName=function(name){
    5. this.name=name
    6. }
    7. }
    8. var p1=new Person('tom',12)
    9. var p2=new Person('bob',13)
    10. function createStudent(name,age){
    11. this.name=name,
    12. this.age=age
    13. }
    14. var s=new createStudent('jack',15)

    方法五:构造函数+原型的组合模式

    套路:自定义构造函数,属性在函数中初始化,方法添加到原型上

    适用场景:需要创建多个类型确定的对象

    1. function Person(name,age){
    2. this.name=name,
    3. this.age=age
    4. }
    5. Person.prototype.setName=function(name){
    6. this.name=name
    7. }
    8. var p1=new Person('tom',12)
    9. var p2=new Person('bob',13)

    原型链继承

    1.套路

    1. 定义父类型构造函数
    2. 给父类型的原型添加方法
    3. 定义子类型的构造函数
    4. 创建父类型的对象赋值给子类型的原型
    5. 将子类型原型的构造属性设置为子类型
    6. 给子类型原型添加方法
    7. 创建子类型的对象:可以调用父类型的方法

    2.关键

    • 子类型的原型为父类型的一个实例对象
    1. function Supper(){
    2. this.supProp='Supper property'
    3. }
    4. Supper.prototype.showSupperProp=function(){
    5. console.log(this.supProp);
    6. }
    7. // 子类型
    8. function sub(){
    9. this.subProp='Sub property'
    10. }
    11. // 子类型的原型为父类型的一个实例对象
    12. Sub.prototype=new Supper()
    13. Sub.prototype.showSubProp=function(){
    14. console.log(this.subProp);
    15. }
    16. var sub=new Sub()
    17. sub.showSubProp()
    18. sub.toString()
    19. sub.showSubProp()

     方式2:借用构造函数继承(假的)

    1.套路

    1. 定义父类型构造函数
    2. 定义子类型构造函数
    3. 在子类型构造函数中调用父类型构造

    2.关键

    • 在子类构造函数中用call()调用父类型构造函数
    1. function Person(name,age){
    2. this.name=name
    3. this.age=age
    4. }
    5. function Student(name,age,price){
    6. Person.call(this,name,age)
    7. // 相当于this.Person(name,age)
    8. this.price=price;
    9. }
    10. var a=new Student('tom',20,14000)
    11. console.log(s.name,s.age,s.price);

    方式3:原型链+借用构造函数的组合继承

    • 利用原型链实现对父类型对象的方法继承
    • 利用call()借用父类型构建函数初始化相同属性
    1. function Person(name,age){
    2. this.name=name
    3. this.age=age
    4. }
    5. Person.prototype.setName=function(name){
    6. this.name=name
    7. }
    8. function Student(name,age,price){
    9. Person.call(this,name,age)//为了得到属性
    10. // 相当于this.Person(name,age)
    11. this.price=price;
    12. }
    13. Student.prototype.setprice=function(price){
    14. this.price=price
    15. }
    16. Student.prototype=new Person()
    17. Student.prototype.constructor=Student//修正contructor
    18. var s=new Student('tom',14,160000)
    19. s.setName('bob')
    20. s.setprice(19000)
    21. console.log(s.name,s.age,s.price);

    面试题(闭包)

    1. function fun(n,o){
    2. console.log(o);
    3. return{
    4. fun:function(m){
    5. return fun(m,n)
    6. }
    7. }
    8. }
    9. var a=fun(0)//undefined
    10. a.fun(1)//0
    11. a.fun(2)//0
    12. a.fun(3)//0
    13. var b=fun(0).fun(1).fun(2).fun(3)//undefined,0,1,2
    14. var c=fun(0).fun(1)//undefined,0
    15. c.fun(2)//1

    进程(process)

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

    线程(thread)

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

    图解

     相关知识:

    • 应用程序必须运行在某个进程的某个线程上
    • 一个进程中至少有一个运行的线程:主线程,进程启动后自动创建
    • 一个进程中也可以同时运行多个线程,我们会说程序是多线程运行的
    • 一个进程内的数据可以供其中多个线程直接共享
    • 多个进程之间的数据是不能直接共享的
    • 线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用

    相关问题

    何为多进程与多线程?

    多进程运行:一应用程序可以同时启动多个实例运行

    多线程:在一个进程内,同时有多个线程运行

    比较单线程与多线程?

    多线程

    优点

    • 能有效提升CPU的利用率

    缺点

    • 创建多线程开销
    • 线程间切换开销
    • 死锁与状态同步问题

    单线程

    优点

    • 顺序简单易懂

    缺点

    • 效率低

    JS是单线程,但使用H5中的Web Workers可以多线程运行

    浏览器运行是多线程运行的

    浏览器是单进程还是多进程的?

    • 有的是单进程,firefox、老版IE;有的是多进程,chrome,新版IE

    浏览器内核

    1.支撑浏览器运行的最核心的程序

    2.不同的浏览器可能不一样

    3.内核由很多模块组成

    定时器引发的思考

    1.定时器是定时执行的吗?

    • 定时器并不能保证真正定时执行
    • 一般会延迟一丁点(可以接受),也可能延迟很长时间(不能接受)

    2.定时器回调函数是在分线程执行的吗?

    • 在主线程执行的,JS是单线程的

    3.定时器是如何实现的?

    • 事件循环模型(后面讲)
    1. window.onload = function () {
    2. document.getElementById("btn").onclick = function () {
    3. var start = new Date();
    4. // 同理
    5. // var start=Date.now()
    6. console.log("启动定时器前...");
    7. setTimeout(function () {
    8. console.log("定时器执行了", Date.now() - start);
    9. }, 1000);
    10. console.log("启动定时器后...");
    11. // 做一个长时间的工作
    12. for (let i = 0; i < 100000000; i++) {}
    13. };
    14. };

    JS是单线程执行的

    1.如何证明JS执行是单线程的?

    • setTime()的回调函数是在主线程执行的
    • 定时器回调函数只有在运行栈中的代码全部执行后才有可能执行

    2.为什么JS要用单线程模式,而不用多线程模式?

    • Javascript的单线程与他的用途有关
    • 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM
    • 这决定了它只能是单线程,否则会带来复杂的同步问题

    3.代码的分类

    • 初始化代码(同步代码):包含绑定DOM事件监听,设置定时器,发送ajax请求的代码
    • 回调代码(异步代码):处理回调函数

    4.JS引擎执行代码的基本流程

    1. 先执行初始化代码:包含一些特变的代码   回调函数(异步执行)
    2. 设置定时器
    3. 绑定事件监听
    4. 发送ajax请求

    后面在某个时刻才会执行回调函数

    1. setTimeout(function(){
    2. console.log('timeout 2');
    3. alert('2222')
    4. },2000)
    5. setTimeout(function(){
    6. console.log('timeout 1');
    7. alert('111')
    8. },1000)
    9. function fn(){
    10. console.log('fn()');
    11. }
    12. fn()
    13. console.log('alert()之前');
    14. alert('------')
    15. console.log('alert()之后');

    注意:函数提升 定时器按照时间执行

    浏览器的事件循环(轮询)模型

    运转流程

    • 执行初始化代码,将时间回调函数交给对应模块管理
    • 当事件发生时,管理模块会将回调函数及其数据添加到回调队列中
    • 只有当初始化代码执行完后(可能要一定时间),才会遍历读取回调队列中的回调函数执行

    模型原理图

                 JS(下面的框)

     相关知识

    H5 Web Workers(多线程)

     图解

     不足

    1. 不能跨域加载JS
    2. worker内代码不能访问DOM
    3. 不是每个浏览器都支持这个新特性
    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    7. <title>Documenttitle>
    8. <script>
    9. window.onload = function () {
    10. // console.log(f(7))
    11. var input = document.getElementById("number");
    12. var btn = document.getElementById("btn");
    13. btn.onclick = function () {
    14. var number = input.value;
    15. // 创建一个worker对象
    16. var worker = new Worker("worker.js");
    17. // 绑定接收消息的监听
    18. worker.onmessage = function (event) {
    19. console.log("主线程接受分线程返回的数据" + event.date);
    20. alert(event.data);
    21. };
    22. // 向分线程发送消息
    23. worker.postMessage(number);
    24. console.log("主线程向分线程发送数据:");
    25. };
    26. };
    27. script>
    28. head>
    29. <body>
    30. <input placeholder="数值" id="number" />
    31. <button id="btn">测试button>
    32. body>
    33. html>
    1. function f(n) {
    2. return n <= 2 ? 1 : f(n - 1) + f(n - 2);
    3. }
    4. var onmessage=function(event){
    5. var number=event.data
    6. console.log('分线程接收到主线程发送的数据'+number);
    7. // 计算
    8. var result=f(number)
    9. postMessage(result)
    10. console.log('分线程向主线程返回数据'+result);
    11. }
  • 相关阅读:
    指针笔试题讲解(让指针变得简单易懂)
    docker部署前后端分离项目
    docker-compose部署Nginx
    释放搜索潜力:基于Milvus快速搭建语义检索系统(快速版),让信息尽在掌握
    基于Echarts实现可视化数据大屏全国消费情况大数据科技感页面
    【图论】差分约束算法详解
    【学习】目标检测中的anchor
    【Go系列】 array、slice 和 map
    又是一年开学季,老学长告诉你弯道超车的法则
    JavaWeb总结:
  • 原文地址:https://blog.csdn.net/m0_62520946/article/details/126208697