荔枝FM的前端笔试题

前言:正所谓金三银四,我也在三月份面了一次荔枝FM,初试是作一套比较简单的笔试题,发出来跟你们简单探讨一下,面试时的一些问题主要是经过这些笔试题进行拓展,例如flex布局、改变正则条件,promise事件机制等等,会在下一篇文章中提到,这篇文章仅为初面的笔试题javascript

一、变量提高和函数提高

function outter () {
    return inner;
    function inner () {}
    var inner;
    inner = 9;
}
//问题是下面代码执行输出值是什么:
typeof outter();
复制代码

答案:这道题不单只是考变量提高,由于这里还有函数提高,那就是还要考函数提高和变量提高究竟谁优先级更高了。css

根据 《你不知道的JavaScript(上卷)》 里的说法,js引擎在解释代码以前会先进行编译,编译阶段会将全部的变量声明和函数声明与相关做用域关联起来,而且将这些声明提高到做用域顶部,而后到代码执行阶段才会进行变量赋值。html

虽然第一行代码就是return inner, 可是根据上面的结论,var inner的变量声明和function inner() {}的函数声明会第一时间被提高到顶部。java

那么剩下的问题就是究竟函数优先仍是变量优先,答案天然也在书中找获得,那就是函数优先,函数优先提高后,因为inner已经被声明为函数变量,后面var inner编译器进行LHS,也就是左查询,发现同一做用域中已经有该值会忽略该变量声明,所以这题的答案是字符串'function';面试

 

二、用html和css实现一个宽度为屏幕45%的正方形,可以使用最新标准

<html>
    <div class="box"></div>
</html>
<style> .box { width: 45vw; height: 45vw; } </style>
复制代码

我这是使用最新标准也最简单的实现方式了,你们能够在评论写一写本身的实现方式。正则表达式

 

三、写出6个div元素的堆叠顺序,最上面的在第一个位置,例如: .one .two .three .four .five .six(z-index)

html:数组

<div class="one">
	<div class="two"></div>
    <div class="three"></div>
</div>
<div class="four">
    <div class="five"></div>
    <div class="six"></div>
</div>
复制代码

css:promise

.one {
    position: relative;
    z-index: 2;
    .two {
        z-index: 6;
    }
    .three {
        position: absolute;
        z-index: 5;
    }
}
.four {
    position: absolute;
    z-index: 1;
    .five {}
    .six {
        position: absolute;
        top: 0;
        left: 0;
        z-index: -1;
    }
}
复制代码

PS:其实这道题代码写的不大好,由于没有div宽度和高度,甚至.one和.four也不重叠,就算本身把代码跑起来也是没法看出是否重叠的,所以须要本身去加点东西,不过主要知道考点是什么就行了。app

解析以下:从w3c的文档能够知道,z-index属性设置一个定位元素沿 z 轴的位置,z 轴定义为垂直延伸到显示区的轴。若是为正数,则离用户更近,为负数则表示离用户更远。异步

  1. 没有定位的元素z-index是不生效的
  2. 定位元素拥有更高堆叠顺序的元素老是会处于堆叠顺序较低的定位元素的前面
  3. 子元素必然在父元素的前面,不论是否是定位元素
  4. 同级定位元素的z-index相同时遵循“后来居上”,后面的定位元素堆叠顺序更前
  5. z-index小于0的定位元素处于全部元素的后面,仅在层叠上下文的背景颜色和边框前面

经过上面几点能够得出答案是 .three .two .one .five .six .four,可是这只是元素层叠顺序的冰山一角,更深刻的了解能够读一下张旭鑫大神的文章。

还有疑问的能够直接经过代码看效果:元素z-index的堆叠顺序

拓展阅读:深刻理解CSS中的层叠上下文和层叠顺序

 

四、写出能匹配如下两个要求的正则表达式

(1)字符串长度为8-12

(2)字符串只包含英文和数字

这道题算是送分题,只要对正则有所了解就能答出,并且答案不止一个,你们能够写写看本身的答案

/(\d|[A-z]{8,12})/
复制代码

 

五、四个请求接口分别是/a、/b、/c、/d,算出最快请求回来的那个接口的耗时时长(可用setTimeout模拟异步请求)

