前端面试题及答案整理(一)

各集团秋招很快就伊始了,近期在准备面试的事物,干脆将发现的各个面试题整理一下共享出来,大多数面试题是绝非标准答案的,我付诸的答案也是仅供参考,如若有更好的解答欢迎在评论区留言。

Part1 手写代码

现场手写代码是当今面试中很广阔的一类面课题,考察基础的数据结构与算法能力。

1 数组去重的贯彻

  • 着力数组去重

    Array.prototype.unique = function(){

    var result = [];
    this.forEach(function(v){
        if(result.indexOf(v) < 0){
            result.push(v);
        }
    });
    return result;
    

    }

  • 行使hash表去重,那是一种空间换时间的主意

    Array.prototype.unique = function(){

    var result = [],hash = {};
    this.forEach(function(v){
        if(!hash[v]){
            hash[v] = true;
            result.push(v);
        }
    });
    return result;
    

    }

上面的章程存在一个bug,对于数组[1,2,’1′,’2′,3],去重结果为[1,2,3],原因在于对象对属性索引时会进展强制类型转换,arr[‘1’]和arr[1]获取的都是arr[1]的值,由此需做一些改成:

Array.prototype.unique = function(){
    var result = [],hash = {};
    this.forEach(function(v){
        var type = typeof(v);  //获取元素类型
        hash[v] || (hash[v] = new Array());
        if(hash[v].indexOf(type) < 0){
            hash[v].push(type);  //存储类型
            result.push(v);
        }
    });
    return result;
}
  • 先排序后去重

    Array.prototype.unique = function(){

    var result = [this[0]];
    this.sort();
    this.forEach(function(v){
        v != result[result.length - 1] && result.push(v); //仅与result最后一个元素比较
    });
    

    }

  • 利用ES6 Set去重

    //ES6环境下
    Array.prototype.unique = function(){
         return [...new Set(this)];
    }
    

2 急速排序的落成

格局一(尽可能不要js数组方法):

function quickSort(arr){
    qSort(arr,0,arr.length - 1);
}
function qSort(arr,low,high){
    if(low < high){
        var partKey = partition(arr,low,high);
        qSort(arr,low, partKey - 1);
        qSort(arr,partKey + 1,high);
    }
}
function partition(arr,low,high){
    var key = arr[low];  //使用第一个元素作为分类依据
    while(low < high){
        while(low < high && arr[high] >= arr[key])
            high--;
        arr[low] = arr[high];
        while(low < high && arr[low] <= arr[key])
            low++;
        arr[high] = arr[low];
    }
    arr[low] = key;
    return low;
}

办法二(使用js数组方法):

function quickSort(arr){
   if(arr.length <= 1) return arr;
   var index = Math.floor(arr.length/2);
   var key = arr.splice(index,1)[0];
   var left = [],right = [];
   arr.forEach(function(v){
       v <= key ? left.push(v) : right.push(v);
   });
   return quickSort(left).concat([key],quickSort(right));
}

除此以外要知道,快捷排序的平均时间复杂度O(nlogn),最坏情状是逐步的情事,时间复杂度为n的平方,其余连忙排序是不平静的。

Part2 JavaScript相关

1 JavaScript基础数据类型

JavaScript数据类型包涵原始类型和引用类型,原始类型有三个:

  Number(数值) String(字符串) Boolean(布尔) Null(空) Undefined(未定义)

引用类型有一个:

 Object(对象)

通过typeof(x)可以回到一个变量x的数据类型“number”、“string”、“boolean”、“undefined”、”object”,那里要留心一点:typeof运算符对于null项目重临的是object

《JavaScript高级程序设计》:
那实则是JavaScript最初落成中的一个荒唐,后来被ECMAScript沿用了。现在null被认为是目的的占位符,从而解释了这一顶牛。不过从技术上来说,它照旧是原始值。

2 谈一谈JavaScript效率域链

当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会创建为其创建一个功能域又叫做执行上下文(Execution
Context),在页面加载后会首先成立一个大局的功能域,然后每执行一个函数,会树立一个对应的成效域,从而形成了一条效益域链。每个效用域都有一条对应的效能域链,链头是大局成效域,链尾是当下函数成效域。

效果域链的作用是用来解析标识符,当函数被创制时(不是实践),会将this、arguments、命名参数和该函数中的所有片段变量添加到该当前功效域中,当JavaScript要求寻找变量X的时候(这几个历程称为变量解析),它首先会从成效域链中的链尾也就是时下功用域举行搜索是或不是有X属性,假诺没有找到就本着效能域链继续寻找,直到查找到链头,也就是大局意义域链,仍未找到该变量的话,就认为那段代码的功能域链上不设有x变量,并抛出一个引用错误(ReferenceError)的卓殊。

3 怎样知道JavaScript原型链

JavaScript中的每个对象都有一个prototype属性,大家称为原型,而原型的值也是一个对象,因而它也有友好的原型,那样就串联起来了一条原型链,原型链的链头是object,它的prototype相比特殊,值为null。

