Skip to content

前端一些题1

记录一些坑蒙拐骗的题,温故而知新。

js
    var b = 3; 
    (function(){
        b = 5;
        var b = 2;
    })()
    console.log(b)
result

3

解析:就是一个闭包问题

如果改一下:

js
    var b = 3; 
    (function(){
        b = 5;
        // var b = 2;
    })()
    console.log(b)
result

5

js
    function getPersonInfo(one, two, three) {
        console.log(one)
        console.log(two)
        console.log(three)
    }
    const person = "Lydia";
    const age = 21;
    getPersonInfo`${person} is ${age} years old`;
result

[ '', ' is ', ' years old' ] Lydia 21

解析:在函数内部,模板字面量会被解析成一个数组,其中包含了字符串部分和表达式部分的分割结果,有点像Array.split方法 getPersonInfoaaa ${person} is ${age} years old会分割为

[ 'aaa ', ' is ', ' years old' ]

js
   function getAge(...args){
       console.log(typeof args)
   }
   getAge(21);
result

object

解析:结构以后args是[21]

js
    let val = "0";
    console.log('Value is '+(val != '0')?"define":"undefine");
    val = "1";
    console.log('Value is '+(val != '0')?"define":"undefine");
result

define define

解析:三元运算符地位比较低,所以这题实际上是 "Value is true"?"define":"undefine"

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

122 32 NaN2 NaN

解析:

第一个,当字符串做加法的时候,其他类型都会转字符串;

第二个,+"2"会把字符串的2转变为数字2,所以就变成了1+2+"2";

第三个,"A" - "B"会尝试把减号前后转换为数字,但是转不动所以变成了NaN,再加"2"

第四个,NaN + 2 = NaN

js
    for (var i = 0; i < 10; i++) {
        setTimeout(function () {
            console.log(i);
        }, 0);
    }
result

10个10

解析:应该有人答10个9,总之就是一个闭包问题,要解决这个问题很简单:

js
    for (let i = 0; i < 10; i++) {
        setTimeout(function () {
            console.log(i);
        }, 0);
    }

或者

js
    for (var i = 0; i < 10; i++) {
        (function (i){
            setTimeout(function () {
                console.log(i);
            }, 0);
        })(i)
    }

改改:

js
    for (var i = 0; i < 10; i++) {
        setTimeout(function () {
            console.log(i);
        }, 0);
    }
    i = 20;
result

10个20

解析:event loop,没什么好说的

js
    console.log(["1", "2", "3"].map(Number.parseInt))
result

[ 1, NaN, NaN ]

解析:实际上这里是:

js
    console.log(["1", "2", "3"].map((v,i) => Number.parseInt(v,i)))
    // 相当于执行了 Number.parseInt("1",0)   10进制
    // 相当于执行了 Number.parseInt("2",1)   1进制
    // 相当于执行了 Number.parseInt("3",2)   2进制

具体来说,parseInt 的行为如下:

  • 如果第二个参数未指定,则默认为 10(十进制)。
  • 如果第二个参数为 0 或未指定,则根据字符串的开头来确定进制:
    • 如果字符串以 "0x" 或 "0X" 开头,则使用十六进制。
    • 如果字符串以 "0" 开头,则使用八进制。
    • 其他情况下,默认为十进制。
  1. 实现给定一个数进行加或减,例如给定一个数字7进行减1加2操作,比如: (7).minus(1).add(2)
result

原型上面定义方法,没啥好说的

js
    Number.prototype.minus = function (num) {
    return this - num
    };
    Number.prototype.add = function (num) {
        return this + num
    };
    console.log((7).minus(1).add(2));
  1. 当a等于什么的时候使得下面可以输出console.log
js
    var a = ??;
    if (a == 1 && a == 2 && a == 3) {
        console.log(1);
    }
result

类似vue双向绑定的写法

js
    let value = 0;
    Object.defineProperty(globalThis, 'a', {
        get() {
            return ++value;
        }
    });

    if (a == 1 && a == 2 && a == 3) {
        console.log(1);
    }

改改题目:

js
    var a = ??;
    if (a == 3 && a == 1 && a == 2) {
        console.log(1);
    }
result
js
    let value = 0;
    Object.defineProperty(globalThis, 'a', {
        get() {
            return [3, 1, 2][value++];
        }
    });

    if (a == 3 && a == 1 && a == 2) {
        console.log(1);
    }
  1. 输出是什么
js
async function m1() {
    return 1;
}
async function m2() {
    const n = await m1();
    console.log(n)
    return 2;
}
async function m3() {
    const n = m2();
    console.log(n);
    return 3;
}
m3().then(n => {
    console.log(n);
})
m3();
console.log(4);
result
js
// Promise { <pending> }
// Promise { <pending> }
// 4
// 1
// 3
// 1

如果你错了,没关系,因为刚开始我也错了,那么开始剖析:

js
    async function m1() {
        return 1;
    }
    async function m2() {
        const n = await m1();
        console.log("m2")
        console.log(n)
        return 2;
    }
    async function m3() {
        const n = m2();
        console.log("m3")
        console.log(n);
        return 3;
    }
    m3().then(n => {
        console.log("then")
        console.log(n);
    })
    m3();
    console.log(4);

---------分割线---------

js
// m3 Promise { <pending> }
// m3 Promise { <pending> }
// 4
// m2 1
// then 3
// m2 1

分析:

首先16行代码执行,然后走到11行,再走到5行,此时await存入微任务,然后回到12行输出,同时17行也进入微任务;

执行20行代码,然后走到11行,再走到5行,此时await存入微任务,然后回到12行输出,此时微任务里面存在三个(6行 17行 6行);

21行输出没什么好说的;

剩下的就是微任务执行,也没什么好说的,注意17行输出的是3;

js
console.log(1)

const promise = new Promise((resolve, reject) => {

    console.log(2);

    setTimeout(() => {
        resolve(3);
        reject(4);
    }, 0);
});

promise.then((data) => {
    console.log(data);
}).catch((error) => {
    console.log(error);
});

console.log(5);
result
js
1 2 5 3
  1. 输出1没什么好说的
  2. promise在定义的时候要执行callback,不懂就去看promise源码,输出2
  3. setTimeout进宏任务队列
  4. then进微任务队列
  5. 输出5
  6. 输出3
  7. promise执行完成不会再走catch了
  8. 上文中 resolve(3)reject(4) 互换一下就会变成 1 2 5 4,没什么好说的了
js
var fullname = 'a';

var obj = {
    fullname: 'b',
    prop: {
        fullname: 'c',
        getFullname: () => {
            return this.fullname;
        }
    }
};

console.log(obj.prop.getFullname());

var test = obj.prop.getFullname;

console.log(test());
result
js
// a a

题目很简单,但是这里有一个问题,如果这个代码在node运行的话,有几点要注意:

  1. node中定义var fullname不会挂到 global 上面
  2. 这里的this指向exports或者module.exports
  3. getFullname: () => {return this.fullname;}改为getFullname: function(){return this.fullname;}的时候this才是global
  4. 同理,在3的基础上继续修改第一行改为 this.fullname = 'a'也是没用的,改成 global.fullname = 'a'才可以得到c a的结果

后记

老板,续一杯 卡布奇诺

鄂ICP备2024055897号