2019前端面试题总结之三:某公司中级面试题

908 阅读7分钟

一、选择题

1.要动态改变层中的内容可以使用的方法有?

  • A:innerHTML
  • B:innerText
  • C:通过设置层的隐藏和显示来实现
  • D:通过设置层的样式属性的display属性

// 答案: A,B,注意动态改变,内容

2. 看下面的代码,给出输出的结果?

for (var i = 1; i <= 3; i++){
  setTimeout(function(){
    console.log(i);
  },0)
}
// 答案: 4 4 4 ,因为setTimeout是异步函数

推荐参考链接1 推荐参考链接2

3. 看下面代码,给出输出结果?

var a = 1;
function foo() {
  if(!a){
    var a = 2
  }
  alert(a);
}
foo()
  • A:1
  • B:2
  • C:undefined
  • D:报错

答案是:B,

涉及到的知识点有作用域,变量提升。

因为var是函数级作用域,foo函数中出现var a=2 的存在,

就默认在函数内顶端 声明var a;此时这个a没有被赋值所以是undefined;

然后执行if(!a)等价于!undefined肯定是true。然后给a赋值为2.

所以打印的是2。

二、问答题

1. 请用css实现水平居中,HTML结构如下

<div class="wrapper">
  <div class="content"></div>
</div>

答案:

/*第一种通过定位和位移(未知子模块宽高)或者margin(已知子元素宽高)*/
html,
body,
.wrapper{
  width:100%;
  height:100%;
}
.content{
  width:30%;
  height:30%;
  position:absolute;
  top:50%;
  left:50%;
  transform:tranlate(-50%,-50%);
}
/*或者*/
.content{
  width:200px;
  height:200px;
  position:absolute;
  top:50%;
  left:50%;
  margin-top:-100px;
  margin-left:-100px;
}
/*第二种通过flex布局*/
.wrapper{
  width:100%;
  height:500px;
  display:flex;
  flex-flow: row nowrap;
  /*align-items 定义子元素交叉轴也就是垂直方向的对齐方式*/
  align-items:center;  
  /*justify-content 定义子元素水平方向的对齐方式*/
  justify-content:center;
}
.content{
  width:100px;
  height:100px;
  background: red;
}

2. 下面这个ul,如何点击每一列的时候alert其index?

<ul id="test">
  <li>这是第一条</li>
  <li>这是第二条</li>
  <li>这是第三条</li>
  <li>这是第四条</li>
</ul>
  • 这算是一个闭包和作用域的的考点吧,用ES6的声明很简单。直接上答案。
const test = document.querySelector('#test');
const lis = test.querySelectorAll('li')
/*第一种用 let 声明*/
for(let i = 0; i<lis.length; i++){
  lis[i].addEventListener('click',function(e){
    console.log(i);
  },false)
//	------两种写法而已-----
//  lis[i].onclick=function() {
//    console.log(i);
//  }
}
/*第二种,用 var 声明,采用自执行函数*/
for (var i = 0; i < lis.length; i++) {
  lis[i].addEventListener(
    'click',
    (function(num) {
      return function() {
        console.log(num);
      };
    })(i),
    false
  );
}
------课外延伸,点击某一列,显示其内容的值?
  • 这是一种事件委托,也叫事件代理,是事件捕获和事件冒泡的一种运用。

举个例子,比如一个宿舍的同学同时快递到了,一种方法就是他们都傻傻地一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发给每个宿舍同学;

在这里,取快递就是一个事件,每个同学指的是需要响应事件的 DOM 元素,而出去统一领取快递的宿舍长就是代理的元素,所以真正绑定事件的是这个元素,按照收件人分发快递的过程就是在事件执行中,需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个。

  • 优点:
    • 减少内存消耗。不用给每一个 li 都绑定一个函数。绑定到ul上面,执行事件的时候去匹配判断目标元素。
    • 动态绑定事件。增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;
const test = document.querySelector('#test');

test.addEventListener(
  'click',
  function(e) {
    // 处理兼容性的问题
    const event = e || window.event;
    const target = event.target || event.srcElement;
    console.log(target.innerText);
  },
  false
);

参考事件捕获,事件冒泡,事件代理详细内容

3. 说出一下函数的作用是?空白区域应该填写说明?

