当前位置: 首页 > news >正文

JavaScript考核详解

文章目录

  • JavaScript考核详解
    • 一、请简述var,let,const的区别?
    • 二、解释垃圾回收机制,垃圾回收的方式?
    • 三、以下代码的输出是什么?
    • 四、this的指向
    • 五、实现数组扁平化
    • 六、实现数组去重
    • 七、JS中的基本类型


JavaScript考核详解

一、请简述var,let,const的区别?

  1. 块级作用域:块级作用域有大括号{ }包括,let和const具有块级作用域,var不存在块级作用域。块级作用域解决了ES6中的两个问题:
    • 内层变量可能覆盖外层变量
    • 用来计数的循环变量泄露为全局变量
  2. 变量提升:var存在变量提升,let和const不存在变量提升,即变量只能在声明之后使用,否则会报错。
  3. 给全局添加属性:浏览器的全局对象是window,Node的全局对象是global。var声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但是let和const不会。
  4. 重复声明:var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的变量。const和let不允许重复声明变量。
  5. 暂时性死区:在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。使用var声明的变量不存在暂时性死区,因为var声明的变量都会被提升到作用域的最顶部。
  6. 初始值设置:在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。
  7. 指针指向:let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。

二、解释垃圾回收机制,垃圾回收的方式?

  1. 垃圾回收的概念:JavaScript代码运行时,需要分配内存空间来储存变量和值。当变量不在参与运行时,就需要系统收回被占用的内存空间,这就是垃圾回收。

    回收机制

    • Javascript 具有自动垃圾回收机制,会定期对那些不再使用的变量、对象所占用的内存进行释放,原理就是找到不再使用的变量,然后释放掉其占用的内存。

    • JavaScript中存在两种变量:局部变量和全局变量。全局变量的生命周期会持续到页面卸载;而局部变量声明在函数中,它的生命周期从函数执行开始,直到函数执行结束,在这个过程中,局部变量会在堆或栈中存储它们的值,当函数执行结束后,这些局部变量不再被使用,它们所占有的空间就会被释放。

    • 不过,当局部变量被外部函数使用时,其中一种情况就是闭包,在函数执行结束后,函数外部的变量依然指向函数内部的局部变量,此时局部变量依然在被使用,所以不会回收。

      function outer(){let i = 1function fn(){console.log(i)}return fn
      }
      const fun = outer()
      fun() // 返回1
      // 外层函数使用内部函数的变量
      
  2. 垃圾回收的方式

    1. 引用计数法:IE采用的引用计数算法,定义“内存不再使用”,就是看一个对象是否有指向它的引用,没用引用了就回收对象。

      算法:

      1. 跟踪记录被引用的次数
      2. 如果被引用类一次,那么就记录次数加一,多次引用会累加
      3. 如果减少一个引用就减一
      4. 如果引用次数是0,则释放内存

      但引用计数法存在一个致命的问题:嵌套引用(循环引用)。

      如果两个对象相互引用,尽管他们已不再使用,垃圾回收器不会进行回收,导致内存泄露,因为他们的引用次数永远不会是0,这样的相互引用如果大量存在会导致大量的内存泄露。

    2. 标记清除法:现代的浏览器已经不再使用引用计数算法,使用的大多是基于标记清除算法的某些改进算法,总体思想都是一致的。

      核心:

      • 标记清除算法将“不再使用的对象”定义为“无法达到的对象”。
      • 就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的。
      • 那些无法由根部出发的对象被标记为不再使用,稍后进行回收。

三、以下代码的输出是什么?

var tmp = new Date();function fn(){console.log(tmp);if(false){var tmp = 'hello world';}
}fn();

答案:undefined。

解释:var存在变量提升,var声明的变量会被提升到作用域的顶层,但该声明不包括赋值,所以虽然if判断里的语句虽然并不会执行,但其实已经在fn函数作用域内的顶部声明了一个未被赋值的tmp变量,所以console.log(tmp)打印出来的结果是undefined。

四、this的指向

