• 前端高频面试题 JavaScript篇


    以下问题都来自于互联网前端面经分享,回答为笔者通过查阅资料加上自身理解总结,不保证解答的准确性,有兴趣讨论的同学可以留言或者私信讨论。

    1.JS的异步机制?
    2.闭包如何实现?
    3.原型链、继承?
    4.实现订阅者发布者模式?
    5.数组的方法有哪些?

    1.JS的异步机制?

    JS使用一个任务队列记录异步任务的回调函数,当异步任务(或者事件被激发,如鼠标点击)完成后,其回调函数会被添加到该任务队列的末尾,JS主线程在将所有的同步任务执行完毕后,会无限循环地去检查任务队列,如果任务队列不为空,则主线程回去执行任务队列中的任务。
    关于异步机制的详细解答,可以参考:Javascript异步机制

    2.闭包如何实现?

    在计算机科学中,闭包是引用了自由变量的函数。在Javascript中,在一个函数中定义一个内部函数,并且内部函数引用了外部函数作用域的变量,然后将这个内部函数作为外部函数的返回值,这样就构成了一个闭包。如下代码:

    function wrapper() {
        var milk = '特仑苏'
        function drink() {
            console.log('我喝了' + milk)
        }
        return drink
    }
    var result = wrapper()
    result()  //我喝了特仑苏
    

    关于闭包的详细解答,可以参考:Javascript闭包

    3.原型链、继承?

    在Javascript中,每当我们定义一个函数,Javascript引擎就会自动为这个函数对象添加一个prototype属性(也被称作原型),每当我们使用这个函数new创建一个对象时,Javascript引擎就会自动为这个对象中添加一个__ proto __ 属性,并让其指向其类的prototype。当我们访问一个对象的属性时,首先回去寻找该对象本身的属性,如果找不到的话回去寻找该对象的 __ proto __ 作用域下的属性,一直到寻找到该属性或者没有__ proto __为止。这种寻找实例属性的方式我们称作原型链。
    当我们让子类的prototype指向父类的实例时,便实现了原型链继承。

    // 原型链实现继承的关键代码
    Son.prototype = new Father()
    

    当然Javascript的继承方式还有 构造函数继承 、 组合继承 、 寄生继承,更详尽的解答,可以参考:对Javascript 类、原型链、继承的理解

    4.实现订阅/发布者模式?

    var publisher = {}; // 定义发布者
    publisher.list = []; // 缓存列表 存放订阅者回调函数
    // 增加订阅者
    publisher.listen = function(fn) {
        publisher.list.push(fn);  // 订阅消息添加到缓存列表
    }
    // 发布消息
    publisher.trigger = function(){
        for(var i = 0,fn; fn = this.list[i++];) {
            var that = this
    		fn.apply(null, arguments); 
        }
    }
    

    详细答案可以参考:Javascript中理解发布--订阅模式

    5.数组的方法有哪些?

    这个题属于开放题,答案就比较多了,下面我列举一下比较常用的数组方法:
    遍历方法:
    包括 map、foreach、filter

    let arr = [{
    	name:"西瓜",
    	type:"水果"
    },{
    	name:"芒果",
    	type:"水果"
    },{
    	name:"小龙虾",
    	type:"夜宵"
    }]
    arr.forEach((item, index) => {
    	console.log(item.name)
    }) //分别打印 西瓜 芒果 小龙虾
    arr.map((item, index) => {
    	return item.name
    }) //返回数组["西瓜", "芒果", "小龙虾"]
    arr.filter((item, index) => {
    	if (item.type == "水果")
    		return true;
    	else 
    		return false;
    }) //返回数组[{ name: 西瓜, type : 水果 }, { name: 芒果, type : 水果 }]
    

    forEach:用于遍历数组,无返回值;
    map:遍历数组之后,对每一项返回一个值,并将这些返回值都推入一个数组,最后返回这个新的数组;
    filter:对数据进行过滤,回调函数返回值为false的项将被过滤掉,最后返回过滤后的数组。
    操作方法:
    包括 concat、push、pop、unshift、shift、splice

    let listA = ["西瓜", "芒果"]
    let listB = ["小龙虾"]
    let listC = listA.concat(listB)
    // 返回值:[西瓜, 芒果, 小龙虾]
    
    listC.push("鸡腿")
    // 返回值:4
    // 数组值:[西瓜, 芒果, 小龙虾, 鸡腿]
    
    listC.pop()
    // 返回值:"鸡腿"
    // 数组值:[西瓜, 芒果, 小龙虾]
    
    listC.unshift("鸡腿")
    // 返回值:4
    // 数组值:[鸡腿, 西瓜, 芒果, 小龙虾]
    
    listC.shift()
    // 返回值:"鸡腿"
    // 数组值:[西瓜, 芒果, 小龙虾]
    
    listC.splice(1, 1, "冰激凌", "奶茶")
    // 返回值:[芒果]
    // 数组值:[西瓜, 冰激凌, 奶茶, 小龙虾]
    

    concat:拼接数组,将参数数组拼接到调用数组末尾,并返回这个新数组;值得一提的是,这个方法并不会改变调用数组和参数数组,即上例中的listA、listB);
    push:在数组尾部插入新的元素,返回插入元素之后的数组长度;
    pop:从数组尾部删除元素,返回删除的元素;
    unshift:在数组头部插入新的元素,返回插入元素之后的数组长度;
    shift:从数组头部删除元素,返回删除的元素;
    splice:删除元素并插入元素,第一个参数为操作位置X,第二个参数为需要从操作位置X删除元素数量,后面的参数为需要从操作位置X插入的元素,返回删除的元素组成的数组。

  • 相关阅读:
    roportional Rate Reduction (PRR)
    【C++11新特性】 nullptr关键字
    C++ 智能指针
    std::thread
    C++11 的 std::ref 用法
    for auto
    C++11右值引用与移动构造函数
    leetcode刷题笔记一百零六题 从中序与后序遍历序列构造二叉树
    leetcode刷题笔记一百零五题 从前序与中序遍历序列构造二叉树
    leetcode刷题笔记一百零四题 二叉树的最大深度
  • 原文地址:https://www.cnblogs.com/codernie/p/9225254.html
Copyright © 2020-2023  润新知