☰
JavaScript Questions(埃及阿拉伯语版)43 道进阶面试题精讲:从作用域、this 到事件循环与原型链
2026/9/30 2:16:37 网站建设 项目流程
  • 前端
  • 教程
  • 文档

【免费下载链接】javascript-questions

A long list of (advanced) JavaScript questions, and their explanations :sparkles:

项目地址:https://gitcode.com/GitHub_Trending/ja/javascript-questions
点击查看免费下载

本篇文章以 ar-EG/README_ar-EG.md(埃及阿拉伯语俗语版)为核心骨架,完整还原其收录的全部 43 道进阶 JavaScript 选择题及其答案解析,并结合仓库英文原版 README.md 中对应的权威解释(英文版共 155 道题,阿拉伯语两个版本覆盖其中前 43 题),对每一题背后的运行机制做中文深度讲解。读完本文,你将系统掌握 JavaScript 的变量提升与临时死区、块级作用域、this绑定规则、对象引用语义、原型链与继承、事件传播与事件循环、隐式类型转换、存储 API 与生成器等高频面试考点,可直接用于面试准备、知识复习与日常避坑。

仓库与文档背景

本仓库是一份长期维护的 JavaScript 进阶问答清单(创建于 2019 年),题目按"从基础到进阶"组织,每题采用"问题 + 多选选项 + 可折叠答案解析"的形式。英文原版位于根目录 README.md,文中明确提示:题目基于 2019 年前后的 JavaScript 语法与行为,且仓库持续更新新题。

埃及阿拉伯语版 ar-EG/README_ar-EG.md 由社区以"埃及俗语阿拉伯语 + 英文混写"的方式翻译,覆盖英文版前 43 题,题目编号与英文版一一对应。此外仓库还提供了标准阿拉伯语版 ar-AR/README_AR.md(47 题)、日语版 ja-JA/README-ja_JA.md(86 题)等其他语言的译文,各语言版本题目结构完全一致,方便对照学习。仓库采用 MIT 许可证(见 LICENSE),允许自由使用与修改。

一、变量声明:提升(Hoisting)与临时死区(TDZ)

第 1 题:var与let的初始化时机

题目代码:

function sayHi() { console.log(name); console.log(age); var name = "Lydia"; let age = 21; } sayHi();

正确选项:D:undefined和ReferenceError。

解析:在函数内部,name用var声明,其内存空间在创建阶段就被预先分配,默认值为undefined,因此在使用console.log打印时(尚未执行到赋值行),name仍是undefined。而let(以及const)虽然也会被提升,但不会被初始化,在声明行之前访问会触发所谓"临时死区"(Temporal Dead Zone),抛出ReferenceError。

第 16 题:后置递增与前置递增

let number = 0; console.log(number++); console.log(++number); console.log(number);

正确选项:C:0、2、2。后置运算符x++先返回原值再自增,前置运算符++x先自增再返回新值。第一行输出0(number 变 1),第二行先自增到 2 再输出2,第三行输出 2。

第 20 题:"use strict"禁止隐式全局变量

function getAge() { "use strict"; age = 21; console.log(age); }

正确选项:C:ReferenceError。在严格模式下,给未声明的变量赋值不再自动创建全局变量,而是抛出ReferenceError。

第 23 题:var允许重复声明

var num = 8; var num = 10; console.log(num);

正确选项:B:10。var允许以同名重新声明并覆盖,最终值取最后一次赋值的10;let与const则不允许重复声明同名变量。

第 26 题:全局执行上下文

"在 JavaScript 中,global对象和this关键字总是存在。"——正确选项:A:正确。任何代码都运行在全局执行上下文(global execution context)中,其中容纳所有全局变量。

第 9 题:拼写错误导致的隐式全局对象

let greeting; greetign = {}; // Typo! console.log(greetign);

正确选项:A:{}。greetign是拼写错误,但由于未声明就赋值,在非严格模式下会隐式创建为全局对象属性(浏览器中即window.greetign = {})。官方答案建议使用"use strict"来避免这类问题(呼应第 20 题)。

二、块级作用域、闭包与循环陷阱

第 2 题:var与let在循环中的经典闭包问题