var name = "window";
var person = {name: "person",sayName: function () {console.log(this.name);},hello: () => console.log(this.name)
};
function sayName() {var sss = person.sayName;sss(); person.sayName(); (person.sayName)(); (b = person.sayName)();person.hello()
}
sayName(); 

调用sss();后this指向window。

原因:当函数被作为普通函数调用时,this指向全局对象(在浏览器中是window,在Node.js中是global),或者在严格模式('use strict')下,thisundefined

调用person.sayName();后this指向person。

原因:当函数被作为对象的方法调用时,this指向该对象。

调用(person.sayName)();后this指向person。

原因:当函数被作为对象的方法调用时,this指向该对象。

调用(b = person.sayName)();后this指向window。

原因:当函数被作为普通函数调用时,this指向全局对象(在浏览器中是window,在Node.js中是global),或者在严格模式('use strict')下,thisundefined

调用后person.hello()this指向window

原因:箭头函数不绑定自己的this,它会捕获其所在上下文的this值,作为自己的this值。

五、实现数组扁平化

JavaScript中实现数组扁平化(即将多维数组转换为一维数组)有多种方法,以下是一些常见的方法:

  1. 使用递归

递归是处理嵌套结构如多维数组的一个直观方法。你可以编写一个函数,该函数检查数组中的每个元素,如果元素是数组,则递归调用该函数;否则,将元素添加到结果数组中。

function flattenArray(arr) {let result = [];for (let i = 0; i < arr.length; i++) {if (Array.isArray(arr[i])) {result = result.concat(flattenArray(arr[i]));} else {result.push(arr[i]);}}return result;
}console.log(flattenArray([1, [2, [3, [4]], 5]])); // 输出: [1, 2, 3, 4, 5]
  1. 使用栈

迭代方法结合栈也是处理数组扁平化的有效方式。我们可以将数组元素逐一压入栈中,并在遇到数组时将其元素再次压入栈中,直到栈为空。

