高级前端面试中的三个 “送命题” !!!

news2025/2/28 12:12:14

原型与原型链

说到原型,就不得不提一下构造函数,首先我们看下面一个简单的例子:

function Dog(name,age){
    this.name = name;
    this.age = age;
}

let dog1 = new Dog("哈士奇",3);
let dog2 = new Dog("泰迪",2);

首先创造空的对象,再让 this 指向这个对象,通过 this.name 进行赋值,最终返回 this,这其实也是 new 一个对象的过程。

其实:

  • let obj = {}let obj = new Object() 的语法糖;
  • let arr = []let arr = new Array() 的语法糖;
  • function Dog(){...}let Dog = new Fucntion() 的语法糖。

那什么是原型那?

在 js 中,所有对象都是 Object 的实例,并继承 Object.prototype 的属性和方法,但是有一些是隐性的。

我们来看一下原型的规则:

var obj = {};
obj.attribute = "三座大山";
var arr = [];
arr.attribute = "三座大山";
function fn1 () {}
fn1.attribute = "三座大山";
  1. 所有的引用类型(包括数组,对象,函数)都有隐性原型属性( proto ), 值也是一个普通的对象。
console.log(obj.__proto__);
  1. 所有的函数,都有一个 prototype 属性,值也是一个普通的对象。
console.log(obj.prototype);
  1. 所有的引用类型的 proto 属性值都指向构造函数的 prototype 属性值。
console.log(obj.__proto__ === Object.prototype); // true
  1. 当试图获取对象属性时,如果对象本身没有这个属性,那就会去他的 proto(prototype)中去寻找。
function Dog(name){
   this.name = name;
}

Dog.prototype.callName = function (){
   console.log(this.name,"wang wang");
}

let dog1 = new Dog("Three Mountain");
dog1.printName = function (){
   console.log(this.name);
}

dog1.callName();  // Three Mountain wang wang
dog1.printName(); // Three Mountain

**原型链:**如下图。

在这里插入图片描述

我找一个属性,首先会在 f.proto 中去找,因为属性值为一个对象,那么就会去 f.proto.proto 去找,同理如果还没找到,就会一直向上去查找,直到结果为 null 为止。这个串起来的链即为原型链。

作用域及闭包

讲到作用域,你会想到什么?

当然是执行上下文

每个函数都有自己的 excution context,和 variable object。这些环境用于储存上下文中的变量函数声明参数等。只有函数才能制造作用域。

PS:for if else 不能创造作用域。

console.log(a) ; // undefined
var a = 1;
//可理解为
var a;
console.log(a);  // undefined
a = 1;

执行 console.log 时,a 只是被声明出来,并没有赋值;所以结果当然是 undefined

本质上来说,在 js 里 this 是一个指向函数执行环境的指针

this 永远指向最后调用它的对象,并且在执行时才能获取值,定义是无法确认他的值。

var a = {
    name : "A",
    fn : function (){
        console.log (this.name)
    }
}

a.fn() // this === a a 调用了fn() 所以此时this为a

a.fn.call ({name : "B"}) // this === {name : "B"} 使用call(),将this的值指定为{name:"B"}

var fn1 = a.fn

fn1() // this === window虽然指定fn1 = a.fn,但是调用是有window调用,所以this 为window

this 有多种使用场景,下面我会主要介绍 4 个使用场景:

  1. 作为构造函数执行
function  Student(name,age) {
    this.name = name  // this === s
    this.age = age    // this === s
    //return  this
}

var s = new Student("前端开发爱好者",30)

