每日五道前端面试题--day4

如果你最近想要换工作或者巩固一下自己的前端知识基础,不妨和我一起参与到每日刷题的过程中来,如何?

第四天要刷的面试题如下:

  1. 叙述+操作符的计算规则

  2. bigint类型的作用

  3. 对比扩展运算符和Object.assign

  4. 说说const的原理及其可修改性

  5. 如果尝试new一个箭头函数会怎么样

下面是我的一些理解:

1.1 与数字做加法隐式转换规则

测试程序如下:

const a = [undefined, null, 0, '3', 123n, Symbol(0), true, {}];

function testPrimitiveValue(_x){
    _x.forEach(i=>{
        try {console.log(2+i)} catch(e) {console.log(e)}
    })
}

function testValueOf(_x){
    _x.forEach(i=>{
        try {console.log(2+{valueOf(){return i}})} catch(e) {console.log(e)}
    })
}

function testToString(_x){
    _x.forEach(i=>{
        try {console.log(2+{toString(){return i}})} catch(e) {console.log(e)}
    })
}

function testPropToString(_x){
    _x.forEach(i=>{
        try {console.log(2+{})} catch(e) {console.log(e)}
    })
}



    NaN
    2
    2
    23
    Cannot mix BigInt and other types, use explicit conversions
    Cannot convert a Symbol value to a number
    3
    2[object Object]
 */



    NaN
    2
    2
    23
    TypeError: Cannot mix BigInt and other types, use explicit conversions
    TypeError: Cannot convert a Symbol value to a number
    3
    2[object Object]
 */



    NaN
    2
    2
    23
    Cannot mix BigInt and other types, use explicit conversions
    Cannot convert a Symbol value to a number
    3
    Cannot convert object to primitive value
 */



    2[object Object]
    2[object Object]
    2[object Object]
    2[object Object]
    2[object Object]
    2[object Object]
    2[object Object]
    2[object Object]
 */



结论

与数字做加法运算,会尝试将另外一个操作数转成number类型:

  1. 如果另外一个操作数是primitive value则:

  • undefined -> NaN

  • null -> 0

  • number -> 不用转换

  • string -> 优先级高于number不会转换(反而是另一个number操作数会被转成string类型的)

  • bigint -> 仍为bigint(而不是number),证明: console.log(2n+{valueOf(){return 1n}}); // 3n

  • symbol -> 报错:Cannot convert a Symbol value to a number

  • boolean -> 0或者1

  • object -> ↓↓↓↓↓↓

  1. 如果另外一个操作数是object则检查valueOf方法的返回值:

  • undefined -> NaN

  • null -> 0

  • number -> 不用转换

  • string -> 优先级高于number不会转换(反而是另一个number操作数会被转成string类型的)

  • bigint -> 仍为bigint(而不是number),证明: console.log(2n+{valueOf(){return 1n}}); // 3n

  • symbol -> 报错:Cannot convert a Symbol value to a number

  • boolean -> 0或者1

  • object -> ↓↓↓↓↓↓

  1. 如果另外一个操作数是object并且valueOf方法不存在则检查toString方法的返回值:

  • undefined -> NaN

  • null -> 0

  • number -> 不用转换

  • string -> 优先级高于number不会转换(反而是另一个number操作数会被转成string类型的)

  • bigint -> 仍为bigint(而不是number),证明: console.log(2n+{valueOf(){return 1n}}); // 3n

  • symbol -> 报错:Cannot convert a Symbol value to a number

  • boolean -> 0或者1

  • object -> Cannot convert object to primitive value 可以看出来,toString方法的返回指检查和valueOf返回值的检查方法基本上一致,但是如果toString方法还是返回引用类型的话,那就是给机会不中用了!

  1. 如果另外一个操作数是object并且valueOf、toString方法都不存在 这种情况下返回值出奇的统一就是将2和Object.prototype.toString.call(x)的拼接值

总结一下: 如果另外一个操作数x是primitive value则x一定会向number类型尝试转换,记住每一种转换的结果即可; 如果x是引用类型的,则先查valueOf的存在性和其返回值,再查toString的存在性和返回值,最后由Object.prototype.toString.call(x)结束。

1.2 与字符串做加法隐式转换规则

测试程序如下:

const a = [undefined, null, 0, '3', 123n, Symbol(0), true, {}];

function testPrimitiveValue(_x){
    _x.forEach(i=>{
        try {console.log(""+{valueOf(){return i}})} catch(e) {console.log(e)}
    })
}

function testValueOf(_x){
    _x.forEach(i=>{
        try {console.log(""+{valueOf(){return i}})} catch(e) {console.log(e)}
    })
}

function testToString(_x){
    _x.forEach(i=>{
        try {console.log(""+{toString(){return i}})} catch(e) {console.log(e)}
    })
}