function flattenArrayWithStack(arr) {let stack = [...arr];let res = [];while (stack.length) {// 取出栈的最后一个元素const next = stack.pop();if (Array.isArray(next)) {// 如果是数组,则将数组元素逆序压入栈中// 这样可以保证原始数组的顺序在结果中被保留stack.push(...next.reverse());} else {// 否则,将元素添加到结果数组中res.push(next);}}// 因为我们是从栈中取元素,所以结果数组是逆序的,需要反转return res.reverse();
}console.log(flattenArrayWithStack([1, [2, [3, [4]], 5]])); // 输出: [1, 2, 3, 4, 5]
  1. 使用ES6的扩展运算符和reduce

这种方法利用了ES6的扩展运算符...和数组的reduce方法,通过递归的方式实现扁平化。

function flattenArrayWithReduce(arr) {return arr.reduce((acc, val) => Array.isArray(val) ? [...acc, ...flattenArrayWithReduce(val)] : [...acc, val], []);
}console.log(flattenArrayWithReduce([1, [2, [3, [4]], 5]])); // 输出: [1, 2, 3, 4, 5]
  1. 使用flat()(ES2019引入)

从ES2019开始,JavaScript引入了一个名为flat()的数组方法,它可以用来实现数组的扁平化,其默认只会扁平化一层,但你可以通过传递一个整数参数来指定扁平化的深度,如果深度为Infinity,则表示无论嵌套多少层都将被扁平化。

const arr = [1, [2, [3, [4]], 5]];console.log(arr.flat(Infinity)); // 输出: [1, 2, 3, 4, 5]

这是最简单也最现代的方法,但请注意,它可能不适用于需要兼容较旧JavaScript环境的场景。

六、实现数组去重

题目:给定某无序数组,要求去除数组中的重复数字并且返回新的无重复数组。

解答:

  1. 使用ES6的Set数据结构

Set是一个构造函数,它创建一个值的集合,其中的值都是唯一的,没有重复的值。因此,将数组转换为Set,然后再转换回数组,可以实现去重。

function uniqueArray(arr) {return [...new Set(arr)];
}console.log(uniqueArray([1, 2, 2, 3, 4, 4, 5])); // 输出: [1, 2, 3, 4, 5]
  1. 使用filter()indexOf()

遍历数组,对于当前元素,使用indexOf()检查它首次出现的位置是否和当前位置相同,如果相同,则说明不是重复元素,将其保留。

function uniqueArray(arr) {return arr.filter((item, index) => arr.indexOf(item) === index);
}console.log(uniqueArray([1, 2, 2, 3, 4, 4, 5])); // 输出: [1, 2, 3, 4, 5]

但需要注意的是,这种方法在数组元素为对象时可能不适用,因为对象比较是基于引用的。

  1. 使用Map数据结构

类似于SetMap也是一个集合,但它保存键值对。我们可以利用它的键是唯一的特性来实现去重。

function uniqueArray(arr) {const map = new Map();arr.forEach(item => map.set(item, true));return Array.from(map.keys());
}console.log(uniqueArray([1, 2, 2, 3, 4, 4, 5])); // 输出: [1, 2, 3, 4, 5]
  1. 使用reduce()

reduce()方法可以对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。我们可以利用这一点来构建一个新的数组,只包含不重复的元素。

function uniqueArray(arr) {return arr.reduce((acc, current) => {if (acc.indexOf(current) === -1) {acc.push(current);}return acc;}, []);
}console.log(uniqueArray([1, 2, 2, 3, 4, 4, 5])); // 输出: [1, 2, 3, 4, 5]

七、JS中的基本类型

Number、Object、BigInt、Symbol、String、Boolean、Undefined、Null

  • 栈:原始数据类型(Undefined、Null、Boolean、Number、String)
  • 堆:引用数据类型(对象、数组和函数)

ES6新增:Symbol、Bigint

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于鸿蒙API10的RTSP播放器(五:拖动底部视频滑轨实现跳转)
  • 深度解析 MintRich 独特的价格曲线机制玩法
  • 【宠物小精灵之收服(待更新)】
  • 【JavaWeb】利用IDEA2024+tomcat10配置web6.0版本搭建JavaWeb开发项目
  • 安全建设当中的冷门知识
  • 简单题27 - 移除元素(Java)20240917
  • 如何在win10Docker安装Mysql数据库?
  • JavaSE - 面向对象编程03
  • Qt | AI+Qt6.5.3+ubuntu20.04+FFmpeg实现音视频编解码(播放一个中秋节快乐视频为例)
  • 安全API
  • LeetCode 815.公交路线(BFS广搜 + 建图)(中秋快乐啊)
  • 【AcWing】前缀和与差分(一维 + 二维)
  • 轮转数组 给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数
  • [网络]TCP/IP协议 之 网络层IP协议(3)
  • react crash course 2024 (1)理论概念
  • Consul Config 使用Git做版本控制的实现
  • css的样式优先级
  • Effective Java 笔记(一)
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • java8-模拟hadoop
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • Linux后台研发超实用命令总结
  • mysql外键的使用
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 安装python包到指定虚拟环境
  • 闭包--闭包之tab栏切换(四)
  • 测试开发系类之接口自动化测试
  • 第十八天-企业应用架构模式-基本模式
  • 构造函数(constructor)与原型链(prototype)关系
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 使用API自动生成工具优化前端工作流
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 用Python写一份独特的元宵节祝福
  • 自制字幕遮挡器
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 带你开发类似Pokemon Go的AR游戏
  • 第二十章:异步和文件I/O.(二十三)
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​​​【收录 Hello 算法】10.4 哈希优化策略
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​油烟净化器电源安全,保障健康餐饮生活
  • #pragma multi_compile #pragma shader_feature
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • $L^p$ 调和函数恒为零
  • (1)bark-ml
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (c语言)strcpy函数用法
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (多级缓存)缓存同步
  • (分类)KNN算法- 参数调优
  • (附源码)小程序 交通违法举报系统 毕业设计 242045