首先 new 字段会创建一个空的对象,然后调用 apply() 函数,将 this 指向这个空对象。这样的话,函数内部的 this 就会被空对象代替。

  1. 作为普通函数执行

    function  fn () {
        console.log (this)  // this === window
    }
    
    fn ()
    
  2. 作为对象属性执行

    var obj = {
        name : "A",
        printName : function () {
            console.log (this.name)  // this === obj
        }
    }
    
    obj.printName ()
    
  3. call(),apply(),bind() 三个函数可以修改 this 的指向,具体请往下看:

    var name = "小明" , age = "17"
    
    var obj = {
        name : "安妮",
        objAge : this.age,
        fun : function () {
                console.log ( this.name + "今年" + this.age )
            }
    }
    console.log(obj.objAge) // 17
    obj.fun() // 安妮今年undefined
    
    var name = "小明" , age = "17"
    var obj = {
        name : "安妮",
        objAge :this.age,
        fun : function (like,dislike) {
                  console.log (this.name + "今年" + this.age ,"喜欢吃" + like + "不喜欢吃" + dislike)
               }
        }
    
    var a = { name : "Jay", age : 23 }
    
    obj.fun.call(a,"苹果","香蕉") // Jay今年23 喜欢吃苹果不喜欢吃香蕉
    obj.fun.apply(a,["苹果","香蕉"]) // Jay今年23 喜欢吃苹果不喜欢吃香蕉
    obj.fun.bind(a,"苹果","香蕉")() // Jay今年23 喜欢吃苹果不喜欢吃香蕉
    

    首先 call,apply,bind 第一个参数都是 this 指向的对象,callapply 如果第一个参数指向 nullundefined 时,那么 this 会指向 windows 对象。

    call,apply 都是改变上下文中的 this,并且是立即执行的。

    bind 方法可以让对应的函数想什么时候调用就什么时候调用。

    闭包

    闭包的概念很抽象,看下面的例子你就会理解什么叫闭包了:

    function a(){
      var n = 0;
      this.fun = function () {
        n++;
        console.log(n);
      };
    }
    
    var c = new a();
    
    c.fun();  //1
    c.fun();  //2
    

    闭包就是能够读取其他函数内部变量的函数。

    在 js 中只有函数内部的子函数才能读取局部变量。

    所以可以简单的理解为:定义在内部函数的函数

    用途主要有两个:

    • 前面提到的,读取函数内部的变量。
    • 让变量值始终保持在内存中

    异步和单线程

    我们先感受下异步。

    console.log("start");
    setTimeout(function () {
        console.log("medium");
    }, 1000);
    console.log("end");
    

    使用异步后,打印的顺序为 start->end->medium 。因为没有阻塞。

    为什么会产生异步呢?

    首先因为 js 为单线程,也就是说 CPU 同一时间只能处理一个事务。得按顺序,一个一个处理。

    如上例所示,

    • 第一步:执行第一行打印 “start”;
    • 第二步:执行 setTimeout,将其中的函数分存起来,等待时间结束后执行;
    • 第三步:执行最后一行,打印 “end”;
    • 第四部:处于空闲状态,查看暂存中,是否有可执行的函数;
    • 第五步:执行分存函数。

    为什么 js 引擎是单线程?

    js 的主要用途是与用户互动,以及操作 DOM,这决定它只能是单线程。

    例:一个线程要添加 DOM 节点,一个线程要删减 DOM 节点,容易造成分歧

    为了更好使用多 CPU,H5 提供了 web Worker 标准,允许 js 创建多线程,但是子线程受到主线程控制,而且不得操作 DOM。

    任务列队

    单线程就意味着,所有的任务都要排队,前一个结束,才会执行后面的任务。

    如果列队是因为计算量大,CPU 忙不过来,倒也算了。

    但是更多的时候,CPU 是闲置的,因为 IO 设备处理得很慢,例如 ajax 读取网络数据。

    js 设计者便想到,主线程完全可以不管 IO 设备,将其挂起,然后执行后面的任务。

    等后面的任务结束掉,在反过头来处理挂起的任务。

    好,我们来梳理一下:

    • 所有的同步任务都在主线程上执行,形成一个执行栈。
    • 除了主线程之外,还存在一个任务列队,只要任务有了运行结果,就在任务列队中植入一个时间。
    • 主线程完成所有任务,就会读取队列任务,并将其执行。
    • 重复上面三步。
    • 只要主线程空了,就会读取任务列队,这就是 js 的运行机制,也被称为 event loop(事件循环)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1278212.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go GORM简介

GORM(Go Object-Relational Mapping)是一个用于Go语言的ORM库,它提供了一种简单、优雅的方式来操作数据库。GORM支持多种数据库,包括MySQL、PostgreSQL、SQLite和SQL Server。以下是GORM的一些主要特性 全功能ORM:GORM…

leetCode 47. 全排列 II + 回溯算法 + 图解 + 笔记

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列 示例 1: 输入:nums [1,1,2] 输出: [[1,1,2],[1,2,1],[2,1,1]] 示例 2: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2…

uniapp 微信小程序连接蓝牙卡死

解决方法,需要同意隐私保护协议,否则不能开启蓝牙权限和定位权限,会导致定位失败

.NET8构建统计Extreme Optimization Numerical Libraries

为 .NET 8 构建统计应用程序 Extreme Optimization Numerical Libraries for .NET V8.1.22 添加了对 .NET 8 的支持,使您可以使用最新版本的 Microsoft 平台。 Extreme Optimization Numerical Libraries for .NET 是通用数学和统计类的集合,为技术和统计…

基于 Python+flask 构建态势感知系统(附完整源码)

一、开发 一个基于linux的态势感知系统,基于python和flask框架开发,项目文件目录如下: admin -核心算法 charts -图表生成 model -类 app.py -主文件 config.py -配置文件 install.py -安装文件 二、安装 1、配置 数据库密码默认设…

进程的创建:fork()