原型链的出力是用来对象继承,函数A的原型属性(prototype
property)是一个目的,当那么些函数被作为构造函数来创建实例时,该函数的原型属性将被看成原型赋值给持有目的实例,比如我们新建一个数组,数组的艺术便从数组的原型上持续而来。

当访问对象的一个性质时, 首先查找对象自我, 找到则赶回; 若未找到,
则继续寻找其原型对象的性质(倘诺还找不到实际还会沿着原型链向上查找,
直至到根). 只要没有被遮盖的话,
对象原型的属性就能在拥有的实例中找到,若一切原型链未找到则重回undefined;

4 JavaScript变量注明提前

《JavaScript权威指南》中是那样解释的:JavaScript变量在宣称之前早已可用,JavaScript的那个特性被非正式的名为声明提前(hoisting),即JavaScript函数中声称的有着变量(但不关乎赋值)都被“提前”至函数的顶部。

从一个事例来看:

var scope = "global";
function myFunc(){
    console.log(scope); 
    var scope = "local";
}

控制台打印出来的不是“global”而是“undefined”,那是因为在myFunc这些函数的意义域中,局地变量scope注明被提前至函数顶部,而此刻,scope仅宣称,未赋值,因而输出undefined。实际上,下边的代码和上边的功能是千篇一律的:

var scope = "global";
function myFunc(){
    var scope;
    console.log(scope);
    scope = "local";
}

5 怎么着通晓和运用JavaScript闭包

关于闭包具体的概念文献中给的定义很虚幻,我认为闭包是一种使函数可以都去其它函数的有的变量的语法机制。

举个例子:

function outFunc(){
    var name = "Vicfeel";
    function inFunc(){
        console.log(name);
    }
    return inFunc;
}
inFunc(); //控制台显示"Vicfeel"

ECMAScript,这那么些事例大家可以观看,在函数inFunc中照旧得以访问outFunc的部分变量name。

闭包应用举例,模拟类的民用属性,利用闭包的习性,局地变量唯有在sayAge方法中才得以访问,而name在表面也访问,从而已毕了类的私有属性。

    function User(){
        this.name = "Vicfeel";  //共有属性
        var age = 23;    //私有属性
        this.sayAge:function(){
            console.log("my age is " + age); 
        }
    }
    var user = new User();
    console.log(user.name); //"Vicfeel"
    console.log(user.age);  //"undefined"
    user.sayAge();   //"my age is 23"

要打听详细的闭包,推荐一下
阮一峰的互连网日志-学习Javascript闭包(Closure)

6 new构建对象的面目

    function User(){
        this.name = "Vicfeel";
        this.age = 23;
    }

    var user = new User();

通过new操作符,实际上在结构函数User中形成了之类操作:

  • 始建一个新的目的,那一个目的的项目是object;
  • 安装这些新的靶子的内部、可访问性和prototype属性为构造函数(指prototype.construtor所针对的构造函数)中安装的;
  • 实践构造函数;
  • 回到新成立的目的。

    function User(){
        //this = {};  
        //this.constructor = User;
        this.name = "Vicfeel";
        this.age = 23;
        //return this;
    }
    
    var user = new User();
    

即使构造函数默许重回的新成立的this对象,若是手动return
一个变量的话,如若该变量是原始类型则不行,如果是目的,则赶回该目的。

7 JavaScript代理

当大家需求对很多要素添加事件的时候,可以透过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。

例如大家需求向一个ul中动态拉长很七个li,必要遍历li逐个添加点击事件

    <ul id='list'></ul>

    var count = 100;
    var ulList = document.getElementById("list");
    //动态构建节点
    for(var i = count;i--;){
        var liDom = document.createElement('li');
        ulList.appendChild(liDom);
    }
    //绑定点击事件
    var liNode = ulList.getElementByTagName("li");
    for(var i=0, l = liNodes.length; i < l; i++){
        liNode[i].onClick = function(){
            //li点击事件
        }
    }   

分明,DOM操作是卓殊消耗质量的。所以重复的风云绑定大约是性质杀手。而事件代理的主题绪想,就是经过尽量少的绑定,去监听尽量多的风浪。如何做吗?答案是运用事件冒泡机制,对其父节点ul举行事件绑定(伊夫nt
Bubble),然后通过event.target来判断是哪个节点触发的风浪,从而裁减过多EventHandler的绑定。

    var count = 100;
    var ulList = document.getElementById("list");
    //动态构建节点
    for(var i = count;i--;){
        var liDom = document.createElement('li');
        ulList.appendChild(liDom);
    }
    //绑定点击事件
    var liNode = ulList.getElementByTagName("li");
    liNode.onClick = function(e){
        if(e.target && e.target.nodeName.toUpperCase == "LI") {
            // li点击事件
        }
    }

发现新内容会遍地更新…

博文小编:vicfeel
博文出处:http://www.cnblogs.com/vicfeel
正文版权归小编和今日头条共有,欢迎转发,但须保留此段表明,并交由原文链接,谢谢协作!
万一阅读了本文章,觉得有帮扶,您可以为自我的博文点击“推荐一下”!