web方向js考核题解

this指向代码题

1.讲出几大类函数this指向 - 普通函数,对象函数,构造函数,箭头函数

(1)普通函数:this指向全局对象window.

(2)对象函数:this指向函数所在的对象。

(3)构造函数:this指向该构造函数形成的对象实例。

(4)箭头函数:本身不存在this,已外层元素的this指向作为自己的this指向。

2.讲出apply,call,bind的区别,以及使用方法

区别:

  1. apply,call修改完this指向,立即自动执行。bind需要手动调用。
  2. call和bind传入参数为对象,apply为数组。

使用方法

  1. call和bind传入对象作为参数,apply传入数组。
  2. apply和call传入参数后会自动修改this指向,bind修改完this指向,需要手动调用一遍。
3.
Plain 复制代码
var name = 'global'

const obj = {
  name: 'obj',

  say() {
    console.log(this.name)

    const fn = function () {
      console.log(this.name)
    }

    fn()
  }
}

obj.say()
  1. 两次 console.log 分别输出什么?

obj,global.

  1. 为什么?

第一次say由obj调用,this指向obj,fn由window调用,this指向window。

  1. 如果把 fn 改成箭头函数:
Plain 复制代码
const fn = () => {
  console.log(this.name)
}

输出又是什么?为什么?

obj,obj.第一次say由boj调用,this指向obj,fn为箭头函数,this由外层的say决定,所以也指向obj。

  1. 有没有什么改变this的思路,讲讲实现bind的思路
    改变思路:把函数变成目标对象的一个临时方法,由该对象来调用它。
    bind实现思路:bind 本身不会立即执行函数,而是返回一个新的函数。我会先保存原函数和需要绑定的 this,然后在返回函数
    执行的时候,通过 call 或 apply 调用原函数,并把绑定的参数和后续调用时传入的参数合并起来。除此之外,
    还需要考虑返回的函数被 new 调用的情况,因为这种情况下 this 应该指向新创建的实例,而不是之前绑定的对象。

Var let const 全局预编译 函数预编译

  1. 讲出let,const,var的区别,块级作用域,变量提升,以及后来不使用var的原因
  • 块级作用域:let,const具有块级作用域,var不具有块级作用域。
  • 变量提升:var存在变量提升,let,const虽然也存在变量提升,但他们同时存在暂时性死区,即从当前作用域顶部到变量完成声明,这一区间内该变量是不可访问的。
  • 原因:var的变量提升使var声明的变量可以先使用后声明,以及var可以重复生命同一变量,使得代码可读性和安全性大大降低,所以不用。
Plain 复制代码
var a = 1;
let b = 2;

function test() {
  console.log(a);
  console.log(b);

  var a = 3;
  let b = 4;

  console.log(a);
  console.log(b);
}

test();

console.log(a);
console.log(b);
  1. 控制台会输出什么?

先输出undefined,然后报错。

  1. 哪一行会报错,为什么会报错?

函数内第一次打印b,let声明的函数存在暂时性死区,禁止访问。

  1. 如果把函数里面的 let b = 4 改成 var b = 4,输出又会有什么变化?

undefined,undefined,3,4,1,2

垃圾回收机制

  1. 什么是垃圾回收机制?判断机制是什么?

垃圾回收机制:定期扫描内存,找出那些不再被使用的变量或对象,并自动释放它们占用的内存空间。

判断机制:第一个是引用次数,当引用次数为0时触发垃圾回收。第二个是标记清除法,从根元素开始,将所有可达的变量标记为1,将剩下的变量清除。

  1. 什么是内存泄漏?前端常见的内存泄漏场景有哪些?

内存泄漏:程序申请了一块内存,使用完毕后,由于某些原因没有被垃圾回收释放,且这块内存再也无法被程序访问或使用了。

常见场景:意外的全局变量,未清理的定时器,事件监听器未解绑,闭包使用完变量后为设为null,DOM 节点被 JavaScript 变量引用,导致节点无法被回收。

  1. 你有了解过V8 引擎对垃圾回收机制的优化吗? 比如分代回收式垃圾回收?

根据变量的存活时间,把变量分为新生代和老生代,新生代存放新创建的对象。空间小,回收极频繁。老生代存放存活时间久或体积巨大的对象。空间大,回收频率低。对不同代的变量采用不同的回收算法。

闭包 作用域链

  1. JS有哪几种作用域?

全局作用域,函数作用域,块作用域。

  1. 什么是作用域链?变量查找时按照什么顺序进行?

当我们查找某个变量时,我们会首先在当前作用域查找,如果没有就到外层作用域查找,层层查找,直到找到变量所在位置,或查找到全局作用域,这个过程就形成了作用域链,按照由内向外的顺序。

  1. 什么是闭包?

