JS面试真题 part3

news2024/11/25 21:20:33

JS面试真题 part3

  • 11、bind、call、apply区别?如何实现一个bind
  • 12、JavaScript中执行上下文和执行栈是什么
  • 13、说说JavaScript中的事件模型
  • 14、解释下什么是事件代理?应用场景?
  • 15、说说你对闭包的理解?闭包使用场景

11、bind、call、apply区别?如何实现一个bind

自己回答:
相同点:都是改变函数的this指向,函数接收的第一个参数都是要指向的对象。
不同点:函数有没有执行以及参数传递的方式不同
bind函数并没有执行。
call和apply函数执行了。
call的参数第一个是要指向的对象,后面是参数列表
apply的参数第一个是要指向的对象,第二个是数组,数组里是参数列表
bind的参数第一个是要指向的对象,后面是参数列表,可以分次传。

bind实现:

 Function.prototype.bindFunc=function(obj,...agament){
			let that=this
			return function(...agament2){
				let agamentAll=[...agament,...agament2]
				let func=that.apply(obj,agamentAll)
			   return func
		}
}

验证:

function getName(age,sex){
		   console.log(this.name,age,sex)
		   return {
			   name:this.name,
			   age:age,
			   sex:sex
		   }
		}
		let obj={
		   name:'张三'
		}
		let newFunc=getName.bindFunc(obj,'18')
		let aa =newFunc('女')
		console.log('aa',aa)

在这里插入图片描述
标准回答:
callapplybind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向

  • 三者都可以改变函数的this对象指向
  • 三者第一个参数都是this要指向的对象,如果没有这个参数或参数为undefinednull,则默认指向全局window
  • 三者都可以传参,但是apply是数组,而call是参数列表,且applycall是一次性传入参数,而bind可以分多次传入
  • bind是返回绑定this之后的函数,applycall则是立即执行

实现:
分为三步

  • 修改this指向
  • 动态传递参数
  • 兼容new关键字
    自己回答实现里的少了兼容new关键字,如果我们对bind返回的函数使用new会发生什么呢
 function Person(name, age) {
 this.name = name;
 this.age = age;
}

const BoundPerson = Person.bind(null, '前端西瓜哥');
const boundPerson = new BoundPerson(100);
// Person {name: '前端西瓜哥', age: 100}

boundPerson.__proto__ === Person.prototype
// true

等价于直接new原来的Person函数,依然可以进行参数分次传递
修改后

 Function.prototype.bindFunc=function(obj,...agament){
 			let that=this	
 			return function Fn(...agament2){
 				let agamentAll=[...agament,...agament2]
				let func=this instanceof Fn?new that(...agamentAll):that.apply(obj,agamentAll);
 			   return func
 		  }
     }

12、JavaScript中执行上下文和执行栈是什么

自己回答:
JavaScript中执行上下文:当前变量或函数的生效范围和集合
执行栈:全局执行上下文和函数执行上下文的执行顺序

标准回答:
定义:执行上下文是一种对js代码执行环境的抽象概念,只要有JavaScript代码运行,那么它就一定是运行在执行上下文中。

执行上下文包含了三个重要的组成部分:变量对象作用域链this值

执行上下文的类型分为三种:

  • 全局执行上下文:只有一个,浏览器的全局对象就是window对象,this指向这个全局对象
  • 函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
  • Eval函数执行上下文:指的是运行在eval函数中的代码,很少用而且不建议使用

执行上下文的生命周期包括三个阶段:创建阶段->执行阶段->回收阶段
在这里插入图片描述

创建阶段

  • 生成变量对象
    • 创建arguments:如果是函数上下文,首先会创建 arguments 对象,给变量对象添加形参名称和值。
    • 扫描函数声明:对于找到的函数声明,将函数名和函数引用(指针)存入 VO 中,如果 VO 中已经有同名函数,那么就进行覆盖(重写引用指针)。
    • 扫描变量声明:对于找到的每个变量声明,将变量名存入 VO 中,并且将变量的值初始化为undefined 。如果变量的名字已经在变量对象里存在,不会进行任何操作并继续扫描。
  • 建立作用域链:在执行期上下文的创建阶段,作用域链是在变量对象之后创建的。作用域链本身包含变量对象。
  • 确定this的指向:如果当前函数被作为对象方法调用使用 bind、call、apply 等 API 进行委托调用,则将当前代码块的调用者信息(this value)存入当前执行上下文,否则默认为全局对象调用