function testPropToString(_x){
    _x.forEach(i=>{
        try {console.log(""+{})} catch(e) {console.log(e)}
    })
}



    undefined
    null
    0
    3
    123
    Cannot convert a Symbol value to a string
    true
    [object Object]
 */



    undefined
    null
    0
    3
    123
    Cannot convert a Symbol value to a string
    true
    [object Object]
 */



    undefined
    null
    0
    3
    123
    Cannot convert a Symbol value to a string
    true
    Cannot convert object to primitive value
 */



    [object Object]
    [object Object]
    [object Object]
    [object Object]
    [object Object]
    [object Object]
    [object Object]
    [object Object]
 */



结论

与字符串做加法运算,会尝试将另外一个操作数转成string类型:

  1. 如果另外一个操作数是primitive value则:

  • undefined -> 'undefined'

  • null -> 'null'

  • number -> '0'

  • string -> 不用转变

  • bigint -> '123' n不见了

  • symbol -> Cannot convert a Symbol value to a string

  • boolean -> 'true'

  • object -> ↓↓↓↓↓↓

  1. 如果另外一个操作数是object则检查valueOf方法的返回值:

  • undefined -> 'undefined'

  • null -> 'null'

  • number -> '0'

  • string -> 不用转变

  • bigint -> '123' n不见了

  • symbol -> Cannot convert a Symbol value to a string

  • boolean -> 'true'

  • object -> ↓↓↓↓↓↓

  1. 如果另外一个操作数是object并且valueOf方法不存在则检查toString方法的返回值:

  • undefined -> 'undefined'

  • null -> 'null'

  • number -> '0'

  • string -> 不用转变

  • bigint -> '123' n不见了

  • symbol -> Cannot convert a Symbol value to a string

  • boolean -> 'true'

  • object -> Cannot convert object to primitive value 可以看出来,toString方法的返回值检查和valueOf返回值的检查方法基本上一致,但是如果toString方法还是返回引用类型的话,那就是给机会不中用了!

  1. 如果另外一个操作数是object并且valueOf、toString方法都不存在 这种情况下返回值出奇的统一就是将2和Object.prototype.toString.call(x)的拼接值

总结一下: 如果另外一个操作数x是primitive value则x一定会向string类型尝试转换,记住每一种转换的结果即可; 如果x是引用类型的,则先查valueOf的存在性和其返回值,再查toString的存在性和返回值,最后由Object.prototype.toString.call(x)结束。

1.3 非数字,字符串做加法隐式转换规则

测试程序如下:

console.log(true + true); 
console.log(true + undefined); 
console.log(true + null); 
console.log(true + 123n); 
console.log(true + Symbol(0)); 
console.log(true + {}); 
console.log(true + {valueOf(){return 1}}); 
console.log(true + {toString(){return 1}}); 

console.log(undefined + true); 
console.log(undefined + undefined); 
console.log(undefined + null); 
console.log(undefined + 123n); 
console.log(undefined + Symbol(0)); 
console.log(undefined + {}); 
console.log(undefined + {valueOf(){return 1}}); 
console.log(undefined + {toString(){return 1}}); 

console.log(null + true); 
console.log(null + undefined); 
console.log(null + null); 
console.log(null + 123n); 
console.log(null + Symbol(0)); 
console.log(null + {}); 
console.log(null + {valueOf(){return 1}}); 
console.log(null + {toString(){return 1}}); 

console.log({} + true); 
console.log({} + undefined); 
console.log({} + null); 
console.log({} + 123n); 
console.log({} + Symbol(0)); 
console.log({} + {}); 
console.log({} + {valueOf(){return 1}}); 
console.log({} + {toString(){return 1}}); 

完整的结论

  • bigint不能出现在一般的+运算中!

  • 所有值作为+的操作数的时候都会先转成number或者string类型之后再使用转换值计算

  • symbol不能向number或者string隐式转换,所以symbol也不能参与+运算

  • 如果操作数之一为string类型的,或者转化类型之后为string的,则应该按照【与字符串做加法隐式转换规则 】计算

  • 如果操作数之一为number类型的,并且另一个操作数不为string或者转化类型之后的string,则应该按照【与数字做加法隐式转换规则】计算

  • 如果两个操作数均不为number或者string,或者转换之后的类型军部为number或者string,则只有可能是null undefined boolean,它们都是先转成number类型的再计算

  • 引用类型转成number或者string的方式为,依次检查: valueOf -> toString -> Object.prototype.toString.call(x)的返回值。

看到这,不给作者点个赞?不点赞可能记不住哟~

由于js遵循的是IEEE双精度浮点数标准,也就是使用64bit的二进制数去表示一个浮点数,其中1bit为符号位,11bit为指数位,剩下的52位为尾数。

