刷面试题之<<携程 地面业务 前端面试经历>>

在简书看到这篇面试题,结合作者的答案和个人的理解做了一下,因个人水平有限(不谦虚,确实很菜),如果个人做的有什么不对的欢迎指出来,共同交流

作者:诗和元芳
链接:https://www.jianshu.com/p/e6e...
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

笔试

题目一

<div id="d">
    <div id = "a"></div>
    <div id = "b"></div>
    <div id = "c"></div>
</div>
<script>
    var a = [document.getElementById('a'),document.getElementById('b'),document.getElementById('c')];
    var b = [document.getElementById('d').getElementsByTagName('div')];
</script>
问a 和 b 的区别

我们把结果打印出来看一下:

a
刷面试题之<<携程 地面业务 前端面试经历>>

b
刷面试题之<<携程 地面业务 前端面试经历>>

看MDN官方对Element.getElementsByTagName()这个说法的解释:
Element.getElementsByTagName()方法返回一个动态的包含所有指定标签名的元素的HTML集合HTMLCollection。指定的元素的子树会被搜索,不包括元素自己。返回的列表是动态的,这意味着它会随着DOM树的变化自动更新自身。所以,使用相同元素和相同参数时,没有必要多次的调用Element.getElementsByTagName() .”

很多人(包括我和作者)都会以为这题差别是在b返回的是二维数组,其实都是想当然了。
a返回的是一个包含三个dom元素的数组,而b返回的是只有一个HTMLCollection元素的数组。这是完全的两种结构且HTMLCollection并不继承自Array.

  • 1、HTMLCollection是及时更新的,当文档中的DOM变化时,它是会随之变化的
  • 2、HTMLCollection可以用 HTMLCollection.item()HTMLCollection.namedItem() 这种方式来获取内部元素。

题目二 数组去重

请手打一个数组去重的方法,题目是[1,2,3,2].distinct() = [1,2,3]。

关于数组去重的方法有很多,网上资料太多不再赘述,作者用的是一种hash去重的方法。

Array.prototype.distinct = Array.prototype.distinct || function(){
            var len = this.length,
                  i = 0,
                  hash = {},
                  myArr = [];
        for(; i < len; i ++){
                  if(!hash[this[i]]){
                      hash[this[i]] = true;
                      myArr.push(this[i])
                  }
        }
    return myArr;
}

这种方法可以达到题目中的要求,但并不是一种严谨的数组去重方式。
假设我们的的数组变成[1,2,3,2,'1'],这种方法就无法达到去重的效果了,这种方式无法区分数字1和字符串'1',还需要通过类型判断。
关于数组去重,最简单的是ES6的:

Array.prototype.distinct = Array.prototype.distinct||function(){
    console.log(this);
    return Array.from(new Set(this)); //return [...(new Set(this))];
}

题目三,考察闭包

function mo(){
    var x = 0;
    return function(){
        console.log(++x)
    }
}
var a = mo();
var b = mo();
a();
a();
b();

答案是1,2,1。
a 和 b是不同的两个函数,分别保持着各自对不同的x的引用。

题目四

var p = [];
var A = new Function();
A.prototype = p;
var a = new A;
a.push(1);
console.log(a.length);
console.log(p.length);

答案:1,0。
这题要理解的一点是:

a.__proto__ === p

按照<<高级程序设计>>中讲解的new的过程:

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
  • 执行构造函数中的代码(为这个对象添加属性)
  • 返回新对象

我们模仿一下new这个过程发生的事:
new A =>

(funciton(){
    //第一步,把__proto__指向p(A.prototype)
    //第二步,按照p(A.prototype)的样子创造一个对象(克隆)
    var a = Object.create(A.protype);
    A.call(a);
    return a;
})()

new 如果在继承对象是没有参数的情况下,是可以不加后面的括号的,编译器会自动替你加上的。但是要记住new的没有括号优先级是低于.的,有括号是高于();

题目五,数组降维