let和const定义的变量在创建阶段没有被赋值,var声明的变量在创建阶段被赋值为undefined。创建阶段,扫描函数声明和变量,然后将函数声明存储在环境中,变量初始化为undefined(var声明时)

函数提升优先级高于变量提升,且不会被同名变量声明覆盖,但是会被变量赋值后覆盖。而且存在同名函数与同名变量时,优先执行函数。

执行阶段

执行阶段 中,执行流进入函数并且在上下文中运行/解释代码,JS引擎开始对定义的变量赋值、开始顺着作用域链访问变量、如果内部有函数调用就创建一个新的执行上下文压入执行栈并把控制权交出

  • 变量赋值:如果找不到变量的值,将会为其分配undefined
  • 函数的引用
  • 执行其他代码

回收阶段

  • 执行上下文等待虚拟机回收执行上下文

执行上下文栈:

执行栈,也叫调用栈,具有LIFO(后进先出)结构,用于存储在代码执行期间创建的所有上下文。

顺序如下:

  1. 在全局代码执行前, JS引擎就会创建一个来存储管理所有的执行上下文对象
  2. 在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
  3. 在函数执行上下文创建后, 将其添加到栈中(压栈)
  4. 在当前函数执行完后,将栈顶的对象移除(出栈)
  5. 当所有的代码执行完后, 栈中只剩下window

举例:在这里插入图片描述
在这里插入图片描述

13、说说JavaScript中的事件模型

自己回答:
事件模型?
忘了概念,复习浏览器事件详解
标准回答:
事件模型之前先阐述一下,事件与事件流
1、事件与事件流
事件:在html文档或者浏览器中发生的一种交互操作,使得网页具有互动性,常见的有加载事件、鼠标事件、自定义事件等。
由于dom是数结构,父子节点都绑定事件,存在一个顺序问题,这就涉及到了事件流
事件流都会经历三个阶段:
-事件捕获阶段:从上往下传递

  • 处于目标阶段
  • 事件冒泡阶段:从下往上传播
    在这里插入图片描述
    事件模型包括:
  • 原始事件模型(DOM0级)
  • 标准事件模型(DOM2级)
  • IE事件模型(基本不用)

原始事件模型:
DOM0级事件具有很有的跨游览器优势,会以最快的速度绑定,但是由于绑定速度太快,可能页面还没加载完全

  • 只支持冒泡,不支持捕获
  • 同一种类型的事件只能绑定一次
    在这里插入图片描述
    标准事件模型:
    一共三个阶段:事件捕获、事件处理、事件冒泡

事件绑定监听函数如下:

addEventListener(eventTpye,hander,useCapture)

事件移除监听函数如下:

removeEventListener(eventTpye,hander,useCapture)
  • eventTpye指定事件类型(不要加on)
  • hander是事件处理函数
  • useCapture是一个boolean用于指定是否在捕获阶段进行处理,一般设置为false与ie浏览器保持一致

特性:

  • 可以在一个DOM元素上绑定多个事件处理器,各自并不会冲突
  • 执行时机,与useCapture设置有关

IE事件模型:
一共俩个阶段:事件处理、事件冒泡(没有事件捕获)

事件绑定监听函数如下:

attachEvent(eventTpye,hander)

事件移除监听函数如下:

attachEvent(eventTpye,hander)

14、解释下什么是事件代理?应用场景?

自己回答:
事件代理,由父级绑定事件,通过子节点id触发对应子节点的事件,避免多次绑定事件,也避免新增的子节点漏掉绑定事件
应用场景:li节点事件监听,在父级ul或div上绑定监听事件