for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 1); } for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 1); }

正确选项:C:3 3 3和0 1 2。由于事件队列机制,setTimeout的回调在循环结束后才执行。第一个循环用var声明i,它是全局/函数作用域的单一变量,循环结束时i已是 3,因此三个回调都打印 3;第二个循环用let声明i,它拥有块级作用域,每次迭代都会生成独立的新绑定,所以分别输出 0、1、2。

第 27 题:continue跳过本轮

for (let i = 1; i < 5; i++) { if (i === 3) continue; console.log(i); }

正确选项:C:1、2、4。continue在条件满足时跳过本轮剩余语句,直接进入下一次迭代,因此 3 不会被打印。

第 30 题:事件队列中的setTimeout

const foo = () => console.log("First"); const bar = () => setTimeout(() => console.log("Second")); const baz = () => console.log("Third"); bar(); foo(); baz();

正确选项:B:First、Third、Second。浏览器运行环境由 JavaScript 引擎与 Web APIs(如setTimeout)共同构成。setTimeout的回调(callback)会先被安排到任务队列中,主线程继续执行后续同步代码foo与baz,待调用栈清空后才执行回调,因此Second最后输出。

三、this绑定规则

第 3 题:箭头函数没有自己的this

const shape = { radius: 10, diameter() { return this.radius * 2; }, perimeter: () => 2 * Math.PI * this.radius, }; shape.diameter(); shape.perimeter();

正确选项:B:20和NaN。diameter是普通方法,this指向shape,返回10 * 2 = 20;perimeter是箭头函数,其this指向定义时的外层作用域(如window),而不是shape。外层没有radius,this.radius为undefined,运算结果自然是NaN。

第 33 题:call立即执行 vsbind返回新函数

const person = { name: "Lydia" }; function sayHi(age) { console.log(`${this.name} is ${age}`); } sayHi.call(person, 21); sayHi.bind(person, 21);

正确选项:D:Lydia is 21和function。两者都能显式指定this,但call会立即调用函数,而bind只返回一个绑定了this的新函数,不会立即执行,因此console.log打印出的是一段函数体。

第 12 题:new与普通调用的区别

function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } const lydia = new Person("Lydia", "Hallie"); const sarah = Person("Sarah", "Smith");

正确选项:A:Person {firstName: "Lydia", lastName: "Hallie"}和undefined。new会创建并返回一个新空对象,并把this绑定到它;而不带new调用构造函数时,this指向全局对象(浏览器中即window),相当于执行window.firstName = "Sarah",函数本身没有返回值,所以sarah是undefined。

四、对象、引用与原型链

第 6 题:对象按引用赋值

let c = { greeting: "Hey!" }; let d; d = c; c.greeting = "Hello"; console.log(d.greeting);

正确选项:A:Hello。对象彼此赋值时不会创建副本,只是把引用(内存地址)复制给新变量,c与d指向同一个对象,因此通过c修改属性会同时反映到d上。

第 46 题(英文版):数组元素持有引用副本

英文版 README.md 对引用语义做了更深入的图解(第 46 题):const members = [person]复制的是引用而非对象本身;随后person = null只是改变了person这个变量的指向,数组第一个元素仍持有原对象引用,所以打印结果是[{ name: "Lydia" }]。注意:复制引用与"共享同一个引用"在行为上是不同的。

第 5 题:对象键永远是字符串

const bird = { size: "small" }; const mouse = { name: "Mickey", small: true };

正确选项:A:mouse.bird.size不合法。JavaScript 中所有对象键(除 Symbol 外)底层都是字符串,即使书写时不带引号。mouse[bird.size]会先求值bird.size得到"small",等价于mouse["small"],返回true;而mouse.bird访问的是不存在的bird属性,得到undefined,再访问undefined.size便抛出cannot read property of undefined。

第 7 题:==与===对包装对象

let a = 3; let b = new Number(3); let c = 3; console.log(a == b); console.log(a === b); console.log(b === c);

正确选项:C:true、false、false。new Number(3)虽然显示为数字 3,实际却是一个包装对象。==只比较值(宽松相等),3 == 3为true;===同时比较值和类型,对象与原始值、以及两个不同的对象之间都不严格相等,因此后两行均为false。

