百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

40道前端基础题你能答对几道?附有答案解析

lipiwang 2024-10-16 13:10 22 浏览 0 评论

在三大框架盛行的时代, 基本上会个Vue就能在小公司浑水摸鱼。但是当想突破的时候就会意识到基础的重要性。

JavaScript中有很多重要特性及概念。比如原型,原型链,this,闭包,作用域,隐式转换等等。如果不能熟练掌握,在进阶中级前端开发工程师的道路上必定是困难重重。

用一个小时把这些题做完。检测一下你的基础掌握程度。

进入正题

第 1 题

if(false){
    var a = 1;
    let b = 2;
}
console.log(a);
console.log(b);

解析:

// 输出
undefined
ReferenceError: b is not defined

var不会产生块级作用域,let会产生块级作用域。

伪代码相当于:

var a;if(false){    a = 1;let b = 2;}console.log(a); console.log(b);

第 2 题

var a;
if(false){
    a = 1;
let b = 2;
}
console.log(a); 
console.log(b);

解析:

// 输出
ReferenceError: Cannot access 'a' before initialization

let声明的变量不会提升,并且会产生暂存死区。在let声明变量之前访问变量会抛出错误。

第 3 题

var a = {n: 1}
var b = a
a.x = a = {n: 2}
console.log(a.n, b.n);
console.log(a.x, b.x);

解析:

// 输出
2 1undefined {n: 2}
var b = a,此时a和b指向同一个对象。
.运算符比 = 运算符高,先计算`a.x`,此时 
b = {
n:1,
x:undefined
}
相当于给对象添加了x属性。
a.x = a = {n:2};
计算完a.x,再计算 = ,赋值是从右向左,此时a指向一个新对象。
a = {
n:2
}
a.x已经执行过了,此时对象的x属性赋值为a,此时
对象 = {
n:1,
x:{
n:2
}
}
即:
a = {
n:2
}
b = {
n:1,
x:{
n:2
}
}

第 4 题

console.log(c);
var c;
function c(a) {
    console.log(a);
    var a = 3;
    function a(){
    }
}
c(2);

解析:

// 输出 

function c(a){
    console.log(a);
    var a = 3;
    function a(){
    }
}

function a(){
}

变量提升也有优先级, 函数声明 > arguments > 变量声明。

第 5 题

var c = 1;
function c(c) {
    console.log(c);
var c = 3;
}
console.log(c);
c(2);

解析:


/  输出
1
TypeError: c is not a function

由于函数声明会提升,当函数外的console.log?执行时,c已经被赋值为1。因此,执行c(2)时会抛出TypeError,因为1不是函数。


第 6 题

var name = 'erdong';
(function () {
if (typeof name === 'undefined') {
var name = 'chen';
console.log(name);
    } else {
console.log(name);
    }
})();

解析:

// 输出
chen

自执行函数执行时,会先进行变量提升(这里涉及到执行上下文不过多说,一定要搞懂执行上下文),在自执行函数执行时,伪代码为:

var name = 'erdong';
(function () {
var name;  // 变量name会提升到当前作用域顶部
if (typeof name === 'undefined') {
        name = 'chen'
console.log(name)
    } else {
console.log(name)
    }
})();

所以会执行if中的console.log(name)

第 7 题

var a = 10;  
function test() {  
    a = 100;  
console.log(a);  
console.log(this.a);  
var a;  
console.log(a); 
}
test();

解析:


// 输出
10010100

test()为函数独立调用,作用域中的this绑定为全局对象window。

test函数执行时,var a被提升到了作用域顶部,因此函数作用域中存在一个变量a。所以在函数中访问的a都是局部作用域中的a。

第 8 题

if (!('a' in window)) {
var a = 1;
}
console.log(a);

解析:

// 输出
undefined

由于if后的{}不会产生块级作用域(不包含let,const时),此时的伪代码为:

var a;
if (!(a in window)) {
    a = 1;
}
console.log(a);