标准回答:
事件代理,就是把一个元素响应事件(click、keydown…)的函数委托到另一个元素
事件流会经过三个阶段:捕获->目标->冒泡阶段,事件委托就是在冒泡阶段完成
事件委托,会把一个或者一组元素的事件委托到它的父层或者更外的元素上,真正绑定事件的是外层元素,而不是目标元素
当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
应用场景:
如果有个列表,列表中有大量的列表项,点击列表项响应一个事件。如果给每个列表项都绑定一个函数的话,那么对内存的消耗是非常大的,如果用户还能动态增加或删除列表元素,那每次改变的时候都需要给增加的元素绑定事件,给删除的元素解除事件。这时候就可以事件委托,把事件绑定在父级元素ul上面,然后执行事件时候再匹配目标元素,和目标元素的增减也没有关系。
如:

<input type="button" name="" id="btn" value=" " />
<ul id="ul1">
 <li>item 1</li>
 <li>item 2</li>
 <li>item 3</li>
 <li>item 4</li>
</ul>

使用事件委托

const oBtn = document.getElementById("btn");
const oUl = document.getElementById("ul1");
const num = 4;
//
oUl.onclick = function (ev) {
 ev = ev || window.event;
 const target = ev.target || ev.srcElement;
 if (target.nodeName.toLowerCase() == 'li') {
 console.log('the content is: ', target.innerHTML);
 }
};
//
oBtn.onclick = function () {
 num++;
 const oLi = document.createElement('li');
 oLi.innerHTML = `item ${num}`;
 oUl.appendChild(oLi);
};

总结:
适合事件委托的事件有:click、mousedown、mouseup、keydown、keyup、keypress

15、说说你对闭包的理解?闭包使用场景

自己回答:
函数内部访问外部的变量,形成闭包
使用场景:var定义变量的for循环,内部使用异步,如定时器内访问变量,用闭包进行传递,可以 让for循环的变量传参正确

标准回答:
一个函数和对其周围状态的引用绑定在一起,这样的组合就是闭包
闭包让你可以在一个内层函数中访问到其外层函数的作用域
使用场景:
任何闭包的使用场景都离不开这两点:

  • 创建私有变量
  • 延长变量的生命周期

一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的

