zoukankan      html  css  js  c++  java
  • js笔试题

    第一题

        console.log(a)       //       undefined
        var a = 1;
        var getNum = function() {
            a = 2;
        }
        function getNum() {
            a = 3;
        }
        console.log(a)      //        1
        getNum()
        console.log(a)      //        2
    
    

    这道题主要考查声明提升函数声明先于变量声明这两个知识点。在解析这个js片段的时候是按照这样的顺序:

    // 声明提升
    function getNum() {
        a = 3;
    }
    var a;
    var getNum;
    
    // 
    console.log(a);
    a = 1;
    getNum = function() {
        a = 2;
    }
    console.log(a)
    getNum()
    console.log(a)
    

    这样就很清晰了,第一次输出a的时候仅仅是声明了还没有赋值,所以是undefined。第二次的不用说了。第三次输出2是因为,变量声明是无法覆盖函数声明的,一开始getNum指向一个函数,后来赋值成了一个函数表达式,指向了另一个函数。

    第二题

    // 每隔一秒输出一次i值
    for(var i = 0; i < 5; i++){
        // TODO
    }
    

    此题主要考查闭包js执行机制。以下几种解法:

    大概1秒输出一次的版本:

    // 利用立即执行函数形成闭包
    (function(i){
        setTimeout(function() {
            console.log(i)
    }, i * 1000)})(i)
    
    // 利用setTimeout的第三个参数形成闭包
    setTimeout(function(i) {
        console.log(i)
    }, i * 1000, i)
    
    // 如果不是题目中指定了var,利用ES6的let就简单多了
    for(let i = 1; i < 5; i++) {
        setTimeout(function(){
            console.log(i)
        }, i * 1000)
    }
    
    // 再看ES7版本
    const sleep = (time) => 
        new Promise((resolve, reject) => 
            setTimeout(resolve, time));
    (async function(){
       for(var i = 0; i < 5; i++){
           await sleep(1000);
           console.log(i);
       }
    })()
    

    之所以是说是大概,是因为setTimeout并不是延时多少秒后执行函数,而是多少秒后把函数扔进事件队列中等待执行,如果此时队列里有其他任务 的话那就不是精确的1秒了。

    关于js执行机制,看这里这一次,彻底弄懂 JavaScript 执行机制

    再看比较精确的1秒版本:

    for(var i =0; i < 5; i++) {
        var time = new Date();
        while(new Date() - time < 1000) {
        }
        console.log(i)
    }
    

    直接阻塞线程一秒钟,简单粗暴有木有~

    第三题

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

    这题主要考查对象。其实这里a[b]a[c]中的b、c都会调用object.prototype.toString(),都变成了[object Object],这样就与对象中的key值无关了。所以a[b]a[c]的指向是相同的。

    第四题

    var f = function() {
        var c = "ccc";
        return {
            a: function() {
                return c;
            },
            b: function(d) {
                c = d;
            }
        }
    }()
    
    console.warn(f.a())         // ccc
    console.warn(f.c)           // undefined
    console.warn(f.b("www"))    // undefined
    console.warn(f.a())         // www

    这题主要考查的是执行上下文中的作用域链。我们要注意到函数表达式后的那个函数执行符——(),它是个立即执行函数,也就是说f是个包含a、b属性的对象。

    console.warn(f.a()) 
    

    当a()的执行上下文被激活时,作用域和变量对象被确定,c是个自由变量,需要在作用域链中向上查找,然受在父级作用域中找到,所以输出“ccc”。

    console.warn(f.c)
    

    这个就不用说啦,f中没有c这个属性,取不到当然返回undefined

    console.warn(f.b("www"))
    

    同第一行一样,修改的是父级作用域中的c,但由于没有返回值所以输出的是undefined。

    函数会顺着作用域链查找当前执行环境不存在的变量,对象则从原型链上查找!!!

    第五题

    数组去重 输入[1,2,3,1,'1','2',2]返回[1,2,3,'1','2']。 这个嘛方法就很多啦。

    (function(arr){
        console.log([...(new Set(arr))])
    })([1,2,3,1,'1','2',2])
    

    利用Map结构的key可以是任意类型这个特性,能很好的区分字符'1'和数字1,而普通对象的key值是字符串类型,无法区分这两者。

    (function(arr) {
        let hash = new Map();
        arr = arr.reduce((item, value) => {
            hash.has(value) ? '' : hash.set(value, true) && item.push(value)
            return item;
        }, [])
        console.log(arr)
    })([1,2,3,1,'1','2',2])
    

    第六题

    有两个小写字符串s1、s2,s2是s1经过打乱后增加一个小写字符得到的, 编程得出s2中增加的字符,算法时间复杂度最好接近O(n)(如s1是'abc',s2是'cbad',那么增加的字符为‘d’)。

    解法一

    笔者关于这道题的思考,首先是考虑到增加的字符可能是s1中已经存在的,那通过遍历+indexOf()的方案也就没用了,所以笔者在写这道题的时候考虑到s1、s2只有一个字符之差,索性把s1、s2中的字符都填入一个对象中,统计每个字符的个数,个数为奇数的就是那个多出来的字符了。(另外欢迎在评论区中给出更优解)上代码:

    var s1 = "aaabweddccc";
    var s2 = "aaaewwbcccdd";
    (function(a,b){           
        let all = a + b;
        let allLen = all.length;
        let hash = {};
        for(let i = 0; i < allLen; i++) {
            hash[all[i]] ? hash[all[i]]++ : hash[all[i]] = 1;              
        } 
        console.log(hash)                          
        for(let j in hash) {
            if(hash[j] % 2 !== 0) {
                console.log(j)
            }
        }
    })(s1,s2)
    

    运行结果:

    解法二

    这个方法是后来想到的。思路是这样的,如果没有插入那个额外的字符之前,对两个字符串进行排序后,两字符串对应位置的字符肯定是相同的,插入一个字符之后,必定有个位置的字符不匹配。

    (function(a,b){           
        a = a.split("").sort()
        b = b.split("").sort()
        for(let i = 0, len = b.length; i < len; i++) {
            if(a[i] !== b[i])
            console.log(b[i])             
        } 
    })(s1,s2)
    

    运行结果:

    总结

    总共就6道题,考的比较基础,包括:

    • 声明提升
    • 闭包
    • 执行上下文
    • js执行机制
    • ......

    作者:Gesangs
    链接:https://juejin.im/post/5abaeecef265da237a4d0e20
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    hdu1556 Color the ball
    HDU
    《解读window核心编程》 之 字符和字符串处理方式
    WebService之CXF注解之四(測试类)
    gdal以GA_Update方式打开jpg文件的做法
    贪吃蛇源代码分析
    极光消息推送服务器端开发实现推送(上)
    2014,为了梦想宁愿破釜沉舟
    小强的HTML5移动开发之路(37)——jqMobi快速入门
    你可能不知道的5种 CSS 和 JS 的交互方式
  • 原文地址:https://www.cnblogs.com/cangqinglang/p/8964070.html
Copyright © 2011-2022 走看看