(function(window) {
  function fn(str) {
    this.str = str;
  }
  fn.prototype.format = function() {
    //  var arg = '________';
    var arg = arguments;
    // return this.str.replace(_______, function(a, b, c, d) {
    return this.str.replace(/\{(\d+)\}/g, function(match, b, offset, string) {
      console.log(match); // 根据正则匹配到{}的字符串
      console.log(b); // {}中的数字字符串
      // 假如replace()方法的第一个参数是一个RegExp 对象,则代表第n个括号匹配的字符串。
      // 例如,用 /\{(\d+)\}/g 这个来匹配,b 就是匹配的 \d+。
      console.log(offset); // 该字字段在字符串中的开始索引位置
      console.log(string); // 原始字符串
      console.log(arg[b]);
      return arg[b] || '';
    });
  };
  window.fn = fn;
})(window);
//use
(function() {
  var t = new fn('<p><a href="{0}">{1}</a><span>{2}</span></p>');
  console.log(t.format('http://www.alibaba.com', 'Alibaba', 'Welcome'));
})();
  • 这个函数的作用就是格式化一段代码,将传入的参数替换掉html里面{}中的内容。类似于vue中{}的实现。

replace()函数中的b为什么会输出{}里面的内容。请参考这个链接描述那段里的第二段

4. 写一个function,清除字符串前后的空格。(兼容所有浏览器)

// 函数方法
function strTrim(str) {
  return str.replace(/(^\s+)|(\s+$)/g,'')
}
// 重写trim方法
if(!String.prototype.trim){
  String.prototype.trim=function(){
    //利用正则匹配去除字符串前后空格
    return this.replace(/(^\s+)|(\s+$)/g,"");
  }
}
const str = '    Hello,Arthas!  http://www.xueyunhao.com    '
console.log(str);
console.log(strTrim(str));
console.log(str.trim());

5. 用js实现随机选取10-100之间的10个数字,存入一个数组,并排序。

let newArray = []; // 创建一个空数组,用来存放获取的数字
// 封装一个获取10-100随机数的函数
function getRandomNumber(startNum, endNum) {
  const rangeChoice = endNum - startNum + 1; // +1 是为了能够取到100;
  const result = Math.floor(Math.random() * rangeChoice + startNum);
  return result;
}
// 循环10次获取数字并填入数组
for (let i = 0; i < 10; i++) {
  newArray.push(getRandomNumber(10, 100));
}
console.log(newArray);
// 将数组进行排序
newArray.sort(function(a, b) {
  return a - b;
});
console.log(newArray);

6. 使用js编写一个函数,能够对传入的常见对象进行clone(深拷贝)

// 第一种方法,使用JSON.parse()和JSON.stringify()对对象进行深拷贝
const arthas = {
  fn: function() {
    console.log('hello Arthas');
  },
  b: { c: 1 },
  c: [1, 2, 3],
  name: 'Arthas',
  nowDate: new Date(),
  f: null,
  g: undefined,
  n:123,
};
function deepClone(obj){
  return JSON.parse(JSON.stringify(obj))
}
const xue = deepClone(arthas);
console.log(arthas);
console.log(xue);
// 上述clone的方法会忽略function和undefined的字段,对date类型支持貌似也不友好。而且只能克隆原始对象自身的值,不能克隆它继承的值
// 对于纯数据的json对象的深克隆,可以使用JSON.parse()和JSON.stringify()方法,
// 第二种方法,
const arthas = {
  fn: function() {
    console.log('hello Arthas');
  },
  b: { c: 1 },
  c: [1, 2, 3],
  name: 'Arthas',
  nowDate: new Date(),
  f: null,
  g: undefined,
  n:123,
};
function deepClone(obj) {
  if (obj === null) {
    return null
  }
  const result = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === 'object') {
        result[key] = deepClone(obj[key]);  // 如果是对象,再次调用该方法自身
      } else {
        result[key] = obj[key];
      }
    }
  }
  return result;
}
const xue = deepClone(arthas);
console.log(arthas);
console.log(xue);

7. 某种药方要求非常严格,你每天需要同时服用A.B两种药片各一颗,不能多也不能少。这种药非常贵,你不希望有任何一点浪费。一天,你打开药片A的药瓶,倒出一粒药片放在手心,然后打开另一个药瓶,但是不小心倒出了两粒药片。现在,你手上有一颗药片A,两颗药片B,并且你无法区别哪个是A,哪个是B。你如何才能严格遵循药方服用药片,并且不能有任何的浪费?

  • 把现有的三个药片各切一半,分成两个堆。
  • 再从A药瓶中拿出一粒切半,分别放入两堆。
  • 这样今天先吃第一堆,明天再吃第二堆。

以上是经过参考很多同行分享与官方文档,汇总的一份总结,如有不对,请指出,最后感谢大家观看,求点赞,求分享,求评论,求打赏~~