1、在页面上添加一些可以调整字号的按钮

 function makeSizer(size) {
 return function() {
 document.body.style.fontSize = size + 'px';
 };
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

2、柯里化函数
柯里化的目的在于避免频繁调用具有相同参数函数的同时,又能轻松的重用

// 
function getArea(width, height) {
 return width * height
}
// 10
const area1 = getArea(10, 20)
const area2 = getArea(10, 30)
const area3 = getArea(10, 40)
// 
function getArea(width) {
 return height => {
 return width * height
 }
}
const getTenWidthArea = getArea(10)
// 10
const area1 = getTenWidthArea(20)
// 
const getTwentyWidthArea = getArea(20)

3、用闭包模拟私有方法
javaScript中,没有支持声明私有变量,但我们可以使用闭包来模拟私有方法

var Counter = (function() {
 var privateCounter = 0;
 function changeBy(val) {
 privateCounter += val;
 }
 return {
 increment: function() {
 changeBy(1);
 },
 decrement: function() {
 changeBy(-1);
 },
 value: function() {
 return privateCounter;
 }
 }
})();
var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */

上述通过闭包来定义公共函数,并令其可以访问私有函数和变量,这种方式也叫模块方式
两个计数器 Counter1Counter2是维护它们各自的独立性的,每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境,不会影响另一个闭包的变量
4、例如计数器、延迟调用、回调等闭包的应用,核心思想是创建私有变量和延长变量的生命周期

注意事项
如果不是某些特定任务需要使用闭包,在其他函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响
例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。
原因在于每个对象的创建。方法都会被重新赋值

function MyObject(name, message) {
	 this.name = name.toString();
	 this.message = message.toString();
	 this.getName = function() {
	  return this.name;
	 };
	 this.getMessage = function() {
	   return this.message;
    };
}

上面的代码中,我们并没有利用到闭包的好处,因此可以避免使用闭包,修改如下:

function MyObject(name, message) {
	 this.name = name.toString();
	 this.message = message.toString();
}
MyObject.prototype.getName = function() {
	 return this.name;
};
MyObject.prototype.getMessage = function() {
	 return this.message;
};

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

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

相关文章

make 程序规定的 makefile 文件的书写语法

&#xff08;1&#xff09; 常用的 gcc 选项&#xff1a; &#xff08;2&#xff09; make 的作用&#xff1a; &#xff08;3&#xff09; 搭建 make 的实验环境 &#xff0c; linux 的很简单&#xff0c; windows 的复杂一点&#xff1a; windows 上 make 环境的搭建&#…

python爬虫基础:了解html

编辑器vscode <!DOCTYPE html> <html><head><title>第一个网页</title></head><body><h1>字体</h1><h2>字体</h2><h3>字体</h3><p>Lorem, ipsum dolor sit amet consectetur adipisicing…

电商平台如何实现自动监控订单签收状态,加快资金划拨进程?

资金划拨作为交易流程的核心环节之一&#xff0c;直接关系到商家资金回笼的速度、消费者购物体验的满意度以及平台自身的信誉与稳定性。 区别于自营电商&#xff0c;电商平台入驻了许多第三方商家&#xff0c;为了保障交易安全和控制风险&#xff0c;在交易未完成之前&#xff…

Java 入门指南:Java 并发编程 —— 同步工具类 Semephore(信号量)

文章目录 同步工具类Semephore核心功能限制并发访问量公平与非公平策略灵活性与适应性 常用方法使用示例 同步工具类 JUC&#xff08;Java.util.concurrent&#xff09;是 Java 提供的用于并发编程的工具类库&#xff0c;其中包含了一些通信工具类&#xff0c;用于在多个线程之…

Spring和MyBatis常见面试题总结

文章目录 1 Spring 基础1.1 说一下你对 Spring 的理解&#x1f525;1.2 Spring,Spring MVC,Spring Boot 之间什么关系?1.3 Spring 框架中用到了哪些设计模式&#xff1f;&#x1f525;1.4 说说自己对于 Spring MVC 了解?1.5 Spring MVC 的核心组件有哪些&#xff1f;1.6 Spri…

flutter开发实战-GoRouter路由go与push区别实践

flutter开发实战-GoRouter路由go与push区别实践 GoRouter是一个flutter的声明性路由包&#xff0c;使用路由器API提供一个方便的、基于url的API&#xff0c;用于在不同屏幕之间导航。可以定义URL模式、使用URL导航、处理深度链接以及许多其他与导航相关的场景。 之前使用了Go…

Vue3封装table表格右键菜单功能

1) 效果&#xff0c;右键单击单元格&#xff0c;打开菜单弹窗: 点击菜单选项&#xff0c;可选择只读/编辑&#xff0c;可在只读/编辑方法中&#xff0c;拿到该行列表格的数据&#xff0c;进行相关操作 2) 思路 1、右键菜单组件 出现的时机&#xff0c;是右键单击table表格row-…

移动安全需求分析与安全保护工程

移动应用安全威胁与需求分析 移动应用系统组成&#xff1a; 移动应用&#xff1a;简称App 通信网络&#xff1a;无线网络&#xff0c;移动通信网络及互联网 应用服务端&#xff1a;由相关服务器构成&#xff0c;负责处理来自App相关信息或数据 移动应用安全分析 Android系统…

【0基础】制作HTML网页小游戏——贪吃蛇(附详细解析)

我在昨天的文章&#xff08;贪吃蛇HTML源码&#xff09;里面分享了网页版贪吃蛇小游戏的源码&#xff0c;今天就来给大家详细讲解一下每部分代码是如何运作的&#xff0c;以及以后要如何美化贪吃蛇的UI界面&#xff0c;在哪里修改等。 目录 一、代码运作 1、HTML结构: 2、C…

数组的常用算法

数组是同类型数据的集合。便于整体处理数据&#xff0c;数组操作的主要算法有&#xff1a; 1求极值 2查找 3排序 2查找 cprimer plus第11.1节278--279页 4数组和指针的区别&#xff1a;数组表示法和指针表示法 数组表示法1 int a[4]{2,4,1,5}; for(int i0;i<4;i)cou…

