likes
comments
collection
share

据说只有10%的人能全部答对这5道JavaScript题目 ✨

作者站长头像
站长
· 阅读数 32

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第4篇文章,点击查看活动详情

intspirit 创建了一个JS测验,里面包含了很多js基础的题目,今天和大家分享下 TOP-5 JS 错误问题(数据基于数百位前端开发测试的结果)。

让我们一起来看看这五道题目,解析结果放在下面。大家可以花个5-10分钟时间及看下这几道题目的输出,看下自己对了几道😉😉

Top5. 默认函数参数和函数长度属性(18%的人答对)

function foo(a, b, c = 10, d) {
 console.log(foo.length)
}
 
foo(1, 2, 3, 4)

Top4. Object.defineProperty(14%的人答对)

const obj = {}
 
Object.defineProperty(obj, 'myCompany', {
  value: 'intspirit'
})
 
console.log(obj.myCompany)
delete obj.myCompany
console.log(obj.myCompany)

Top3. Array.map 和 parseInt(14%的人答对)

const numbers = ['9', '10', '11'].map(parseInt)
 
console.log(numbers)

Top2. 使用Object.create 和 Object.assign克隆对象(11%的人答对)

function User() {
  this.verified = true
}
 
const user = new User()
const admin = Object.create(user)
 
const clone1 = { ...admin }
const clone2 = Object.assign({}, admin)
 
console.log(admin.verified, clone1.verified, clone2.verified)

Top1. 字符串函数和 instanceof 运算符(8%的人答对)

var str = 'Hello'
var str2 = String('Hello')
 
console.log(str instanceof String)
console.log(str2 instanceof String)

答案解析

Top5代码解析

首先我们需要知道在ES6引入默认参数之前,函数长度属性用于返回所有函数参数长度,如下:

function foo(a, b, c, d) {
  console.log(foo.length) // 输出4
}
foo(1, 2, 3, 4)

在ES6引入默认参数之后,长度属性发生了变化,由于具有默认值的形参是可选的,因为这样的参数不包含在函数的长度中。按照常识,默认值参数后面的所有参数也是可选的。因此,它们也不包含在函数的长度属性中。所以Top5代码的结果应该是2

Top4代码解析

这一题,有些小伙伴第一反应的输出结果是 intspirit undefined,可是结果并不是这样的,这是为啥呢? 其实这题考察的是对Object.defineProperty(obj, prop, desc)参数的了解

  • obj     需要定义属性的当前对象
  • prop    当前需要定义的属性名
  • desc    描述符 一般是一个对象
Object.defineProperty(person, 'name', {
  value: '张三', // 属性值
  enumerable: false, // 控制属性是否可以枚举,默认值是false
  writable: false, // 控制属性是否可以被修改,默认值是false
  configurable: false // 控制属性是否可以被删除,默认值是false
})

可以看出 Object.defineProperty定义的属性,configurable值默认是false,意味着不可以删除,那么这一题的答案很明显了,输出intspirit intspirit

注意 :当使用了getter或setter方法,不允许使用writable和value这两个属性

Top3代码解析

首先我们要明白 Array.map 回调函数接受三个参数 currentValue, index, arrary, parseInt 只接受两个两个参数, 所以map实际上执行的代码如下:

parseInt('9', 0)
parseInt('10', 1)
parseInt('11', 2)

这里就涉及到了parseInt的第二个参数,对于第二个参数有以下几点需要注意:

  1. 参数是2~36之间的整数值,这个值其实就是我们说的进制
  2. 如果超出该范围,返回NaN
  3. 如果是0或未提供,在判定规则如下
    • 如果字符串 string 以"0x"或者"0X"开头, 则基数是16 (16进制)。
    • 如果字符串 string 以"0"开头, 基数是8(八进制)或者10(十进制),那么具体是哪个基数由实现环境决- 定。ECMAScript 5 规定使用10,但是并不是所有的浏览器都遵循这个规定。因此,最好明确给出第二个参数的值。
    • 如果字符串 string 以其它任何值开头,则基数是10 (十进制)。

看了上面对于parseInt第二个参数的解析,那么答案就很明显了 答案:[9, NaN, 3]

Top2代码解析

看看这题的代码执行过程是怎样的

  1. 通过new实例化User, 包含属性verified为true
function User() {
  this.verified = true
}
 
const user = new User()
  1. 使用 Object.create() 方法创建一个新对象 admin,使用现有对象作为新创建对象的原型
const admin = Object.create(user)
  1. 执行了两个浅拷贝:一个使用 ... 扩展运算符,另一个使用 Object.assign
const clone1 = { ...admin }
const clone2 = Object.assign({}, admin)
  1. 查看verified属性是否被拷贝:
console.log(admin.verified, clone1.verified, clone2.verified)

输出结果是:true, undefined, undefined 很明显,扩展运算符和Object.assign都没有克隆verified属性,这是因为 扩展运算符和Object.assign在克隆时都忽略了原型,这些对象的原型

admin.__proto__ User { verified: true }
clone1.__proto__ [Object: null prototype] {}
clone2.__proto__ [Object: null prototype] {}

那么,如何浅拷贝一个对象,并包括他的原型呢,如下:

const clone1 = { __proto__: Object.getPrototypeOf(admin), ...admin }
const clone2 = Object.assign(Object.create(Object.getPrototypeOf(admin)), admin)

测试结果:

据说只有10%的人能全部答对这5道JavaScript题目 ✨

Top1代码解析

有一部分人的答案是:true true 还有一部分人答案是: false true

正确的结果是false false。因为

  1. instanceof 运算符仅适用于对象。
  2. 字符 Hello 是基本数据类型,所以返回false
  3. 非构造函数上下文中的字符串调用(不使用new关键字调用)返回一个原始字符串

上面的5个问题,你答对几道了呢,欢迎大家在评论区讨论 😎😎😎

题目来源:t.me/s/intspirit