var a相当于window.a。因此!(a in window)转成布尔值为false,不会执行a = 1。所有console.log(a)输出undefined。

第 9 题

var a = 1;

function c(a, b) {
    console.log(a);
    a = 2;
    console.log(a);
}
c();

解析:

//输出
undefined 
2

跟第4题类似。

第 10 题

var val=1;
var obj={
val:2,
    del:function(){
        console.log(this);                    
this.val*=2;
        console.log(val);
    }
}
obj.del();

解析:

// 输出
obj(指向的值)
1

当通过obj.del()调用del函数时,del函数作用域中的this绑定为obj。

在函数作用域中访问val时,由于函数中并没有变量val,因此实际上访问的是全局作用域中的val,即 1。

这里考察的是this的指向,一定要熟练掌握。

第 11 题:

var name = "erdong";
var object = {
    name: "chen",
    getNameFunc: function () {
        return function () {
            return this.name;
        }
    }
}
console.log(object.getNameFunc()());

解析:

// 输出
erdong

object.getNameFunc()(),先执行object.getNameFunc()返回一个函数:

function () {
return this.name;
}

返回的函数再执行,相当于

(function () {
return this.name;
})();

此时的this绑定为window。因此输出全局变量name的值erdong。

第 12 题

var name = "erdong";
var object = {
name: "chen",
getNameFunc: function () {
var that = this;
return function () {
return that.name;
        }
    }
}
console.log(object.getNameFunc()());

解析:

//输出
chen

object.getNameFunc()执行时,此时getNameFunc中的this绑定为object,因此that = object。object.getNameFunc()返回的函数在执行时,产生闭包,因此返回的函数也能访问到外层作用域中的变量that,因此object.name为object.name,即 chen。

第 13 题

(function() {
  var a = b = 3;
})();
console.log(typeof a === 'undefined');
console.log(typeof b === 'undefined');

解析:

// 输出
true
false

首先要明白var a = b = 3是怎样执行的,伪代码:

b = 3;var a = b;

因此在自执行函数执行时,b由于未经var等操作符声明,为全局变量。a为函数作用域中的局部变量。因此在外面访问a和b时,其值分别为ReferenceError: a is not defined和3。但是typeof检测未声明的变量不会抛出错误,会返回’undefined’。因此typeof a和typeof b分别返回’undefined’和’number’。

第 14 题

var a = 6;
setTimeout(function () {
    a = 666;
}, 0)
console.log(a);

解析:

//输出
6

setTimeout为宏任务。即使设置延迟为0ms,也是等待同步代码执行完才会执行。因此console.log(a)输出 6

第 15 题

function fn1() {
    var a = 2;
    function fn2 () {
      a++;
      console.log(a);
    }
    return fn2;
}
var f = fn1();
f();
f();

解析:

// 输出
34

由于fn1函数执行后返回函数fn2,此时产生了闭包。因此fn2中a访问的是fn1作用域中的变量a,因此第一次a++,之后a为3,第二次之后a为4。

第 16 题

var a = (function(foo){
    return typeof foo.bar;
})({foo:{bar:1}});

console.log(a);

解析

//输出
undefined