[1,2,3,[4,5,[6,7]]]

下面是作者提供的两种写法:

function fn(arr){ 
    var tempArr = Array.from(arr.join('-'));  //join()会自动添加逗号
    for(var i = 0;i<tempArr.length;i++){ 
        if(isNaN(tempArr[i])){ 
            tempArr.splice(i,1) 
        } 
    } 
    return tempArr; 
}
function fn(arr){
         var myArr = [];
         var fn2 = function(arr2){
               for(var i = 0;i<arr2.length;i++){
                   if(Array.isArray(arr2[i])){
                        fn2.call(null,arr2[i])
                   }
                   else{
                       myArr.push(arr2[i]);
                   }
               }
         }
         fn2(arr);
         return myArr;
       }
       fn([1,2,3,[4,5,[6,7]]]);

这里再提供一种简洁的写法:

let flatten = arr => arr.reduce((pre,cur)=>{
    Array.isArray(cur)?pre.push(...flatten(cur)):pre.push(cur);
    return pre
},[])

面试

函数声明和函数表达式有什么区别

答:解析器有一个函数声明提升的过程,读取并将函数声明添加到执行环境中,Javascript在第一遍会声明函数并将它们放到源代码的顶部。使其在执行任何代码之前可用。

函数声明既然会提升,优先级是什么,和var比呢

答:函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖,也会被后面的同名函数替换。

console.log(typeof(foo));   //function
function foo(){}
var foo = 5;
foo = 5;
console.log(typeof(foo));  //number
function foo(){}

函数声明的提升为什么会比var高,编译器干了什么事情

引擎在执行javascript代码之前,会先将其进行编译,编译阶段会找到所有声明,并找到合适的作用域将它们关联起来。
Javascript在第一遍会声明函数并将它们放到源代码的顶部
函数声明提升的是整个函数,变量声明提升的仅仅是var a;这部分。

函数声明会将变量声明覆盖,而变量声明只能当做重复声明被忽略。所以函数声明的提升比var高。(纯个人理解,如有不对欢迎指出)

es6 装饰器用过没,是干什么用的(应该是es7的,反正我也没答出来,答出来肯定还继续深的问)

装饰类、装饰方法或属性。装饰器可以联想到装饰器模式:向一个现有的对象添加新的功能,同时又不改变其结构的设计模式,它是作为现有的类的一个包装。

es6中的扩展运算符...的实现原理

调用默认的iterator接口

<-------------------以下内容明天接着刷---------------------------->

es6中的解构中的...和上面的区别

答:说真的,我也不知道啥区别,不是一样用吗?

[...org,name] = [1,2,3,4] 这样的话,org里是个啥

答:开始问的放后面是啥,我想了半天,没敢说,我说难道后面的就没抓到,全被org抓走了?其实不是,直接报错了,...是rest的意思,既然是rest,那就只能放在最后啊

更新说明我还不会用,区别应该是问的es7中的解构。原理就是es6直接采用for of,也就是说,所有总有迭代器的对象都能使用扩展运算符,在es6里说不能放前面的,但是在es7里如果用于对象是可以放前面的。懂了这个,上面几题就都该会了

for of 和for in区别

答:for in 是键值对形式,for of 是输出value形式,然后for of只要是配置了迭代器,都能遍历。

this的指向问题

答:这个正常的都说了

箭头函数中的this

答:这里说的不好,我只说了用了箭头函数的话,this就被传进来了。就不需要绑定进来了。

箭头函数中的this默认指向在定义它时,它所处的对象,而不是执行时的对象, 定义它的时候,可能环境是window

什么是闭包(这里答的不太好,虽然都会用啊处理的,我用类似如下代码举例,貌似面试官并不满意...)

function aa(){
        var a = 1;
        return function bb(){
            console.log(a);
        }
    }
    aa()()

什么是作用域