JAVA 的excel数据批量导入解析 现在都用什么API工具 Apache POI 、EasyExcel 、easypoi有什么区别

&#x1f4dd;个人主页&#x1f339;&#xff1a;个人主页 ⏩收录专栏⏪&#xff1a;SpringBoot &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339;&#xff0c;让我们共同进步&#xff01; 在Java中&#xff0c;处理Excel数据批量导入解析时&#xff0c;常…

通讯录

在写一个程序前需要了解的知识&#xff0c;需要对通讯录的流程了如指掌&#xff0c;才能写出一个完整的程序 。 写一个主函数&#xff0c;里面包含菜单、对菜单的选择、以及循环。创建个人信息结构体&#xff0c;多人构成的结构体数组。分析每一个函数&#xff1a; 1).增加信…

webstorm修改主题色和配色常用插件(全部实用)包含主题、界面、开发效率等

Windows 用户打开setting 选择配色 更换主题看这里 效率插件 Rainbow Brackets 推荐理由&#xff1a;用各种鲜明的颜色显示括号&#xff0c;这样可以很容易分清楚括号配对问题。 Key promoter 推荐理由&#xff1a;只要是鼠标操作能够用快捷键替代的&#xff0c;Key Promoter…

若依漏洞综合利用工具

若依漏洞综合利用工具 安装与使用 该工具使用java开发&#xff0c;环境要求&#xff1a;JDK1.8版本 java -jar “文件名” 即可打开图形化界面。 注意查看"必看操作说明"模块。 1.首先下载好几个必要模块。 然后把openjfx-17.0.11_windows-x64_bin-sdk放在D盘根…

音视频入门基础:AAC专题(1)——AAC官方文档下载

一、AAC简介 高级音频编码&#xff08;英语&#xff1a;Advanced Audio Coding&#xff0c;AAC&#xff09;是有损音频压缩的专利数字音频编码标准&#xff0c;由Fraunhofer IIS、杜比实验室、贝尔实验室、Sony、Nokia等公司共同开发。出现于1997年&#xff0c;为一种基于MPEG…

【python因果推断库14】饮酒年龄 - 贝叶斯分析

目录 饮酒年龄 - 贝叶斯分析 主效应模型 交互模型 将连续变量以治疗阈值为中心 饮酒年龄 - 贝叶斯分析 这个例子使用了回归断点设计来探讨最低合法饮酒年龄&#xff08;在美国为21岁&#xff09;对全因死亡率的因果效应。数据集来自carpenter2009effect 的一项研究。 impo…

C语言蓝桥杯:语言基础

竞赛常用库函数 最值查询 min_element和max_element在vector(迭代器的使用) nth_element函数的使用 例题lanqiao OJ 497成绩分析 第一种用min_element和max_element函数的写法 第二种用min和max的写法 二分查找 二分查找只能对数组操作 binary_search函数&#xff0c;用于查找…

yolov8实现图片验证码识别

1、环境准备 1.1、安装miniconda 地址&#xff1a;Index of /anaconda/miniconda/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 注意&#xff1a;为避免不兼容的问题&#xff0c;推荐下载py38版本&#xff0c;我下载的是Miniconda3-py38_23.1.0-1-Windows-x86_…

【Java 类与对象】多态

空山新雨后 天气晚来秋 目录 多态的概念 多态实现条件 多态的转型 向上转型 向下转型 instanceof 关键字 方法的重写 Override注解 重写的权限 只能重写继承而来的方法&#xff08;1&#xff09; final、static 不能被重写&#xff08;2&#xff09; 重写的方法不能带有等级更严…

向量——通俗地解释

1. 向量 向量是一个既有大小(模)又有方向的对象&#xff0c;它可以用来描述空间中的位置、力或速度等量。我们可以从物理、数学和计算机的角度来看待向量&#xff0c;这三种观点看似不同却有关联。 &#xff08;1&#xff09;在物理专业视角下&#xff0c;向量是空间中的箭头&a…