实参foo的值为{foo:{bar:1},因此typeof foo.bar为undefined。

typeof foo.foo.bar为number。

第 17 题

function f(){
    return f;
}
console.log(new f() instanceof f);

解析:

//输出
false

由于构造函数f的返回值为f。因此new f()的值为f。所以console.log(new f() instanceof f)为console.log(f instanceof f),即 false。

第 18 题

function A () {
}
A.prototype.n = 1;
var b = new A();
A.prototype = {
n: 2,
m: 3
}
var c = new A();
console.log(b.n, b.m);
console.log(c.n, c.m);

解析:

// 输出
1,undefined
2,3

var b = new A(); 实例化b时,A的prototype为

A.prototype = {
constructor:A,
n:1
}

当访问b.n和b.m时,通过原型链找到A.prototype指向的对象上,即b.n = 1,b.m = undefined。

var c = new A(); 实例化c时,A的prototype为

A.prototype = {
n: 2,
m: 3
}

当访问a.n和a.m时,通过原型链找到A.prototype指向的对象上,此时A.prototype重写,因此a.n = 2,b.m = 3。


第 19 题

var F = function(){};
var O = {};
Object.prototype.a = function(){
console.log('a')
}
Function.prototype.b = function(){
console.log('b')
}
var f = new F();
F.a();  
F.b();  
O.a();
O.b();

解析:

// 输出
a
b
a
TypeError: O.b is not a function

F为函数,它也能访问Object原型上的方法,O为对象,不能访问Function原型上的方法。

F的原型链为:

F => F.__proto__ => Function.prototype => Function.prototype.__proto__ => Object.prototype

由于Object.prototype在F的原型链上,所以F能访问Object.prototype上的属性和方法。即: F.a(),F.b()能正常访问。

O的原型链为:

O => O.__proto__ => Object.prototype

由于Function.prototype不在O的原型链上,因此O不能访问Function.prototype上的方法,即O.b()抛出错误。

如果你对原型和原型链掌握的好,试着理解下面的示例:

console.log(Object instanceof Function);
console.log(Function instanceof Object);
console.log(Function instanceof Function);

第 20 题

function Person() {
    getAge = function () {
console.log(10)
    }
return this;
}
Person.getAge = function () {
console.log(20)
}
Person.prototype.getAge = function () {
console.log(30)
}
var getAge = function () {
console.log(40)
}
function getAge() {
console.log(50)
}
Person.getAge();
getAge();
Person().getAge();
new Person.getAge();
getAge();
new Person().getAge();

解析:

/ 输出
20
40
10
20
10
30

Person.getAge();此时执行的是Person函数上getAge方法。

Person.getAge = function () {
console.log(20)
}

所以输出:20。

getAge();此时执行的是全局中的getAge方法。此时全局getAge方法为:

function () {
console.log(40)
}

所以输出:40。

Person().getAge();由于Person()单独执行所以,作用域中的this绑定为window,相当于window.getAge()。同上,执行的都是全局getAge 方法,但是Person执行时,内部执行了。

getAge = function () {
console.log(10)
}

因此全局getAge方法现在为:

function () {
console.log(10)
}

所以输出:10。

new Person.getAge();此时相当于实例化Person.getAge这个函数,伪代码:

var b = Person.getAge;
new b();

所以输出:20

getAge();执行全局getAge方法,由于在Person().getAge()执行时把全局getAge方法赋值为:

function () {
console.log(10)
}

所以输出:10。

new Person().getAge();此时调用的是Person原型上的getAge方法:

Person.prototype.getAge = function () {
console.log(30)
}

所以输出:30。

// 这里要注意:1.变量提升及提升后再赋值。2.调用构造函数时,带()和不带()的区别。

第 21 题

console.log(false.toString()); 
console.log([1, 2, 3].toString()); 
console.log(1.toString()); 
console.log(5..toString());

解析:

// 输出
'false'
'1,2,3'
Uncaught SyntaxError: Invalid or unexpected token
'5'

当执行1.toString();时,由于1.也是有效数字,因此此时变成(1.)toString()。没有用.调用toString方法,因此抛出错误。

正确的应该是:

1..toString();1 .toString();(1).toString();

第 22 题

console.log(typeof NaN === 'number');

解析:


//输出
true

NaN为不是数字的数字。虽然它不是数字,但是它也是数字类型。


第 23 题

console.log(1 + "2" + "2");
console.log(1 + +"2" + "2");
console.log(1 + -"1" + "2");
console.log(+"1" + "1" + "2"); 
console.log( "A" - "B" + "2"); 
console.log( "A" - "B" + 2);

解析:

//输出

'122'
'32'
'02'
'112'
'NaN2'
NaN

首先要明白两点:

  1. +a,会把a转换为数字。-a会把a转换成数字的负值(如果能转换为数字的话,否则为NaN)。
  2. 字符串与任何值相加都是字符串拼接。

console.log(1 + “2” + “2”);简单的字符串拼接,即结果为:‘122’。

console.log(1 + +“2” + “2”);这里相当于console.log(1 + 2 + “2”);,然后再字符串拼接。即结果为:‘32’。

console.log(1 + -“1” + “2”);这里相当于console.log(1 + -1 + “2”);,然后再字符串拼接。即结果为:‘02’。

console.log(+“1” + “1” + “2”);这里相当于console.log(1 + “1” + “2”);,然后再字符串拼接。即结果为:‘112’。

console.log( “A” - “B” + “2”);,由于’A’ - ‘B’ = NaN,所以相当于console.log( NaN + “2”);, 然后再字符串拼接。即结果为:‘NaN2’。

console.log( “A” - “B” + 2);同上,相当于console.log(NaN + 2),由于NaN+任何值还是NaN,即结果为:NaN。

第 24 题

var a = 666;console.log(++a);console.log(a++);console.log(a);

解析:

// 输出
667
667
668

++a先执行+1操作,再执行取值操作。此时a的值为667。因此输出667。

a++先执行取值操作,再执行+1。此时输出667,随后a的值变为668。

–a和a–同理。

使用这类运算符时要注意:

1)这里的++、–不能用作于常量。比如