答:在进入脚本标签编译阶段的时候就定义了各类作用域,外面的变量就在全局作用域,函数内部的就在函数的作用域里,作用域外的函数不能访问某个作用域里面的东西

什么是作用域链

答:在各级执行上下文创建阶段的时候,就确定了各级作用域,串起来就是作用域链了。比如闭包的时候外部函数出栈之后,内部函数还保留了对外部函数某个变量的引用,就是通过作用域链找过去的

什么是原型

答:prototype,好像我也说不出啥,就举个函数的写原型的例子。
js有哪些设计模式(我说有工厂模式,构造函数模式,原型模式,面试官说这是面向对象,不过我觉得有啥区别,面向对象编程不久是要用这些设计模式吗)
这些模式都是咋写的,我手写给他看

为什么要用原型

答:共享原型里的东西给下属继承的对象,这样在new的时候不用重新创建,节省内存空间

eval的缺点

答:我说了用法,就是可执行string,然后缺点没说,没怎么研究,只是看了一眼用法类型的

with的缺点

答:没用过,在网上看到过,说不要用,然后我就不用,应该会导致性能问题吧

在严格模式下能不能用eval

答:不能

es5和es6严格模式的区别

答:不知道

什么是柯里化,举React和Redux的例子

答:解释了柯里化是啥,举不出来例子,没看过源码啊或者是对react了解的不够多

什么是纯函数

答:不产生任何交互的函数?答的不好,我说reducer应该就是个纯函数,猜对了而已。

纯函数是指 不依赖于且不改变它作用域之外的变量状态 的函数纯函数的概念链接

页面和服务器之间的交互有哪几种(ajax,websocket,不满意)

ajax的Type有几种(我只知道post和get)

这题我可能没有理解...
get和post的区别(我说的表象区别,url参数,安全性,大小限制,面试官不是很满意)

与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用。
然而,在以下情况中,请使用 POST 请求:
无法使用缓存文件(更新服务器上的文件或数据库)
向服务器发送大量数据(POST 没有数据量限制)
发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

HTTP请求头上都有什么信息

答:UA,HOST,其他的我也没说,就说还有几个没注意..

如何统计页面上的按钮被点击了多少次

答:和服务器交互?反正也只能存服务器啊...

单页面应用和多页面应用的区别

答:一个跳页面是内部的,一个跳页面是href整页刷新的。

哪种更容易被SEO到,优化SEO

答:猜测是多页面,页面多呗...优化的不知道

上两题补充链接

cookie和localstorage区别(我说大小,安全,有效期,貌似又不是很满意)

JSON.stringify(大OBJ)的时候会有什么问题
答:性能损失。

script标签顺序怎么控制,涉及到依赖必须要有先后

答:在HTML层就控制顺序呗,显然不是他要的答案

除了直接引用script标签,如果不用import require这样的东西,怎么调用其它页面的js

答:真不知道,a.js里除了用script标签引用b.js

import和require的区别

答:import是静态加载,一旦你import,内容就进来了,require是动态加载,用的时候才加载,后面又问了一些,后面就不会了

函数节流怎么实现

答:简单是settimeout,时间超出就执行,没超出再进来的话就直接clear掉。面试官觉得太简单了。

canvas 绘制原理

答:不知道

如何使用canvas拖动一个小球撞击另外一个小球,然后另外一个小球被撞击出去
答:canvas一年半没用铁定不记得了(总共也就2年经验),但是说了一下实现思路

canvas 里有很多小球时如何优化性能

答:不知道

微信小程序跳转页面最多能跳转多少层 不会

RN中listview 的key值的实现原理 不会

然后还问了一些关于项目上的问题,以及如何设计一个搜索组件,需要考虑到哪些问题。
应该就这些,没想起来的想起来再补充,感觉答的不好,很多都不记得了。
三分之一的题目 比如实现原理啊,缺点啊,为什么啊,会有什么问题啊,此类问题要么不会,要么答的不好
总共就这么多,我要继续巩固基础了~!!!!!!!

相关推荐