引入 创建进程的方式我们已经学习了一个!在我们运行指令(或者运行我们自己写的可执行程序)的时候不就是创建了一个进程嘛?那个创建进程的方式称为指令级别的创建子进程! 那如果我们想要在代码中创建进程该怎么办呢? fork() for…

SSM框架(五):Maven进阶

文章目录 一、分模块开发1.1 分模块开发的意义1.2 步骤 二、依赖管理2.1 依赖传递2.2 可选依赖和排除依赖 三、继承与聚合3.1 聚合3.2 继承3.3 聚合和继承区别 四、属性4.1 pom文件的依赖使用属性4.2 资源文件使用属性 五、多环境开发六、跳过测试七、私服7.1 下载与使用7.2 私…

禁止谷歌浏览器自动更新

禁止谷歌浏览器自动更新 在使用Python包selenium的时候浏览器版版本发生变化后产生很多问题如: 1、直接版本不对应无法运行 2、版本不一致导致debug启动浏览器超级慢 这里是已谷歌浏览器为代表的。 禁止自动更新的方法如下: 1、WinR调出运行&#x…

一小时玩转【负载均衡】

😄作者简介: 小曾同学.com,一个致力于测试开发的博主⛽️,主要职责:测试开发、CI/CD 如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步。 😊 座右铭:不…

SpringBoot 是如何启动一个内置的Tomcat

为什么说Spring Boot框架内置Tomcat 容器,Spring Boot框架又是怎么样去启动Tomcat的?我简单总结下学习过程。 一:简单了解SpringBoot的启动类 我们都知道Spring Boot框架的启动类上是需要使用 @SpringBootApplication 注解标注的, @SpringBootApplication 是一个复合注解…

Redis--10--Pipeline

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 Pipeline举例比较普通模式与 PipeLine 模式小结: Pipeline 前面我们已经说过,Redis客户端执行一条命令分为如下4个部分:1)发送命…

前端入门(五)Vue3组合式API特性

文章目录 Vue3简介创建Vue3工程使用vite创建vue-cli方式 常用 Composition API启动项 - setup()setup的执行时机与参数 响应式原理vue2中的响应式vue3中的响应式ref函数reactive函数reactive与ref对比 计算属性 - computed监视属性 - watchwatchEffect Vue3生命周期自定义hook函…

滑动平均窗口的定义,优点,缺点,以及目前的应用!!

文章目录 前言一、滑动平均窗口的优点二、滑动平均窗口的缺点三、滑动平均窗口的应用 前言 滑动平均窗口是一种数据处理方法,它以固定的窗口大小对数据进行移动,并在每个窗口内计算数据的平均值。这种方法主要用于平滑数据,减小数据波动的影…

基于SpringBoot的仓库管理系统设计与实现附带源码和论文

博主24h在线,想要源码文档部署视频直接私聊,全网最低价,9.9拿走! 【关键词】仓库管理系统,jsp编程技术,mysql数据库,SSM,Springboot 目 录 摘 要 Abstract 第1章 绪论 1.1 课题…

阿里云服务器跨区域迁移(多数据盘)

方法一. 复制镜像,共享镜像(只有系统盘没有数据盘的情况!) 正常阿里云同区域服务器迁移只需要选择共享镜像即可,但是由于新老服务器区域限制所以需要先复制到新服务器区域再进行共享 选择服务器实例先创建后复制 比如…

Linux 内核源码各版本下载

下载地址: kernel/git/stable/linux.git - Linux kernel stable treehttps://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/refs/ 1. Linux 内核的基本概念: 内核是什么? 内核是操作系统的核心部分,负责管理系统…

网络虚拟化场景下网络包的发送过程

网络虚拟化有和存储虚拟化类似的地方,例如,它们都是基于 virtio 的,因而在看网络虚拟化的过程中,会看到和存储虚拟化很像的数据结构和原理。但是,网络虚拟化也有自己的特殊性。例如,存储虚拟化是将宿主机上…

物流单管理系统软件物流单打印,物流单打印模板,佳易王物流快运单管理软件下载

物流单管理系统软件物流单打印,物流单打印模板,佳易王物流快运单管理软件下载 软件试用版下载或技术支持可以点击最下方官网卡片 上图:在物流开单时,可以先输入电话,如果之前存在该托运人信息,则可以一键…

hbase Master is initializing

问题如下: ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializing ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializingat org.apache.hadoop.hbase.master.HMaster.checkInitialized(HMaster.java:2452)at org.…

P1 什么是链表 C语言简单易懂

目录 前言 01 什么是链表 02 数组的特点 03 数组的缺点 3.1 删除数组其中一个元素 3.2 数组增加某个节点 04 链表 前言 🎬 个人主页:ChenPi 🐻推荐专栏1: 《 C 》✨✨✨ 🔥 推荐专栏2: 《 Linux C应用编程(概念…