前端js面试题 (四)

news2025/1/21 2:53:21

文章目录

    • ES6新增的proxy
    • 手写,proxy访问某对象输出别的数字
    • 深度拷贝,为啥无法使用JSON.parse(JSON.stringify(obj))
    • 异步编程有哪些,async await来由,本质原理是什么
    • 事件队列输出题
      • 第一题
      • 第二题
      • 第三题
    • 粘性布局的原理,以及要自己实现应该怎么办
    • this指向题
    • `window.onload` 和 `jquery`的`$(document).ready()`的区别
    • 浏览器在渲染页面的时候到底做了些什么?

在这里插入图片描述

ES6新增的proxy

ES6引入了Proxy(代理)对象,它提供了一种拦截和自定义操作对象行为的机制。Proxy允许你在目标对象的基础上封装一个代理对象,通过定义各种拦截器来拦截对目标对象的访问和修改。

get(target, property, receiver): 拦截对目标对象属性的读取操作。
set(target, property, value, receiver): 拦截对目标对象属性的设置操作。
apply(target, thisArg, argumentsList): 拦截对目标对象的函数调用。
construct(target, argumentsList, newTarget): 拦截对目标对象的new操作符。

更多内容请参考
把es6 proxy 和 vue3.0的proxy一起学了

手写,proxy访问某对象输出别的数字

  const handler = {
    get: function (target, key) {
      return Math.random() * 10;
    },
  };

  const obj = {
    name: "dx",
    age: "18",
  };

 const p = new Proxy(obj, handler);

 console.log(p.name)

深度拷贝,为啥无法使用JSON.parse(JSON.stringify(obj))

因为转换过后,很多js的数据会发生变化,无法与原数据完全一致。

哪些js中的数据类型或者哪些场景下,JSON无法转化?

  1. new Date()
    转变后一个Date对象变成了时间字符串
 JSON.parse(JSON.stringify({a: new Date()})); // {a: '2023-11-11T07:13:19.302Z'}
  1. 对象中出现循环引用
// 循环引用
const jsonStr = '{ "key": {} }';
const obj = JSON.parse(jsonStr);
obj.key.circularReference = obj; // 循环引用
JSON.stringify(obj); // 在调用 JSON.stringify 时,会抛出 TypeError
  1. function
    转变后是一个空对象
JSON.parse(JSON.stringify({a: function(){}})); // {}
  1. undefined
    转变后是一个空对象
JSON.parse(JSON.stringify({a: undefined})); // {}
  1. NaN Infinity -Infinity
    转变后都会变为null
JSON.parse(JSON.stringify({a: NaN})); // {a: null}
  1. new RegExp()
    属性还在,但值变为空对象
JSON.parse(JSON.stringify({a: new RegExp('\\ww')})); // {a: {}}
  1. new Error()
    属性还在,但值变为空对象
JSON.parse(JSON.stringify({a: new Error('xxxx')})); // {a: {}}

所以,为了保证深度拷贝的万无一失,需要考虑各种情况,不是简单的JSON就能完成的,即使以上情况都没有,为了确保 JSON.parse() 不会失败,提供的 JSON 字符串应该是有效的、符合规范的,并且不包含不支持的数据类型。在处理可能导致异常的情况时,最好使用 try...catch 来捕获异常并进行相应的处理。

深度拷贝 leader:深拷贝有这5个段位,你只是青铜段位?还想涨薪?

异步编程有哪些,async await来由,本质原理是什么

异步编程的方式:回调函数,Promise,async await

async/await 的来由:
它的目标是简化和改善异步代码的可读性和可维护性,使开发者更容易理解和编写异步操作。

async/await 的本质原理:
async 函数: 使用 async 关键字声明的函数始终返回一个 Promise 对象。在 async 函数内部,通过 await 关键字等待异步操作的结果。当 await 后面的表达式解决时,函数将会从暂停的地方继续执行。

await 表达式: await 用于等待一个 Promise 解决,然后获取解决的值。在等待期间,async 函数会被暂停,允许其他代码执行。如果 Promise 解决为拒绝,await 将抛出一个异常,可以通过 try…catch 捕获。

