JS考核之解析

1. 请简述var, let, const的区别?

答:

  1. var:具有变量提升,可在变量声明前就使用该变量
  2. let:不具有变量提升,用let声明的变量可以重新赋值
  3. const:不具有变量提升,用const声明的变量:简单数据类型不能重新赋值,引用数据类型可以重新赋值,但不能更改其地址

2.解释垃圾回收机制,垃圾回收的方式?

答:

  1. 垃圾回收机制:当某段内存不再使用时,系统会自动回收并释放该内存,引用数据类型可由程序员手动回收
    • 内存管理:垃圾回收器自动跟踪分配给对象的内存,并在对象不再被需要时释放这些内存。
    • 引用:对象通过引用被其他部分的代码所访问。只要对象还有引用指向它,它就被认为是可达的,因而不应被回收。
    • 垃圾:如果没有任何引用指向某个对象,那么这个对象就变成了垃圾,可以被回收
  2. 垃圾回收的方式:
    • 标记-清除(Mark and Sweep):
      标记阶段:垃圾回收器从一系列称为“根”的对象开始(比如全局对象、栈中的本地变量等),递归地遍历所有从根可达的对象,并标记这些对象。
      清除阶段:未被标记的对象被认为是垃圾,垃圾回收器将释放这些未标记的对象占用的内存。
    • 复制(Copying):
      JavaScript引擎将可用内存划分为大小相等的两块区域。运行时只使用其中一个区域来分配内存。垃圾回收时,将正在使用的对象复制到另一个区域,并清理当前使用的区域。
    • 分代收集(Generational Collection):
      这种方法基于观察:大多数对象很快就会变得不可达。新创建的对象被称为“年轻代”,而存活了一段时间的对象则被移动到“老年代”。
      对年轻代进行频繁的垃圾回收,而对老年代则较少回收。这样可以优化性能,因为年轻代中的大多数对象通常都是垃圾。
    • 增量标记(Incremental Marking):
      这种方法允许垃圾回收工作分散在整个执行过程中,而不是一次性停止所有工作来进行垃圾回收。这样可以减少长时间的暂停,提高用户体验。

3.以下代码的输出是什么

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

答:
undefined,用var生命的变量tmp具有变量提升的特性,因此会先使用再声明

4.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();

答:

  1. sss();
    sss是一个函数引用,这里直接调用它,没有显式绑定上下文。this指向全局对象window
  2. person.sayName();
    这里直接通过对象person来调用方法sayName,因此this将指向调用它的对象person
  3. (person.sayName)();
    这与第2点相同,this指向person对象,输出:“person”。
  4. (b = person.sayName)();
    这里b只是一个指向person.sayName的引用,当调用b()时,它没有明确的上下文绑定,因此this指向全局对象window
  5. person.hello();
    hello是一个箭头函数,箭头函数不绑定自己的this值,而是从定义它的上下文中继承this值。在这个例子中,hello是在person对象的构造上下文中定义的,但是由于它是箭头函数,它会捕获外层的作用域中的this值。这里的外层作用域是指sayName函数的作用域,而不是person对象。因此,this实际上指的是全局对象window

补充知识点:箭头函数的this指向规则:
箭头函数不会创建自己的this上下文,也就是说,箭头函数内部的this值是定义时所在的上下文(lexical this),而不是调用时的上下文。这意味着箭头函数内部的this值是在定义的时候绑定的,而不是在运行时动态决定的。

5. 实现数组的扁平化

let arr = [1, [2, [3, 4, 5]]];

答:

  1. 使用flat方法
let arr = [1, [2, [3, 4, 5]]];
let flatArr = arr.flat(Infinity); // 或者指定嵌套层数,如 arr.flat(2);
console.log(flatArr); // 输出:[1, 2, 3, 4, 5]
  1. 递归
function flattenArray(arr) {
    return arr.reduce((acc, val) => 
        Array.isArray(val) ? acc.concat(flattenArray(val)) : acc.concat(val), []);
}

let arr = [1, [2, [3, 4, 5]]];
let flatArr = flattenArray(arr);
console.log(flatArr); // 输出:[1, 2, 3, 4, 5]

6. 实现数组去重

const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];

答:

  1. 使用set
const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];

const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // 输出:[1, 2, 3, 5, 9, 8]
  1. 使用filter
const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];

const uniqueArray = array.filter((value, index, self) => self.indexOf(value) === index);
console.log(uniqueArray); // 输出:[1, 2, 3, 5, 9, 8]
  1. 使用Map
const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];

const uniqueArray = array.filter((value) => {
    if (!seen.has(value)) {
        seen.set(value, true);
        return true;
    }
    return false;
}, new Map());

console.log(uniqueArray); // 输出:[1, 2, 3, 5, 9, 8]

7.JS中的基本类型

答:

  1. number数字型
  2. string字符串型
  3. boolean布尔型
  4. undefined未定义型
  5. null空类型
  6. BigInt:表示大于2^53-1的整数
  7. Symbol符号:是一种唯一的不可变的数据类型,用于生成唯一的标识符,通常用作对象属性的键,避免命名冲突

8.讲一下JS的事件流

答:
事件流指的是事件如何在DOM树中传播的过程。当用户与网页交互(例如点击按钮、滚动页面等)时,会产生事件。事件流包括三个阶段:事件捕获、处于目标阶段、事件冒泡。

  1. 事件捕获
    这是事件流的第一个阶段。在这个阶段,事件从最顶层的节点(通常是document或window)开始向下传播,直到达到目标节点。在这个阶段,可以预先拦截事件。

  2. 处于目标阶段
    这是事件流的第二个阶段,事件到达目标节点,触发目标节点上的事件处理程序。这是事件流中最常见的阶段,也是我们通常编写事件处理程序的地方。

  3. 事件冒泡
    这是事件流的最后一个阶段。在这个阶段,事件从目标节点开始向上冒泡,经过DOM树中的每一个父节点,直到文档的根节点。这个阶段可以用来捕获在子节点上发生的事件,并在父节点上执行某些操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值