闭包指可以访问另一个作用域中变量的函数。

  1. 输出什么?为什么?

1,2,1,3,2.因为每次调用 outer() 都会生成一个全新的、独立的闭包,fn1和fn2是两个完全不同的函数对象,他们互不影响。

JavaScript 复制代码
function outer() {
  let count = 0;
  return function () {
    count++;
    console.log(count);
  };
}

const fn1 = outer();
const fn2 = outer();

fn1();
fn1();
fn2();
fn1();
fn2();

原型与原型链

JavaScript 复制代码
function Person(name) {
  this.name = name;
}

Person.prototype.name = "prototype";
Person.prototype.age = 18;

const p = new Person("Jason");

console.log(p.name);
console.log(p.age);
console.log(p.hasOwnProperty("name"));
console.log(p.hasOwnProperty("age"));
console.log(p.__proto__ === Person.prototype);
console.log(Person.prototype.constructor === Person);

p.age = 20;

console.log(p.age);
console.log(Person.prototype.age);

delete p.age;

console.log(p.age);
  1. 九次console.log分别输出什么?

Jason,18,true,false,true,true,20,18,18.

  1. p.name最开始在哪里获取?p.__proto__指向什么?

p.name开始获取自实例p自身,p.__proto__ 指向 Person.prototype

  1. p.age 赋值后,为什么Person.prototype.age没有被修改?删除 p.age 后,为什么仍然能访问到 18

二者不是一个东西,p.age在p这个实例对象上,Person.prototype.age在构造函数的原型对象上。

删除p.age,在实例对象上找不到age属性,会沿着原型链继续找,找到Person.prototype.age。

  1. 什么是原型链?试着讲讲实例p的完整原型链以及原型链的末尾是什么。

每个实例对象上都有一个__proto__属性指向构造函数的原型对象,原型对象又有自己的原型对象,层层向上查找,直到找到顶级原型对象null,就形成了原型链,末尾是null.

深浅拷贝

  1. 讲讲你理解的深浅拷贝,并说出两个拷贝对象的浅拷贝方法

浅拷贝:只拷贝对象的第一层属性。如果属性值是基本类型,拷贝的是值;如果属性值是引用类型,拷贝的是内存地址。这意味着新旧对象共享内部的子对象,修改子对象会相互影响。

深拷贝:递归拷贝对象的所有层级。在堆内存中完整开辟一块新空间,将原对象完全复制一份。新旧对象完全独立,互不影响。

浅拷贝方法:展开运算符,object.assign().

  1. 什么是循环引用?如果你想自己实现深拷贝,讲讲循环引用可能导致的问题以及解决方法

循环引用:循环引用是指对象内部的属性直接或间接地引用了自身。

手动递归深拷贝导致的问题:如果不加处理,递归函数会陷入死循环,导致调用栈溢出。

解决方法:使用 WeakMap作为哈希表进行缓存。每次拷贝一个对象前,先检查缓存中是否已经存在该对象的拷贝,如果存在则直接返回,切断无限递归。

  1. 使用 JSON.parse(JSON.stringify(obj)) 实现深拷贝有什么局限?它无法正确处理什么数据(至少两种)?给出一种更适合的深拷贝原生方法。

无法处理函数和特殊对象。采用structuredClone。

隐式转换

  1. 什么时候会出现隐式转换?请说说不同运算符的转换规则是什么。( + - * / ==)

发生时机:当运算符两侧的操作数类型不一致时,JS 引擎为了能执行运算,会自动将其中一方或双方转换为相同类型。这通常发生在算术运算、比较运算(==) 以及 if / 逻辑上下文中。

加号:如果任一操作数是字符串,则将另一个操作数转为字符串,进行拼接,否则转数字:如果都不是字符串,则将它们都转为数字,进行加法。

- * /:将两个操作数都转为数字(Number),然后进行数学计算。如果任意一方无法转为有效数字,结果就是 NaN。

==:比较前会进行类型转换,遵循以下优先级:

(1)null == undefined 为 true(互转时视为相等)。

(2)数字 vs 字符串:将字符串转为数字再比较。

(3)布尔值参与:将布尔值转为数字(true 变 1,false 变 0)再比较。