async/await 的本质是基于 Promise,它提供了一种更直观的语法来编写异步代码,使得异步操作更容易理解和维护。在底层,async/await 仍然是依赖于 Promise 的实现。

promise成功时

async function fetchDataAsync() {
  const data = await new Promise((res,rej) => {res(1)});
  console.log(data); // 1
}
const a = fetchDataAsync()
console.log(a) // Promise {<fulfilled>: undefined} 一个promise对象,状态是 fulfilled

promise报错时

async function fetchDataAsync() {
  const data = await new Promise((res,rej) => {rej('出错了')});
  console.log(data); // Uncaught (in promise) 出错了
}
const a = fetchDataAsync()
console.log(a) // Promise {<pending>}  promise 对象,状态是rejected

如果await后根本就不是promise

async function fetchDataAsync() {
  const data = await console.log('不是promise');
  console.log(data); // undefined
}
const d = fetchDataAsync()
console.log(d) // Promise {<pending>} 一个promise对象,状态是 fulfilled

事件队列输出题

第一题

console.log('Start');

setTimeout(function() {
  console.log('Timeout');
}, 0);

Promise.resolve().then(function() {
  console.log('Promise');
});

new Promise((res,rej) => {
	console.log('Promise2')
	res(1)	
}).catch((e) => {
	console.log('出错了')
})

console.log('End');

Start 最先,
setTimeout属于宏任务,往宏任务队列里放,
Promise then里面的回调,属于微任务,往微任务队列里放,
Promise2是同步的,它第二,
res(1) 这儿是resolve了,所以catch不会执行,不用放到微任务队列里
End 第三
所有同步执行完了,开始执行异步,先将微任务队列全部执行(队列先进先出)。
Promise 第四
微任务队列执行完了,执行一个宏任务队列里的任务
Timeout 最后

第二题

async function asyncFunction() {
  console.log('Async Start');

  const promise = new Promise((resolve) => {
    setTimeout(() => {
      resolve('Async Timeout');
    }, 0);
  });

  const result = await promise;
  console.log(result);

  console.log('Async End');
}

console.log('Script Start');
asyncFunction();
console.log('Script End');

Script Start 第一,
asyncFunction执行函数体 Async Start第二,
setTimeout 放入宏任务队列,先不执行
遇到await ,不执行asyncFunction函数体await后的内容,跳出函数体
Script End 第三
同步执行完,开始执行异步,微任务队列全部执行,没有,执行一个宏任务
宏任务 resolve('Async Timeout')执行,result拿到了值,接着执行asyncFunction未执行完的函数体
Async Timeout 第四
Async End 第五

第三题

async function async1() {
	console.log('async1 start');
	await async2();
	console.log('asnyc1 end');
}
async function async2() {
	console.log('async2');
}
console.log('script start');
setTimeout(() => {
	console.log('setTimeOut');
}, 0);
async1();
new Promise(function (reslove) {
	console.log('promise1');
	reslove();
}).then(function () {
	console.log('promise2');
})
console.log('script end');

同步任务

// script start
// async1 start
// async2
// promise1
// script end

微任务

// asnyc1 end
// promise2

宏任务

// setTimeOut

粘性布局的原理,以及要自己实现应该怎么办

原理就是监听滚动条的变化,每一次滚动条变化后,就计算dom距离顶部或者底部的距离,如果距离小于我们设计的值,就让dom 的position改为fixed 或者absolute(当粘性布局不是对于window来说时)。
请参考Affix组件 vue3 组件篇 affix

this指向题

var name = 1
var obj = {
    name: 2,
    getName: function () {
        console.log(this.name)
    }
}
setTimeout(obj.getName, 0)

输出结果是什么? 1 怎么改才能是2

var name = 1
var obj = {
    name: 2,
    getName: function () {
        console.log(this.name)
    }
}
setTimeout(function(){ obj.getName() }, 0)

原题不改的情况下,严格模式会发生什么? // 会报错,严格模式,this在全局作用域中指向undefined。

JavaScript 的严格模式(strict mode)是一种在语言层面上的约束,它被设计用来提供更强的错误检测和更安全的代码。启用严格模式的方式是在脚本或函数的开头添加 'use strict';