第 11 题:实例方法要挂到prototype上

function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } const member = new Person("Lydia", "Hallie"); Person.getFullName = function() { return `${this.firstName} ${this.lastName}`; }; console.log(member.getFullName());

正确选项:A:TypeError。直接给构造函数添加属性并不会让已有实例获得该方法。正确的做法是挂到原型上:

Person.prototype.getFullName = function() { return `${this.firstName} ${this.lastName}`; };

这样所有由Person创建的实例都能共享同一个方法,避免在每个实例中复制一份函数,从而节省内存。

第 14 题:并非所有对象都有prototype

"所有对象都有prototype。"——正确选项:B:错误。唯一的例外是基对象(base object),它位于原型链的最顶端,是所有对象继承方法的源头。

第 28 题:扩展内置构造函数的原型

String.prototype.giveLydiaPizza = () => { return "Just give Lydia pizza already!"; }; const name = "Lydia"; console.log(name.giveLydiaPizza());

正确选项:A:"Just give Lydia pizza already!"。String是一个构造函数,可以向其prototype添加方法。字符串等原始值在调用方法时会被自动装箱(temporarily boxed)为对象,因此可以直接调用该原型方法。

第 39 题:一切皆原始值或对象

正确选项:A:primitive 或 object。JavaScript 的原始类型(primitives)包括boolean、null、undefined、bigint、number、string、symbol。原始值本身没有方法,但调用如'foo'.toUpperCase()时引擎会自动装箱,执行完再还原;undefined与null除外。

第 24 题:对象的键是字符串,Set 不是

const obj = { 1: "a", 2: "b", 3: "c" }; const set = new Set([1, 2, 3, 4, 5]); obj.hasOwnProperty("1"); obj.hasOwnProperty(1); set.has("1"); set.has(1);

正确选项:C:true、true、false、true。对象的数字键会被转成字符串,因此"1"与1都能命中hasOwnProperty;而Set采用严格相等的成员判定,数字1与字符串"1"是两个不同的值。

第 25 题:重复对象键取最后值

const obj = { a: "one", b: "two", a: "three" }; console.log(obj);

正确选项:C:{ a: "three", b: "two" }。同一对象中出现重名键时,后写的值覆盖先写的值。

第 29 题:对象作键会被转成"[object Object]"

const a = {}; const b = { key: "b" }; const c = { key: "c" }; a[b] = 123; a[c] = 456; console.log(a[b]);

正确选项:B:456。对象作为另一个对象的键时,会被自动字符串化为"[object Object]"。于是a[b]与a[c]实际都是对a["[object Object]"]赋值,第二次赋值 456 覆盖了 123。

第 18 题:对象比较的是引用

function checkAge(data) { if (data === { age: 18 }) { console.log("You are an adult!"); } else if (data == { age: 18 }) { console.log("You are still an adult."); } else { console.log(`Hmm.. You don't have an age I guess`); } } checkAge({ age: 18 });

正确选项:C:Hmm.. You don't have an age I guess。原始值比较值本身,而对象比较的是引用——即便结构和内容完全相同,两个不同的对象字面量在内存中也是两个地址。正确的对象比较方式是把它们序列化为字符串,或逐一比较内部属性。

第 22 题(关联):对象与数组的"按引用"陷阱补充

第 46 题的结论提醒我们:当把对象塞进数组或传给另一个变量时,复制的是引用;而修改"引用副本"指向的同一对象,所有持有该引用的位置都会同步变化。这是第 6 题与第 46 题共同揭示的核心结论。

五、函数、类型转换与运算符

第 4 题:一元+与!

+true; !"Lydia";

正确选项:A:1和false。一元+试图把操作数转为数字:true转1、false转0。字符串"Lydia"是真值(truthy),对它取反就是询问"这个真值是否为假",结果自然是false。

第 15 题:隐式类型转换(coercion)

function sum(a, b) { return a + b; } sum(1, "2");

正确选项:C:"12"。JavaScript 是动态类型语言,允许隐式类型转换。+遇到字符串时会把数值转成字符串再拼接,因此结果是"12"。

