• 2019年面试题1


    基础题

    1、请写出你了解的Array方法,至少6个?

    push:将一个或多个元素添加到数组的末尾,并返回该数组的新长度。

    unshift:将一个或多个元素添加到数组的开头,并返回该数组的新长度。

    pop:从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。

    shift:从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。

    splice:增删改原素组,返回被修改的元素的数组集合。

    /** 
        array.splice(start[, deleteCount[, item1[, item2[, ...]]]]) 
        中括号内为可选参数
    **/
    let arr = ['Jan', 'March', 'April', 'June'];
    //增:在角标为1的位置插入元素,删除之后的0个元素: ['Jan','Tom', 'March', 'April', 'June']
    arr.splice(1, 0, 'Tom'); 
    // 改:在角标为1的位置插入元素,删除之后的1个元素,也就达到了替换的目的:['Jan','Luck', 'March', 'April', 'June']
    arr.splice(1, 1, 'Luck'); 
    // 删:从角标为1的位置开始删除,删除两个元素: ['Jan', 'April', 'June']
    arr.splice(1, 2); 
    View Code

    concat:数组合并

    此题考察引用数据类型array的了解

    2、写出下题输出结果?

    console.log(1);//step1:同步执行,打印1
    setTimeout(function(){//step2:处理异步--将宏任务回调放入宏任务的EventQueue(下一轮执行时调用,次轮才执行上轮的EventQueue宏任务回调)
        console.log(5); //setp6:处理异步--从宏任务EventQueue取出回调执行,打印5
    },0)
    new Promise(function(resolve){
        resolve();
        console.log(6); //step3:同步执行,打印6
    }).then(function(){//step4:处理异步--将微任务回调放入微任务的EventQueue,(本轮同步完成后,就执行EventQueue微任务回调)
        console.log(7);//setp5:处理异步--从微任务EventQueue取出回调执行,打印7。至此第一轮事件循环结束了,我们开始第二轮循环
    });
    console.log(8);//step3:同步执行,打印8
    
    /**这段代码作为宏任务,进入主线程。
        执行同步代码console.log(),立即执行打印1,
        遇到setTimeout,那么等待0s后将其回调函数注册后分发到宏任务event queue.
        接下来遇到Promise, new Promise作为同步立即执行,then函数分发到微任务event queue
        遇到console.log(8), 立即执行打印8
        整体代码script作为第一个宏任务执行结束, 查看当前有没有可执行的微任务,执行then的回调。(第一轮事件循环结束了,我们开始第二轮循环)
        从宏任务的event queue开始,我们发现了宏任务event queue中还有个setTimeout对应的回调函数,立即执行。 执行结果: 1-6-8-7-5
    
        微任务 promise  process.nextTick          
        宏任务 setTimeout  setInterval  I/O  script
        同一次事件循环中  微任务永远在宏任务之前执行,在当前的微任务没有执行完成时,是不会执行下一个宏任务的。
        setTimeout就是作为宏任务来存在的,而Promise.then则是具有代表性的微任务
        宏任务需要多次事件循环才能执行完,微任务是一次性执行完的
    **/

    此题考查了同步异步,事件循环,任务队列相关知识点

    参考:
    https://www.jianshu.com/p/dc9424a4948e

    https://www.jianshu.com/p/2a5954b78ff5

    https://www.jianshu.com/p/1368d375aa66

    3、下边console输出什么?

    var name = 'the window';
    function func(){
        console.log(this.name);
    };
    var obj = {
        name: 'my obj',
        getNameFunc:function(fn){
            fn && fn(); //打印the window
            return function(){
                return this.name;
            };
        }
    };
    //var fun = object.getNameFunc();返回的是一个function.此时,fun中的this指向是window,所以this.name是The window
    //var fun= function(){}fun是window中的。相当于window.fun = function(){}
    console.log(obj.getNameFunc(func)()) //打印the window 

     此题考查了this相关知识

    4、看下边代码,打印什么?

    let obj = { a: 0 };
    function fn(obj){
        obj.a = 1; //函数参数
        obj = { a: 2 };
        obj.b = 2;
        console.log(obj);// {a: 2, b: 2}
    };
    fn(obj);
    console.log(obj) // {a: 1}
    /**
    引用类型的实参,会按照共享传递方式传递,传递的是实参引用的副本,
    所以会表现为改变形参的属性会影响外边的,重新赋值则会切断与实参的共享联系不会影响到实参
    **/

    此题考查了函数参数传递知识

    参考:https://www.cnblogs.com/xcsn/p/9158727.html

     5、手写一个原生的bind方法?

    了解bind方法

    // 提到bind方法,估计大家还会想到call方法、apply方法;它们都是Function对象内建的方法,它们的第一个参数都是用来更改调用方法中this的指向。需要注意的是bind 是返回新的函数,以便稍后调用;apply 、call 则是立即调用原函数
    function People() {
        console.log(this);
    };
    var func = People.bind({name:'阎涵'});
    func(); //作为普通函数调用,这是bind最常用的场景  
    new func(); //作为构造的时候,bind的决定this的参数(即第一个参数)失效。这是经常面试的,实际开发没意义

    手写一个简单的bind方法

    //手写简单的一个bind方法,bind不能额外传递参数,不区分构造和普通使用
    Function.prototype.myBind = function(obj){
        const oldFun = this;
        const BindFn = function(){
            return oldFun.apply(obj);
        };
        return BindFn;
    };
    
    //使用
    function People() {
        console.log(this);
    };
    var func = People.myBind({name:'阎涵'});
    func(); 
    new func(); 
    
    //弊端:不能传递参数,而且两种用法都只作为普通函数调用,不能作为构造函数

    写一个完整的bind方法

    //手写一个bind方法
    Function.prototype.myBind = function(obj){
        //bind方法预置新参数
        const arg = [...arguments]; 
        arg.shift();
    
        //保存原始函数(主要是存储当前this)
        const oldFun = this;
    
       //新创建一个的函数(基于原始函数)
        const BindFn = function(){
            console.warn( this instanceof BindFn?'当构造用':'当普通函数用'); //若普通调用则this是Window对象,然为构造方式调用
            this instanceof BindFn && (obj = this);
            return oldFun.apply(obj,[...arg,...arguments]); //修改this,传递参数[bind预置+自身传递参数]
        };
    
        // 维护原型关系
        BindFn.prototype = this.prototype;
    
        //返回(已经绑定this后的修改完的原始函数)新函数
        return BindFn;
    };
    
    //使用
    function People() {
        this.sayHaHa = function(){console.log('哈哈')};
        console.log(this,arguments);
    };
    People.prototype.speak =  function(){console.log('我在people原型上哦')};
    var func = People.myBind({name:'阎涵'},'我是bind预置参数');
    func('我是自身传递参数'); //普通使用
    const p = new func(); //构造使用 通过维护原型关系,p对象既有People类的实例成员,也有People类的原型成员。
    p.sayHaHa();
    p.speak();
    console.log(p)

    编程题

    1、给定一个n个对象颜色为红色,白色或蓝色的数组,对其进行排序,使相同颜色的对象相邻,颜色为红色,白色和蓝色。在这里,我们将使用0,1和2的整数分别表示红色,白色和蓝色。比如,输入[2,0,2,1,1,0]排序后[0,0,1,1,2,2]。---力扣(LeetCode)中级算法

    2、将类似以下JSON表示的树状结构(可以无限层级)
    通过parseDOM函数(使用document.createElement,document.createTextNode,appendChild等方法)
    生成一颗DOM树(返回一个element元素)

    const JsonTree = {
            "tagName": "ul",
            "props": {
                "className": "list",
                "data-name": "jsontree"
            },
            "children": [{
                    "tagName": "li",
                    "children": [{
                        "tagName": "img",
                        "props": {
                            "src": "//img.alicdn.com/tps/TB1HwXxLpXXXXchapXXXXXXXXXX-32-32.ico",
                            "width": "16px"
                        }
                    }]
                },
                {
                    "tagName": "li",
                    "children": [{
                        "tagName": "a",
                        "props": {
                            "href": "https://www.aliyun.com",
                            "target": "_blank"
                        },
                        "children": "阿里云"
                    }]
                }
            ]
        };
    View Code

    答案:

    function parseDOM(jsontree) {
            const {
                tagName,
                props,
                children
            } = jsontree;
            const element = document.createElement(tagName);
            //请实现过程
            //....
            for (let _key in props) {
                element[_key] = props[_key];
            }
            if (children && typeof(children) === "object") {
                for (let i = 0; i < children.length; i++) {
                    element.appendChild(parseDOM(children[i]));
                }
            } else {
                if (children) {
                    element.appendChild(document.createTextNode(children));
                }
            }
            return element;
        }
        document.getElementsByTagName(“body ")[0].appendChild(parseDOM(JsonTree));
    View Code

    首先这个面试题很切合实际,在日常的开发过程中经常会遇到这种类型的数据。主要考我们对递归算法的熟练程度。具体的知识点就是题中列出的3个DOM操作的知识。
    参考答案的思路是把每次创建完成的节点添加到父元素中

  • 相关阅读:
    HTTP协议
    javascript常用数组排序及二分查找
    垃圾回收与内存管理
    js的数据存储机制和数据类型
    js中的深复制与浅复制
    斐波那契数列的实现
    认识python中的浅复制与深复制
    微信浏览器中弹窗高度适配
    “ 时,分,秒” 活动倒计时
    互联网协议
  • 原文地址:https://www.cnblogs.com/dshvv/p/11647122.html
Copyright © 2020-2023  润新知