以下是严格模式的一些主要特性:

  1. 变量声明必须使用 varletconst

    • 在严格模式下,未经声明直接赋值给变量会导致引发错误。
  2. 全局变量显式声明:

    • 在严格模式下,全局变量必须使用 var 关键字显式声明。
  3. 删除不可删除的属性时会引发错误:

    • 在严格模式下,尝试删除不可删除的属性会引发错误。
  4. 函数参数命名唯一性:

    • 在严格模式下,函数的参数不能有重复的名称。
  5. 禁止使用 with 语句:

    • 在严格模式下,使用 with 语句会导致引发错误。
  6. 禁止给只读属性赋值:

    • 在严格模式下,给只读属性(如 Math.PI)赋值会引发错误。
  7. 禁止删除变量:

    • 在严格模式下,使用 delete 操作符删除变量、函数或函数参数会引发错误。
  8. 保留字的限制:

    • 在严格模式下,一些在 ECMAScript 5 中被保留但没有特定用途的关键字变得不能用作变量名或函数名。
  9. this 在全局作用域中为 undefined

    • 在严格模式下,全局作用域中函数的 this 值为 undefined,而不是全局对象。
  10. 禁止使用 arguments.calleearguments.caller

    • 在严格模式下,arguments.calleearguments.caller 都会引发错误。
  11. eval 在其自己的词法作用域中运行:

    • 在严格模式下,eval 不再在调用时共享变量环境,它有自己的词法作用域。
  12. evalarguments 不能被重新赋值:

    • 在严格模式下,evalarguments 不能被重新赋值。
  13. 不允许给 evalarguments 传递字符串:

    • 在严格模式下,给 evalarguments 传递字符串会创建新的变量,而不是使用当前作用域中的变量。

使用严格模式有助于减少一些常见的编码错误,提高代码的可维护性和安全性。

window.onloadjquery$(document).ready()的区别

window.onload 浏览器所有的资源(图片,视频等多媒体文件)加载后触发load事件
$(document).ready() 是在dom解析完成后就触发。$(document).ready()window.onload 之前触发。

浏览器在渲染页面的时候到底做了些什么?

这里从建立tcp链接之后开始讲起,之前的过程中,浏览器经历了什么暂时不讨论,如果关心这一部分的同学,可以查阅一下,在浏览器输入url后,浏览器做了。

  1. 客户端向服务器请求下载index.html
  2. 下载完成后,解析index.html文件,从上至下。解析的同时,创建Document对象,没错就是平时用的document,比如document.createElement('div'), 解析HTML元素,和它们的文本内容,添加Element对象和Text节点到文档中, 这个阶段,document.readyState = 'loading',我们也称之为开始创建DomTree。
  3. 如果遇到link外部css,创建线程加载,我们称之为创建CssTree,与此同时继续解析文档。
  4. 遇到script外部js,并且没有设置asyncdefer,浏览器停止解析html,开始下载对应的js,下载完成后,执行js,等执行完成后,继续解析html。
  5. 遇到script外部js,设置了 async, 浏览器创建新的线程下载js,于此同时继续解析html,等js下载完成后,暂停html的解析,开始执行下载的js,js执行完成后,继续解析html。(异步禁止使用document.write() 这会清空之前解析的dom)。
  6. 遇到script外部js,设置了 defer(只对ie9之前的版本有效),浏览器创建新的线程下载js,于此同时继续解析html,等js下载完成后,js不会执行,浏览器继续解析html。(异步禁止使用document.write() 这会清空之前解析的dom)
  7. 遇到 img,video,audio,iframe等多媒体标签时,浏览器会创建新的线程,去异步加载src,同时继续解析html。
  8. html文档全部解析完成后,document.readyState='interactive'所有设置defer的js脚本会按照顺序执行。
  9. document对象触发DOMContentLoader事件,这也标志着程序执行从同步脚本阶段,转化为事件驱动阶段。
  10. 当所有的异步脚本加载完成并执行后,img等多媒体资源加载完成后,document.readyState = 'complete',window对象会触发load事件。
  11. 从此,异步响应方式处理用户输入,网络事件等。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
</body>
</html>