第 48 题(英文版):运算符结合性

英文版第 48 题console.log(3 + 4 + "5")的答案是"75"。当多个运算符优先级相同时,按结合性从左到右求值:先算3 + 4 = 7,再与"5"拼接得到"75"。这与第 15 题的隐式转换规则一致。

第 49 题(英文版):parseInt的解析行为

const num = parseInt("7*6", 10)的结果是7。parseInt从字符串第一个字符开始按基数(radix)解析,遇到不是合法数字的字符(此处是*)即停止,忽略后续内容。

第 17 题:标签模板字面量(Tagged Template Literals)

function getPersonInfo(one, two, three) { console.log(one); console.log(two); console.log(three); } const person = "Lydia"; const age = 21; getPersonInfo`${person} is ${age} years old`;

正确选项:B:["", " is ", " years old"]、"Lydia"、21。使用标签模板时,函数收到的第一个参数永远是"由纯字符串片段组成的数组"(不含插值),后续参数按顺序接收各插值变量的值。

第 19 题:剩余参数的typeof是"object"

function getAge(...args) { console.log(typeof args); } getAge(21);

正确选项:C:"object"。...args收集所有实参为一个数组,而数组是对象,因此typeof返回"object"。

第 21 题:eval执行字符串代码

const sum = eval("10*10+5");

正确选项:A:105。eval把传入的字符串当作代码执行,表达式10 * 10 + 5求出数值105。

第 34 题:IIFE 返回值的类型

function sayHi() { return (() => 0)(); } typeof sayHi();

正确选项:B:"number"。sayHi返回立即执行函数(IIFE)的结果0,它是数字。顺便复习:JavaScript 内置类型共 7 种(null、undefined、boolean、number、string、object、symbol),函数不是独立类型,而属于object。

第 36 题:typeof的输出永远是字符串

console.log(typeof typeof 1);

正确选项:B:"string"。typeof 1返回字符串"number",再对"number"求typeof,结果自然是"string"。

第 40 题:reduce与concat扁平化

[[0, 1], [2, 3]].reduce( (acc, cur) => { return acc.concat(cur); }, [1, 2] );

正确选项:C:[1, 2, 0, 1, 2, 3]。初始值[1, 2]作为acc的初值:第一轮把[0, 1]拼接得到[1, 2, 0, 1],第二轮再拼接[2, 3],最终得到[1, 2, 0, 1, 2, 3]。

第 41 题:双重取反!!

!!null; !!""; !!1;

正确选项:B:false、false、true。null与空字符串都是假值,双重取反得到false;1是真值,双重取反得到true。这是把任意值转成布尔值的惯用技巧。

第 35 题:六个假值

题目要求在0、new Number(0)、""、" "、new Boolean(false)、undefined中选出假值。正确选项:A:0、""、undefined。JavaScript 只有 6 个假值:undefined、null、NaN、0、''(空字符串)、false。任何构造函数返回的对象(包括new Number(0)、new Boolean(false))都是真值。

六、类、事件与浏览器 API

第 8 题:静态方法不属于实例

class Chameleon { static colorChange(newColor) { this.newColor = newColor; return this.newColor; } constructor({ newColor = "green" } = {}) { this.newColor = newColor; } } const freddie = new Chameleon({ newColor: "purple" }); freddie.colorChange("orange");

正确选项:D:TypeError。static方法只存在于构造函数本身上,不会被继承到实例中,因此实例freddie调用colorChange会抛出TypeError。

第 10 题:函数也是对象

function bark() { console.log("Woof!"); } bark.animal = "dog";

正确选项:A:代码完全合法。JavaScript 中函数也是对象,可以像普通对象一样添加属性。

第 13 题:事件传播的三个阶段

正确选项:D:Capturing > Target > Bubbling。事件传播依次经历:捕获阶段(Capturing)——事件从最外层祖先元素逐层下传至目标元素;目标阶段(Target);冒泡阶段(Bubbling)——再从目标逐层向上冒回。

第 31 题:event.target指向触发元素

<div onclick="console.log('first div')"> <div onclick="console.log('second div')"> <button onclick="console.log('button')"> Click! </button> </div> </div>