这就造成了52bit最大只能表示绝对值为2^53 - 1的数字,如果将符号位算进来,就是-(2^53 - 1) -> +(2^53 - 1),也就是-2^53+1 -> 2^53-1

这恰好对应了Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER的值。

也就是说超过这个范围,js就只能用浮点数代替了,就会产生舍入误差了。所以ECMAScript 2020才引入bigint这个新的数据类型来表示这个范围之外的整数。

bigint的原理就是使用非固定长度的二进制数表示整数,因为其长度是不固定的,所以bigint的数据不能参与到和number类型的数据的运算过程中去。

  • 相同点:

    • 两者都是浅拷贝

    • 在实现浅拷贝功能的时候,两者都是后面的值覆盖前面的值

    • 都只会复制ownProperty,包括ownPropertyName和ownPropertySymbol,不涉及原型链上的属性

  • 不同点:

    • 浅拷贝只是扩展运算符的众多用途的一种

    • 扩展运算符产生一个新的对象,而Object.assign是往目标对象上合并属性(不会产生新的对象)

  • 此外:{...obj1, ...obj2}相当于Object.assign({}, obj1, obj2)

  • const原理:在变量名与内存地址之间建立不可变的绑定,当尝试改变变量名的内存地址的时候,由于不可变的绑定的存在会报错

  • 可修改性:对于primitive value修改值会报错,对于引用值来说依然不可以改变这种绑定关系,但是可以对其属性尝试性的进行修改:但需要通过Object.isFrozen来判断这个值是否被冻结了,如果被冻结了,其属性依然是不可以修改的。

补充:Object三傻:freeze seal preventExtensions

先手写一个函数实现new函数的功能:

function myNew (constructor, ...rest) {
    
    if(typeof constructor !== "function") throw new Error('constructor must be a function');
    
    const obj = Object.create(constructor.prototype);
    
    const rst = constructor.apply(obj, rest);
    
    return (rst && (Object(rst) === rst)) ? rst : obj;
}

  • 第二步中,箭头函数没有原型对象,所以constructor.prototype不存在,为undefined,Object.create只接受null或者object类型的,所以这里会报错,这是第一个问题;

  • 第三步中,apply内部会用到this,此时的this应该指向constructor,但是constructor是箭头函数没有this,所以this指向错误;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 《2021测试面试题 - pdf》是一本面试题集合,以PDF格式呈现。这本书可能包含了各种不同类型的面试题,涵盖了不同领域和层级的职位。 阅读这本书可以提供一些关于面试准备的指导,帮助应聘者了解常见的面试问题,以及如何回答这些问题。它可以帮助应聘者熟悉面试过程,了解面试官的期望,并为他们的面试做好准备。 这本书可能包含常见的面试问题,例如个人背景介绍、职业发展规划、技术能力、解决问题的能力、团队合作等。通过阅读这些问题,应聘者可以思考如何回答,并准备一些典型的示例和故事来支持他们的回答。 这本书还可能提供一些面试技巧和建议,包括如何在面试中展示自己的能力和经验,如何有效地回答问题,如何展示个人的职业素养等。 总之,《2021测试面试题 - pdf》是一本面试题集合,旨在帮助应聘者准备面试,了解常见的面试问题,并提供一些面试技巧和建议。对于那些正在寻找工作或准备面试的人来说,这本书可能是一个有用的资源。 ### 回答2: 《2021测试面试题- pdf》是一本面试题集合,针对测试工程师岗位的招聘面试进行了整理和编写。这本题集包含了多种类型的测试题目,涵盖了软件测试的各个方面,旨在帮助招聘单位了解应聘者的测试知识和技能。 这本面试题集的内容包括但不限于测试基础知识、测试策略和方法、测试工具和框架、自动化测试、性能测试、安全测试等。这些题目有些是选择题,有些是简答题或编程题,都是经过精心设计的,可以帮助招聘单位全面地了解应聘者在测试领域的实际能力和经验。 对于应聘者而言,阅读和解答《2021测试面试题- pdf》可以帮助他们复习和巩固测试知识,并提前了解可能会在面试中遇到的问题和考察点。通过认真准备,应聘者可以在面试中更好地回答问题,展示自己的实际能力和经验,提高获得聘用的机会。 对于招聘单位而言,这本题集可以作为一个参考工具,用于筛选和评估应聘者。招聘单位可以根据《2021测试面试题- pdf》中的问题,结合自己的需求和要求,从中选取适合的问题进行面试,以衡量应聘者的能力和适应性。 综上所述,《2021测试面试题- pdf》是一本用于软件测试岗位招聘面试的题目集,旨在帮助招聘单位了解应聘者的测试知识和技能,同时也为应聘者提供了一个复习和准备面试的工具。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Web面试那些事儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值