<script>
    console.log(document.readyState) // loading

    document.onreadystatechange = function () {
        console.log(document.readyState) // 先后打印 interactive, complete
    }
    
	// 当dom解析完成时执行
    document.addEventListener('DOMContentLoaded', function () {
        console.log('DOMContentLoaded') // 在interactive之后打印
    }, false)

    window.addEventListener('load', function () {
        console.log('load') // 在complete之后打印,最后
    })

</script>
loading 
interactive
DOMContentLoaded
complete
load

DOMContentLoaded 是比较重要的监听事件,会在dom解析完成时执行,与jquery的$(document).ready(function(){})功能一致。
而上文第10步也提到了,load事件是在所有资源加载完成后才触发。

在这里插入图片描述

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

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

相关文章

2023 年 数维杯(D题)国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 让我们来看看数维杯D题&#xff01; 问题一&#xff1a;最佳清…

软件外包开发设计文档的编写

编写软件设计文档是软件开发过程中至关重要的一步&#xff0c;下面是一些在编写软件设计文档时需要注意的问题&#xff0c;通过注意这些问题&#xff0c;可以确保软件设计文档是清晰、完整且易于理解的&#xff0c;为整个开发团队提供有力的指导。北京木奇移动技术有限公司&…

candence出现no connect property onpin,,,,错误,该怎么办?

原因是上面有引脚添加了 属性no connect&#xff0c;但依然连接了网络&#xff0c;这个时候需要把线剪切&#xff0c;然后看到引脚上有个X, 解决方法&#xff1a; 工具栏&#xff02;place >no connect "X 再连上线&#xff0c;再生成网标的时候&#xff0c; 就不报错了…

【实施】Sentry-self-hosted部署

Sentry-self-hosted部署 介绍 Sentry 是一个开源的错误追踪&#xff08;error tracking&#xff09;平台。它主要用于监控和追踪应用程序中的错误、异常和崩溃。Sentry允许开发人员实时地收集和分析错误&#xff0c;并提供了强大的工具来排查和修复问题&#xff0c;研发最近是…

MCTS蒙特卡洛树搜索(The Monte Carlo Tree Search)

1、简介 蒙特卡罗树搜索是一类树搜索算法的统称&#xff0c;简称MCTS。它是一种用于某些决策过程的启发式搜索算法&#xff0c;且在搜索空间巨大的游戏中会比较有效。从全局来看&#xff0c;蒙特卡洛树搜索的主要目标是&#xff1a;给定一个游戏状态来选择最佳的下一步。等常见…

AD教程 (十六)常用PCB封装的直接调用

AD教程 &#xff08;十六&#xff09;常用PCB封装的直接调用 打开已经做好的PCB文件 点击设计&#xff0c;生成PCB库&#xff0c;会自动把PCB里所用到的所有封装&#xff0c;全部自动生成 CtrlA 将所有元器件的封装全部选中&#xff08;或者只选中所需要的&#xff09;&#x…

Java相关编程思想

少用继承多用“组合”——在现有类的基础上组织一个新类。 2.继承要用“is”来检验&#xff0c;如果继承者is被继承者&#xff0c;说明这是一个比较好的继承。 3.向上造型&#xff0c;把实现方法留给继承者去实现。&#xff08;动态绑定&#xff09; 4.把接口理解为抽象类的进一…

windows安装gdal库

提示&#xff1a;在windows上使用pip在cmd终端安装gdal 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 原因是由于丹丹安装使用pip安装gdal时报错Microsoft visual C 1…

编码器脉冲信号测量2路DI高速计数器PNP/NPN转RS-485数据采集模块 解码转换成标准Modbus RTU协议 YL150-485

特点&#xff1a; ● 编码器解码转换成标准Modbus RTU协议 ● 可用作编码器计数器或者转速测量 ● 支持编码器计数&#xff0c;可识别正反转 ● 也可以设置作为2路独立DI高速计数器 ● 计数值支持断电自动保存 ● DI输入支持PNP和NPN输入 ● 继电器和机械开关输入时可以…

几个测试接口的好工具,效率加倍~