1++; // 抛出错误

2)如果a不是数字类型,会首先通过Number(a),将a转换为数字。再执行++等运算。

第 25 题

console.log(typeof a);
function a() {}
var a;
console.log(typeof a);

解析:

// 输出
'function'
'function'

跟第4题类似。函数会优先于变量声明提前。因此会忽略var a。

第 26 题

var a;
var b = 'undefined';
console.log(typeof a);
console.log(typeof b);
console.log(typeof c);

解析:

// 输出
'undefined'
'string'
'undefined'

a为声明未赋值,默认为undefined,b的值为字符串’undefined’,c为未定义。

typeof一个未定义的变量时,不会抛出错误,会返回’undefined’。注意typeof返回的都是字符串类型。

第 27 题

var x = 1;
if(function f(){}){
    x += typeof f;
}
console.log(x);

解析:

//输出
1undefined

function f(){}当做if条件判断,其隐式转换后为true。但是在()中的函数不会声明提升,因此f函数在外部是不存在的。因此typeof f = ‘undefined’,所以x += typeof f,相当于x = x + ‘undefined’为’1undefined’

第 28 题

var str = "123abc";
console.log(typeof str++);

解析:

// 输出
'number'

在24题解析时提到,使用++运算符时(无论是前置还是后置),如果变量不是数字类型,会首先用Number()转换为数字。因此typeof str++相当于typeof Number(str)++。由于后置的++是先取值后计算,因此相当于typeof Number(“123abc”)。即typeof NaN,所以输出’number’。

第 29 题

console.log('b' + 'a' + +'a'+'a');

解析:


// 输出
baNaNa

‘b’ + ‘a’ + +‘a’+‘a’相当于’ba’ + +‘a’+‘a’,+‘a’会将’a’转换为数字类型,即+‘a’ = NaN。所以最终得到’ba’ + NaN +‘a’,通过字符串拼接,结果为:baNaNa


第 30 题

var obj = {n: 1};function fn2(a) {    a.n = 2;}fn2(obj);console.log(obj.n);

解析:

// 输出
2

函数传递参数时,如果是基本类型为值传递,如果是引用类型,为引用地址的值传递。其实都是值传递。因此形参a和obj引用地址相同,都指向同一个对象。当执行a.n,实际上共同指向的对象修改了,添加了个n属性,因此obj.n为2。

第 31 题

var x = 10;
function fn() {
console.log(x);
}
function show(f) {
var x = 20;
    f();
}
show(fn);

解析:

// 输出
10