正确选项:C:button。event.target永远是事件实际发生的元素(本例中是<button>),而不是绑定处理器的元素;若需阻止事件继续传播,可调用event.stopPropagation()。

第 32 题:冒泡阶段触发顺序

<div onclick="console.log('div')"> <p onclick="console.log('p')"> Click here! </p> </div>

正确选项:A:p然后div。点击<p>时事件经历三个阶段,默认的处理器在最后的冒泡阶段触发,因此从最深的目标元素p开始,向上依次触发div。

第 22 题:sessionStorage的生命周期

sessionStorage.setItem("cool_secret", 123);

正确选项:B:用户关闭标签页时。sessionStorage中的数据在标签页关闭后被清除;而localStorage会一直保留,直到被代码显式删除。

第 42 题:setInterval的返回值

setInterval(() => console.log("Hi"), 1000);

正确选项:A:唯一的标识符(unique id)。setInterval返回一个定时器 ID,可传给clearInterval以停止该定时器的重复执行。

七、数组、错误处理与生成器补充

第 37 题:稀疏数组(empty slots)

const numbers = [1, 2, 3]; numbers[10] = 11; console.log(numbers);

正确选项:C:[1, 2, 3, 7 x empty, 11]。向超出数组长度的索引写入值时,中间未被占用的位置会形成"空槽"(empty slots),其值被视为undefined;不同浏览器控制台的展示格式略有差异(如 Chrome 显示为7 × empty)。

第 38 题:catch块的块级作用域

(() => { let x, y; try { throw new Error(); } catch (x) { (x = 1), (y = 2); console.log(x); } console.log(x); console.log(y); })();

正确选项:A:1、undefined、2。catch (x)中的x是仅存在于catch块内的局部变量,与外层let x无关:块内x被赋为 1,块外x仍是undefined;而y没有块内同名遮蔽,直接修改了外层的y为 2。

第 43 题:展开字符串

[..."Lydia"];

正确选项:A:["L", "y", "d", "i", "a"]。字符串是可迭代的,展开运算符(spread operator)会把每个字符分别放入数组元素。

英文版补充:生成器(Generator)

英文版 README.md 第 44 题以function* generator(i) { yield i; yield i * 2; }为例,展示了生成器的暂停/恢复机制:普通函数一旦执行不可中途停止,而生成器每次遇到yield便产出(yield,而非 return)当前值并暂停,调用next()后从上次停下的位置继续。第一次next()产出 10,第二次产出10 * 2 = 20。

英文版补充:Promise.race

英文版第 45 题中,两个Promise分别在 500ms 与 100ms 后 resolve,Promise.race只取第一个定论(settle)的 Promise 结果,因此输出"two"。这与事件循环的时间语义密切相关。

结语与进一步学习

埃及阿拉伯语版的 43 道题覆盖了 JavaScript 进阶面试中最常被追问的几大知识板块:变量提升与临时死区、var/let在闭包与循环中的差异、箭头函数与this的绑定、call/bind的区别、对象引用与原型链、隐式类型转换与假值列表、事件传播与事件循环、浏览器存储与定时器 API。

若想继续挑战更多题目,可以对照以下资源深化:

  • 英文原版完整 155 题:README.md
  • 标准阿拉伯语版(47 题):ar-AR/README_AR.md
  • 日语版(86 题):ja-JA/README-ja_JA.md
  • 简体中文版:zh-CN/README-zh_CN.md

建议在本地浏览器控制台或 Node.js 中逐题实际运行代码,观察输出并与解析对照,再结合 LICENSE 中的 MIT 许可自由将这些题目用于个人项目或团队分享。

  • 前端
  • 教程
  • 文档

【免费下载链接】javascript-questions

A long list of (advanced) JavaScript questions, and their explanations :sparkles:

项目地址:https://gitcode.com/GitHub_Trending/ja/javascript-questions
点击查看免费下载

相关推荐

上一篇:3个步骤快速上手B站视频解析工具:让下载B站视频变得简单高效
下一篇:深入解读 Vue 3 响应式核心包:@vue/reactivity 使用指南与源码级原理剖析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询