作为一名后端程序员&#xff0c;一定要对自己写的接口负责&#xff0c;保证接口的正确和稳定性。因此&#xff0c;接口测试也是后端开发中的关键环节。 但我相信&#xff0c;很多朋友是懒得测试接口的&#xff0c;觉得这很麻烦。一般自己写的接口自己都不调用&#xff0c;而是…

【博客系统】 二

本文主要介绍了linux和如何在云服务器上部署一个简单的servlet程序. 一.云服务器 真正搞一个网站,是希望这个网站被其他人访问到 , 所以需要一个云服务器(具有外网ip)来让别人也可以访问 云服务器 操作系统是Linux(一般都是通过命令行来操作) 当前市面上常见的系统: 1.windo…

共享WiFi贴项目商业新模式,到底能不能做

共享WiFi贴的模式&#xff0c;已经在众多商业圈和线下商家门店中引起关注&#xff0c;创造出了一种新的共享互联网商业模式。然而这种共享模式到底能不能做&#xff0c;从中创业者可以获得多少的商业价值呢&#xff1f;让我们一文深度解析一下。 共享WiFi贴&#xff0c;简单来说…

052-第三代软件开发-系统监测

第三代软件开发-系统监测 文章目录 第三代软件开发-系统监测项目介绍系统监测 关键字&#xff1a; Qt、 Qml、 cpu、 内存、memory 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language&#xff09;和 C 的强大功…

智能制造中后期:深挖成本、提升效率的关键——标准工时

在智能制造的背景下&#xff0c;企业面临着持续的成本压力和效率提升的需求。特别是在智能制造的中后期&#xff0c;要想进一步深挖成本、提升效率&#xff0c;必须考虑标准工时这一重要因素。标准工时作为一种基础而富有价值的管理工具&#xff0c;对于建立领先的标准工时系统…

PPP协议_基础知识

ppp协议 点对点协议PPP(Point-to-Point Protocol)是目前使用最广泛的点对点数据链路层协议。 一.ppp协议的组成 PPP协议为在点对点链路传输各种协议数据报提供了一个标准方法&#xff0c;主要由以下三部分构成: 对各种协议数据报的封装方法(封装成帧)链路控制协议LCP    …

【机器学习】 特征工程:特征预处理,归一化、标准化、处理缺失值

特征预处理采用的是特定的统计方法&#xff08;数学方法&#xff09;将数据转化为算法要求的数字 1. 数值型数据 归一化&#xff0c;将原始数据变换到[0,1]之间 标准化&#xff0c;数据转化到均值为0&#xff0c;方差为1的范围内 缺失值&#xff0c;缺失值处理成均值、中…

前后端联调时JS数据精度问题的解决

在JavaScript中&#xff0c;Number类型范围 -2^53 1 到 2^53 - 1&#xff0c;而在Java中Long类型的取值范围是 -2^63 1 到 2^63 - 1, 比JavaScript中大很多&#xff0c;所以后端能正常处理。 其实 ES6 引入了 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 这两个常量…

开源与闭源:驾驭大模型未来的关键决断

在数字化的时代洪流中&#xff0c;开源与闭源的选择不断成为技术界的重要分水岭。随着特斯拉CEO埃隆马斯克的言论及其决策&#xff0c;公开支持开源&#xff0c;并糅合商业理念与技术革新&#xff0c;使得这场辩论再次成为公众关注的焦点。那么&#xff0c;在这场关乎技术发展脉…

八股文-TCP的三次握手

TCP协议是一种面向连接、可靠传输的协议&#xff0c;而建立连接的过程就是著名的三次握手。这个过程保证了通信的双方能够同步信息&#xff0c;确保后续的数据传输是可靠和有序的。本文将深入解析TCP三次握手的步骤及其意义。 漫画TCP的三次握手 TCP连接的建立采用了三次握手的…

vite动态配置svg图标及其他方式集合

文章目录 前言使用vite-plugin-svg-icons动态配置安装插件引入图标下载新建组件svg-icon.vue使用 使用vue组件动态配置总结如有启发&#xff0c;可点赞收藏哟~ 前言 在配置化的情况下&#xff0c;图标配置也显得极为重要的 使用vite-plugin-svg-icons动态配置 参考vite-plugin…