JavaScript采用的是词法作用域,它规定了函数内访问变量时,查找变量是从函数声明的位置向外层作用域中查找,而不是从调用函数的位置开始向上查找。因此fn函数内部访问的x是全局作用域中的x,而不是show函数作用域中的x。

第 32 题

Object.prototype.bar = 1; 
var foo = {
    goo: undefined
};
console.log(foo.bar);
console.log('bar' in foo);
console.log(foo.hasOwnProperty('bar'));
console.log(foo.hasOwnProperty('goo'));

解析:

//输出
1
true
false
true

in操作符:检测指定对象(右边)原型链上是否有对应的属性值。

hasOwnProperty方法:检测指定对象自身上是否有对应的属性值。两者的区别在于in会查找原型链,而hasOwnProperty不会。

示例中对象foo自身上存在goo属性,而它的原型链上存在bar属性。

通过这个例子要注意如果要判断foo上是否有属性goo,不能简单的通过if(foo.goo){}判断,因为goo的值可能为undefined或者其他可能隐式转换为false的值。

第 33 题

Object.prototype.bar = 1;var foo = {    moo: 2};for(var i in foo) {    console.log(i); }

解析:

// 输出
'moo''bar'

for…in…遍历对象上除了Symbol以外的可枚举属性,包括原型链上的属性。

第 34 题

function foo1() {
    return {
        bar: "hello"
    };
}
function foo2() {
    return 
    {
        bar: "hello"
    };
}
console.log(foo1());
console.log(foo2());

解析:

// 输出
{ bar: "hello" }
undefined

两个函数唯一区别就是return后面跟的值,一个换行一个不换行。

当我们书写代码时忘记在结尾书写;时,JavaScript解析器会根据一定规则自动补上;。

return
{
    bar: "hello"
}
=> 会被解析成
return;
{
    bar: "hello"
};

因此函数执行后会返回undefined。

第 35 题

console.log((function(){ return typeof arguments; })());

解析:

// 输出
'object'

arguments为类数组,类型为object。因此typeof arguments = ‘object’。


第 36 题

console.log(Boolean(false));
console.log(Boolean('0'));
console.log(Boolean(''));
console.log(Boolean(NaN));

解析:

//输出

false
true
false
fasle

只有下面几种值在转换为布尔值时为false:

+0,-0,NaN,false,'',null,undefined。

除此之外的值在转换为布尔值的时候全部为true。

第 37 题

console.log(Array(3));
console.log(Array(2,3));

解析:

// 输出

[empty × 3] 

[2,3]

使用Array()创建数组时,要注意传入的值的类型和数量。

第 38 题

console.log(0.1 + 0.2 == 0.3);

解析:

// 输出
false

第 39 题

var a=[1, 2, 3];
console.log(a.join());

解析:

//输出
1,2,3

join方法如果省略参数,默认以,分隔。

第 40 题

var a = [3];
var b = [1];
console.log(a - b);

解析:

// 输出
2

在执行a - b时,a和b都要转换为数字。首先a先转换为字符串,[3] => [3].toString() => ‘3’,然后Number(3) => 3。b同理。因此转换之后为3 - 1 = 2。

最后

如果文中有错误,请务必留言指正,感谢你的阅读,喜欢就点个赞哦!

让我们共同学习,共同进步。

相关推荐

一个简单便捷搭建个人知识库的开源项目(MDwiki)

这里我通过自动翻译软件,搬运总结MDwiki官网的部署和使用方法。第一步:下载编译好的后MDwiki文件,只有一个HTML文件“mdwiki.html”。第二步:在mdwiki.html同级目录创建“...

强大、简洁、快速、持续更新 PandaWiki新一代 AI 驱动的开源知识库

PandaWiki是什么PandaWiki是一款AI大模型驱动的开源知识库搭建系统,帮助你快速构建智能化的产品文档、技术文档、FAQ、博客系统,借助大模型的力量为你提供AI创作、AI问答...

DeepWiki-Open: 开源版Deepwiki,可自己构建github文档库