function a () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('/a');
        }, 1000);
    });
 }
function b () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('/b');
        }, 2000);
    });
}
function c () {
   	return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('/c');
        }, 500);
    });
}
function d () {
 	return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('/d');
        }, 3000);
	});
}
// Promise.race竞赛方法在第一个请求resolve后就立马进入then,能够算出最快接口的时间
const startTime = new Date / 1;
Promise.race([a(), b(), c(), d()]).then(o => {
    const endTime = new Date / 1;
    console.log(`接口${o}最快完成请求,请求时长为${endTime - startTime}`);
});
复制代码

 

六、实现一个模态框dialog

要求:构造函数不能直接执行,必须使用new,每一个实例不互相影响参数列表以下

参数名 类型 默认值
title String XXXX(不记得了)
body String ''
cancelText String 取消
okText String 确认

具备show和close方法,能够经过on绑定相关事件,off解绑相关事件。

须要达成效果以下:

let dialog = new Dialog();
dialog.on('show', () => {
   console.log('Dialog Show'); 
});
dialog.on('close', () => {
   console.log('Dialog Close'); 
});

dialog.show(); // 输出Dialog Show;
setTimeout(() => {
    dialog.close(); // 输出Dialog Close;
}, 3000);
复制代码

答案:这道题看起来也是少了不少细节, 不过这是一种经常使用的弹窗组件,所以咱们能够本身给它补上应有的功能。

class Dialog {
  // show方法的回调函数数组
  showCallbacks = [];

  // close方法的回调函数数组
  closeCallbacks = [];

  // 构造函数初始化参数
  constructor(options) {
    this.options = Object.assign(
      {
        title: "title",
        body: "是否确认是一个dialog",
        cancelText: "取消",
        okText: "确认"
      },
      options
    );
    document.body.appendChild(this.renderTemplate());
    this.initEvent();
  }

  // 渲染弹窗模板方法
  renderTemplate() {
    const { title, body, cancelText, okText } = this.options;
    this.container = document.createElement("div");
    this.container.classList = "dialog-container";
    this.container.innerHTML = `<div class="dialog-title">${title}</div> <div class="dialog-body">${body}</div> <div class="dialog-footer"> <div class="dialog-confirm">${okText}</div> <div class="dialog-cancel">${cancelText}</div> </div>`;
    return this.container;
  }
    
  // 初始化事件
  initEvent() {
    this.container
      .querySelector(".dialog-confirm")
      .addEventListener("click", () => {
        this.close();
      });
    this.container
      .querySelector(".dialog-cancel")
      .addEventListener("click", () => {
        this.close();
      });
  }

  // 事件绑定
  on(type, callback) {
    if (!callback || typeof callback !== "function")
      throw new Error("callback必须是函数");
    this[`${type}Callbacks`].push(callback);
  }

  // 事件解绑
  off(type, callback) {
    if (callback && typeof callback === "function") {
      // 将函数toString后在回调数组中查找对比。
      callback = callback.toString();
      this[`${type}Callbacks`].forEach((v, i) => {
        // 一样的回调函数将一次性所有解绑
        if (v.toString === callback) {
          // 删除事件回调数组中的值
          this[`${type}Callbacks`].splice(i, ++i);
        }
      });
      return;
    }

    // 若是不传callback,清空整个回调函数数组
    this[`${type}Callbacks`] = [];
  }

  // show方法,执行show回调函数数组
  show() {
    this.container.style.display = "block";
    this.showCallbacks.forEach(callback => {
      callback();
    });
  }

  // close方法,执行close回调函数数组
  close() {
    this.container.style.display = "none";
    this.closeCallbacks.forEach(callback => {
      callback();
    });
  }
}

复制代码

示例代码:实现一个Dialog弹窗

最后这道题其实有两道题,选择其中之一做答,不过期间有限,我没作另外一道题因此没记住问题是什么,顺便吐槽一下那个答题页面打代码时真的很不顺手,严重影响答题效率。

 

上面的答案可能并不必定对或者并非最佳答案,毕竟我的答案或有缺漏,但愿有更好答案的朋友能够在评论写一下,谢谢你们的阅读。

相关文章
相关标签/搜索