有趣的前端面试题——后篇:答案篇

本文为——后篇:答案篇,只想看题目可见

有趣的前端面试题——前篇:题目篇

1.看代码得结果 题1

var a = 1
if (true) {
  console.log(a)
  let a = 2
}

结果:ReferenceError: Cannot access ‘a’ before initialization // 初始化之前无法访问 ‘a’

考点:暂时性死区

分析:如果区块中存在 let 和 const 命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域,这种现象就叫 “暂时性死区”。其本质就是,只要进入当前作用域,所要使用的变量就已经存在,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

2.看代码得结果 题2

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 1
undefined {n: 2}

考点:浅拷贝,连等操作,运算符优先级

分析:真实的执行过程为如下
b = a 为浅拷贝,即 a 和 b 为同一个对象。
a.x = a = {n: 2},由于 . 运算符的优先级高于 =,所以先为 a 添加 x 属性,所以此时 a、b 都为 {n: 1, x: undefined}
连等操作是先执行右边,即 a = {n: 2},然后执行 a.x = a
此时,问题来了,大家会以为 a 为 {n: 2, x: {n: 2}},其实不然。因为 a.x 已经在前面进行赋值了,所以不再执行。此时 a 为新对象 {n: 2}
a.x = a 的赋值操作 = 还未执行,b 还指向旧对象,所以 b 应该等于 {n: 1, x: {n: 2}}

3.看代码得结果 题3

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

结果
1
TypeError: c is not a function

考点:变量提升,函数声明提升

分析:以上代码的真实执行过程为

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

4.看代码得结果 题4

(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 未声明,所以为全局变量。a 为函数局部作用域中的局部变量。因此,在外部访问 a 时会报 ReferenceError: a is not defined,访问 b 时为 3。但是 typeof 检测未声明的变量不会抛出错误,会返回 ‘undefined’。因此 typeof a 和 typeof b 分别返回 ‘undefined’ 和 ‘number’。

5.看代码得结果 题5

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

结果:false

考点:考细节

分析:容易写成 true。这里主要是 new f() 会返回 f 函数,而不是 f 实例。

6.看代码得结果 题6

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()
这个返回 20 没啥问题。

getAge()
这个我们就要看代码中到底执行的谁了。涉及到变量提升、函数声明提升。

// 函数表达式
var getAge = function () {
  console.log(40)
}
// 函数声明
function getAge() {
  console.log(50)
}

这段代码等价于

var getAge
function getAge() {
  console.log(50)
}
getAge = function () {
  console.log(40)
}

所以输出的结果是 40。

Person().getAge()

这个过程可分为两步,第一步执行 Person(),第二步调用 getAge() 方法。
第一步会将 window 上的 getAge() 方法赋值为输出 10 的方法,然后返回 this(这里为 window)。第二步,调用 getAge() 方法,即调用 window 上的 getAge() 方法。因此,最后输出 10。

new Person.getAge()

注意,这里 new 的是 Person.getAge() 方法,所以输出的 20。

getAge()

这里输出 10,是因为 window 上的 getAge() 方法在 Person().getAge() 时重新赋值了。

new Person().getAge()

这里是先 new Person(),在调用 getAge() 方法。由于 new 出来的实例并没有 getAge() 方法,所以只能去原型上找,因此,最后输出 30。

7.看代码得结果 题7

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.字符串与任何值相加都是字符串拼接;
2.+a 会把 a 转换为数字,-a 会把 a 转换成数字的负值 (如果能转换为数字的话,否则为 NaN);

8.看代码得结果 题8

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

结果
‘function’
‘function’

考点:函数声明提升、变量提升

分析:函数会优先于变量声明提前,因此会忽略 var a

9.看代码得结果 题9

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’。

10.看代码得结果 题10

var b = 10;
(function b(){
    b = 20;
    console.log(b); 
})();

结果
ƒ b(){
b = 20;
console.log(b);
}

考点
非匿名自执行函数,函数名只读

分析
非匿名自执行函数,函数名只读。这里大家会以为把 function b 赋值为 20 或者把全局环境中的 b 赋值为 20,其实这里的 b = 20 并不会生效,如果要设置 window 上的 b,可以这么做

var b = 10;
(function b() {
    window.b = 20; 
    console.log(b); // [Function b]
    console.log(window.b); // 20
})();

11.看代码得结果 题11

var obj = {
    '2': 3,
    '3': 4,
    'length': 2,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)

结果
在这里插入图片描述

考点:类数组?

分析

  • 使用第一次 push,obj 对象的 push 方法设置 obj[2] = 1; obj.length += 1
  • 使用第二次 push,obj 对象的 push 方法设置 obj[3] = 2; obj.length += 1
  • 使用 console.log 输出的时候,因为 obj 具有 length 属性和 splice 方法,故将其作为数组进行打印
  • 打印时因为数组未设置下标为 0 1 处的值,故打印为 empty,obj[0] 获取为 undefined

12.看代码得结果 题12

var a = {}, b = {key:'123'}, c = {key:'456'};  
a[b] = 'b';
a[c] = 'c';  
console.log(a[b]);

结果
c

考点:对象的键名的转换

分析
对象的键名只能是字符串和 Symbol 类型,其他类型的键名会被转换成字符串类型,对象转字符串默认会调用 toString() 方法。b 和 c 都会通过 toString() 转换成字符串 "[object Object]",所以 a[c] 会覆盖 a[b]。

13.看代码得结果 题13

function changeObjProperty(o) {
  o.siteUrl = "http://www.baidu.com"
  o = new Object()
  o.siteUrl = "http://www.google.com"
} 
let webSite = new Object();
changeObjProperty(webSite);
console.log(webSite.siteUrl);

结果
http://www.baidu.com

考点:对象形参

分析

// webSite 引用地址的值 copy 给 o 了
function changeObjProperty(o) {
  // 改变对应地址内的对象属性值
  o.siteUrl = "http://www.baidu.com"
  // 变量 o 指向新的地址, 以后的变动和旧地址无关
  o = new Object()
  o.siteUrl = "http://www.google.com"
} 

14.代码题 —— 接受参数 n = 5,不用 for 循环输出数组 [1, 2, 3, 4, 5]

思路:这题问题在于如何不使用 for 循环去进行迭代数据。我们应该想到 递归 + 闭包 的方式进行实现。

考点:递归 + 闭包

代码实现

const addArr = (function () {
  const arr = []
  return function (i) {
    arr.unshift(i--)
    i !== 0 && addArr(i)
    return arr
  }
})()

addArr(5)

参考链接

这些前端基础题你能答对几道?(测试你的基础掌握,附答案解析)

壹题

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值