14 个易错的 JavaScript 面试题深度解析
本文深入解析 14 个高频 JavaScript 面试题,涵盖 typeof 运算符、arguments 对象特性、函数表达式与声明的区别、delete 操作符限制、赋值表达式执行顺序、this 绑定规则、逗号操作符、变量提升(hoisting)及 new 构造函数返回机制等核心概念。通过逐题拆解代码执行逻辑,帮助开发者理解底层原理,避免常见陷阱,夯实理论基础。
本文整理自一篇名为 quiz-legend 的 JavaScript 测试文章,旨在供读者学习、理解、背诵及批判性思考。
arguments 对象与 typeof 运算符
问题一
(function(){
return typeof arguments;//"object"
})();
arguments 是一个类数组对象(Array-like object),代表传入函数的参数列表,可在任何函数中直接访问。typeof 操作符仅返回字符串类型的结果。根据下表可知,不同数据类型对应的 typeof 返回值如下:

由此推断,typeof arguments 的结果为 object。
函数表达式与变量赋值的差异
问题二
var f = function g(){ return 23; };
typeof g();//报错
这是一个名为 g 的函数表达式(function expression),随后被赋值给变量 f。函数名 g 与变量 f 存在以下差异: 函数名 g 不可重新赋值,而变量 f 可以。 函数名 g 仅在函数体内部可见,在外部访问 g 会报错。
delete 操作符的限制与内存影响
问题三
(function(x){
delete x;
return x;//1
})(1);
delete 操作符用于删除对象属性,正确语法如下: delete object.property delete object['property'] delete 仅对对象属性有效,对变量和函数名无效,因此 delete x 无实际意义。
需注意,delete 不会直接释放内存,它仅间接切断对象引用。
赋值表达式的执行顺序
问题四 var y = 1, x = y = typeof x; x;//"undefined" 我们试图分解上述代码成下面两步: var y = 1; //step 1 var x = y = typeof x; //step 2 第一步应该没有异议,我们直接看第二步 1.赋值表达式从右向左执行 2.y被重新赋值为typeof x的结果,也就是undefined 3.x被赋值为右边表达式(y = typeof x)的结果,也就是undefined
问题五
(function f(f){
return typeof f();//"number"
})(function(){ return 1; });
直接通过注释解释:
(function f(f){
//这里的f是传入的参数function(){ return 1; }
//执行的结果自然是1
return typeof f(); //所以根据问题一的表格我们知道,typeof 1结果是"number"
})(function(){ return 1; });
函数调用中的 this 指向问题
问题六
var foo = {
bar: function() { return this.baz; },
baz: 1
};
(function(){
return typeof arguments[0]();//"undefined"
})(foo.bar);
此处易误认为结果是 number。向函数传递参数本质是赋值,因此 arguments[0] 获取的是 bar 函数的实际值,而非 foo.bar 的引用。此时 this 指向 window 而非 foo。
问题七
var foo = {
bar: function(){ return this.baz; },
baz: 1
}
typeof (f = foo.bar)();//"undefined"
此题与上一题原理相同,(f = foo.bar) 返回的是 bar 函数的值而非引用,因此 this 不指向 foo。
逗号操作符与返回值
问题八
var f = (function f(){ return '1'; }, function g(){ return 2; })();
typeof f;//"number"
逗号操作符从左至右对每个操作对象求值,并返回最后一个操作对象的值。
因此 (function f(){ return '1'; }, function g(){ return 2; }) 返回函数 g,执行后结果为 2;最后 typeof 2,根据问题一的表格,结果自然是 number。
函数表达式的作用域限制
问题九
var x = 1;
if (function f(){}) {
x += typeof f;
}
x;//"1undefined"
此题关键点在于问题二中提到的:函数表达式中的函数名 f 不能在函数体外部访问。
变量声明与 typeof 的嵌套使用
问题十
var x = [typeof x, typeof y][1];
typeof typeof x;//"string" 1.因为没有声明过变量y,所以typeof y返回"undefined"
2. 将 typeof y 的结果赋值给 x,即 x 现为 "undefined" 3. typeof x 结果为 "string" 4. typeof "string" 的结果仍为 "string"。
问题十一
(function(foo){
return typeof foo.bar;//"undefined"
})({ foo: { bar: 1 } });
这是一个纯粹的视觉陷阱,见注释。
(function(foo){
//这里的foo,是{ foo: { bar: 1 } },并没有bar属性哦。
//bar属性是在foo.foo下面
//所以这里结果是"undefined"
return typeof foo.bar;
})({ foo: { bar: 1 } });
函数声明提升(Hoisting)机制
问题十二
(function f(){
function f(){ return 1; }
return f();//2
function f(){ return 2; }
})();
通过 function declaration 声明的函数可在声明前使用,此特性称为 hoisting(提升)。因此上述代码实际被解释为:
(function f(){
function f(){ return 1; }
function f(){ return 2; }
return f();
})();
new 构造函数与返回值覆盖
问题十三
function f(){ return f; }
new f() instanceof f;//false
当代码 new f() 执行时,发生以下过程: 1. 创建一个新对象,继承自 f.prototype。 2. 执行构造函数 f,传入相应参数,并将上下文 (this) 指定为该新实例。new f() 等同于 new f(),仅适用于不传参情况。 3. 若构造函数返回一个“对象”,则该对象取代 new 产生的结果;若未返回对象,则返回步骤 1 创建的对象。
注:通常构造函数不返回值,但若用户希望覆盖返回值,可返回普通对象(数组也是对象,同样有效)。
因此,此处 new f() 返回的是函数 f 本身,而非其实例。
with 语句与函数 length 属性
问题十四 with (function(x, undefined){}) length;//2 with 语句将对象添加到作用域链顶部。若 statement 中存在未使用命名空间的变量且与作用域链中某属性同名,则该变量指向该属性值;若无同名属性,则抛出 ReferenceError 异常。
分析可知,function(x, undefined){} 是匿名函数表达式,作为函数具有 length 属性,表示参数个数。因此最终结果为 2。
写在最后
有人视这些题为坑爹,有人觉得开阔眼界,见仁见智。但有一件事是确定的:无论是否坚定实践派,缺乏理论基础注定走不远——你绝不会见到熟练技工突然成为火箭专家。
查阅文档、研读标准、结合实践,才是决胜之道。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
JavaScript新手常犯的编码错误与最佳实践指南
2026-11-04 22:12:38
相关标签:
