当前位置: 首页 > 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


http://www.mrgr.cn/news/28895.html

相关文章:

  • 【LeetCode】【算法】11. 盛最多水的容器
  • python共享全局变量的方案
  • 丹摩征文活动|Faster-Rcnn-训练与测试详细教程
  • MySQL核心业务大表归档过程
  • CentOS AppStream 8 手动更新 yum源
  • leetcode83. Remove Duplicates from Sorted List
  • 淘宝npm镜像源更新后,如何正常使用npm命令
  • 使用C++程序编写5 个浮点数,求平均值后输出
  • STL相关简介
  • 削峰+限流:秒杀场景下的高并发写请求解决方案
  • Vscode运行Python无法导入自己编写的包的解决方法
  • 【数据结构初阶】顺序结构二叉树(堆)接口实现超详解
  • Flet全平台开发:软件开发界勇士为Python语言补短板的一次极具挑战性的尝试、冲刺和华丽亮相
  • AWS认证SAA-C03每日一题
  • python中Web开发框架的使用
  • Java4----String
  • 绿咖啡豆缺陷检测系统源码分享
  • (十六)、把镜像推送到私有化 Docker 仓库
  • c++249多态
  • 以root用户登陆ubuntu的桌面环境
  • win+linux平台C语言获取进程的线程数量
  • Java 语言的虚拟机风格
  • 移动应用开发实验室web组js第一次考核
  • 设计模式中工厂模式的C语言实现
  • 网络安全笔试练习题,据说10分钟内答对的都是高手!
  • 算法题之回文子串