(4)对象 vs 原始类型(字符串/数字/Symbol):将对象转为原始类型(To再比较。

(5)如果两侧都是对象:比较的是内存地址,只有引用同一个对象才返回 true,不会进行类型转换。

  1. [] == false 的输出是什么,并判断过程

输出 true。先将false转为0,再将\[\]转为空字符串,再将空字符串转为0,0==0,所以为true.

数据类型

  1. js有几种数据类型?分别是什么?指出哪些是原始类型,哪些是引用类型?SymbolBigInt 的作用?

8种,null,undefined,string,number,boolen,symbol,bigint,object.

原始类型:null,undefined,string,number,boolen,symbol,bigint

引用类型:object

symbol:创建绝对唯一的标识符.

bigint:精确表示超大整数.

  1. 获取数据类型方式有哪些?各自的特点

typeof:快速区分原始类型和函数,无法区分null和对象,以及具体的对象类型。

instanceof:检测引用类型的具体构造函数,无法检测原始类型,跨窗口场景下失效。

Object.prototype.toString.call():最准确的内置类型识别,无法区分自定义类实例。

  1. 为什么typeof null==Object ?

这是 JS 的历史遗留 bug:JS 最初用低位标记表示数据类型,000 开头代表对象类型,而 null 的所有二进制位都是 0(表示空指针),刚好落入对象的标记范围,所以 typeof null 返回 'object'。这个问题一直保留至今是为了兼容旧代码,没有修复。

任务队列

JS中哪些任务是同步任务 宏任务 微任务?下列代码的控制台输出是什么?

JavaScript 复制代码
button.addEventListener('click',()=>{
  Promise.resolve().then(()=> console.log('Microtask 1'));
  console.log('Listener 1');
});
button.addEventListener('click', ()=>{
  Promise.resolve().then(()=>console.log('Microtask 2'));
  console.log('Listener 2');
});

同步任务:大部分常规语句,函数调用,Promise 的执行器函数,async 函数中 await 之前的代码。

宏任务:定时器类,I/O操作,UI渲染,MessageChannel 的消息回调,事件监听。

微任务:Promise 的链式回调,async/await 中 await 之后的代码,MutationObserver,queueMicrotask() 显式调用的回调,Node.js 环境中的 process.nextTick()。

输出:Listener 1,Listener 2,Microtask 1,Microtask 2

异步编程

JS运行特点?为什么需要异步编程?什么是回调地狱?如何解决回调地狱?

JS运行特点:单线程运行,异步编程

为什么需要异步编程:让浏览器可以将未完成任务挂起,继续处理其他工作,等结果准备好后再处理,同时监听用户输入、加载数据、播放动画,而不会互相阻塞。

回调地狱:需要使用多个回调函数时,需要在函数中层层嵌套,使得代码难以阅读和维护,运行结果处理分散,形成回调地狱。

如何解决回调地狱:Promise链式调用,统一错误处理.

ES6新特性

JavaScript 复制代码
const id = Symbol("id");

const user = {
  name: "Tom",
  age: 18,
  [id]: 1001
};

function fn(user) {
  const { name, age } = user;
  console.log(arguments.length);
  console.log(name, age);
  console.log(user.id);
  console.log(user[id]);
 
}

fn(user, "extra");
  1. 四次 console.log 分别输出什么?

2,Tom 18,undefined,1001

  1. 为什么 arguments.length2

因为 arguments 保存的是函数调用时实际传入的所有实参。

  1. const { name, age } = user 是什么语法?

对象的解构赋值。

  1. user[id]user.id 有什么区别?

前者访问symbol属性,后者访问字符串属性

  1. Symbol 作为对象属性名有什么作用?

Symbol 创建出来的值具有唯一性,可以作为对象属性名,避免和其他普通属性或者其他 Symbol 属性发生命名冲突。

相关推荐
风骏时光牛马1 小时前
AI面试复盘:沉淀经验,找准求职短板
前端
liangshanbo12151 小时前
面试题终极整理:手写 Promise.all / Promise.allSettled
前端·javascript·promise
心易行者1 小时前
用HTML在线运行搭后台管理系统:5个核心模块+0服务器,3天跑通完整业务
大数据·前端·网络·人工智能·python
ThornArmor1 小时前
重铸1996|首秀点亮:编写 helloworld 并用 Makefile 自动化收割第一个 .z64 卡带镜像
开发语言
船厂电气自动化ai大模型1 小时前
AI大模型与数学 第73课 秩的核心定义、矩阵秩的通用求解方法
开发语言·数据结构·机器学习
单线程121381 小时前
从案例分析 Vue3 Tokenizer+Parser 源码五
前端·javascript·vue.js
神奇的程序员1 小时前
Apple Watch S12,送一台
前端
小白学大数据2 小时前
Codex 里的 GPT 6 Astra、GPT 5.6 Sol、Terra、Luna 怎么选
开发语言·gpt·microsoft
moonsims2 小时前
Voliro 无人机-Aerial Mobile Robot(空中移动机器人):把无人机从“飞过去拍摄”,升级成“飞过去并与目标物理接触、测量甚至操作”
前端·人工智能·安全·无人机·量子计算