Deepwiki是Devin团队开发的github文档库,用户能免费使用,但代码不是开源,而DeepWiki-Open侧是开源版本的实现。DeepWiki-Open旨在为GitHub和GitLa...

最近爆火的wiki知识管理开源项目PandaWiki

项目介绍PandaWiki是一款AI大模型驱动的开源知识库搭建系统,帮助你快速构建智能化的产品文档、技术文档、FAQ、博客系统,借助大模型的力量为你提供AI创作、AI问答、AI搜索等...

轻量级开源wiki系统介绍(轻量开源论坛系统)

wiki系统有很多DokuWiki、MediaWiki、MinDoc等等都是开源的wiki系统。商业版的wiki,像很多企业在用的confluence等。今天我们讲的是一款轻量级且开源的文档管理系统:...

DNS解析错误要怎么处理(dns解析状态异常怎么办)

在互联网时代,网络已经成为人们生活和工作中不可或缺的一部分。然而,当遇到DNS解析错误时,原本畅通无阻的网络访问会突然陷入困境,让人感到十分困扰。DNS,即域名系统,它如同互联网的电话簿,将人们易于...

网页加载慢?这些方法让你秒开网页!

打开浏览器,信心满满地准备查资料、看视频或者追剧,却发现网页怎么都打不开!是不是瞬间感觉手足无措?别慌,这个问题其实挺常见,而且解决起来并没有你想象的那么复杂。今天就来聊聊网页打不开究竟是怎么回事,以...

windows11 常用CMD命令大全(windows11msdn)

Windows11中的命令提示符(CMD)是一个强大的工具,可以通过命令行执行各种系统操作和管理任务。以下是一些常用的CMD命令,按功能分类整理,供你参考:一、系统信息与状态systeminfo显...

电脑提示DNS服务器未响应怎么解决?

我们在使用电脑的时候经常会遇到各种各样的网络问题,例如最近就有Win11电脑用户在使用的时候遇到了DNS未响应的问题,遇到这种情况我们应该怎么解决呢?  方法一:刷新DNS缓存  1、打开运行(W...

宽带拨号错误 651 全解析:故障定位与修复方案

在使用PPPoE拨号连接互联网时,错误651提示「调制解调器或其他连接设备报告错误」,通常表明从用户终端到运营商机房的链路中存在异常。以下从硬件、系统、网络三层维度展开排查:一、故障成因分类图...

如何正确清除 DNS 缓存吗?(解决你访问延时 )

DNS缓存是一个临时数据库,用于存储有关以前的DNS查找的信息。换句话说,每当你访问网站时,你的操作系统和网络浏览器都会保留该域和相应IP地址的记录。这消除了对远程DNS服务器重复查询的...

网络配置命令:ipconfig和ifconfig,两者有啥区别?

在计算机网络的世界里,网络接口就像是连接你电脑和外部网络的桥梁,而网络配置则是确保这座桥梁稳固、通信顺畅的关键。提到网络配置工具,ipconfig和ifconfig绝对是两个绕不开的名字。它们一...

救急的命令 你会几个?(救急一下)

很多人都说小编是注册表狂魔,其实不完全是,小编常用的命令行才是重点。其实所谓的命令行都是当初DOS时代的标准操作方式,随着Windows不断演化,DOS的命令早已成为Windows的一部分了——开始菜...

电脑有网却访问不了GitHub原来是这样

当满心欢喜打开电脑,准备在GitHub这个“开源宝藏库”里挖掘点超酷的项目,却遭遇了网页无法访问的尴尬。看着屏幕上那令人无奈的提示,原本高涨的热情瞬间被泼了一盆冷水,是不是感觉世界都不美好了...

rockstargames更新慢| r星更新速度 怎么办 解决办法

rockstargames更新慢|r星更新速度怎么办解决办法说到RockstarGames,那可是游戏界的大佬,作品个顶个的经典。但话说回来,每当新内容更新时,那蜗牛般的下载速度,真是让人急得...

取消回复欢迎 发表评论: