平时遇到的前端面试题

我最近一个多月都在忙着找工作,这些是在面试过程中遇到的一些面试题。

10 + ‘20’ = ? 再加 ‘20’ 呢?

10 + '20' = '1020' 
'1020' + '20' = '102020'

请写出 Ajax 请求中用到的函数

var xhr = new XMLHttpRequest();
xhr.open('GET/POST', 'http://localhost:8080?username=meishadevs', true);
xhr.onreadystatechange = function() {};
xhr.send();

使用正则表达式提取出url值为 https://map.baidu.com/x/y/z 中的 map.baidu.com

// 会匹配两次,第一次使用整个正则表达式去匹配,第二次使用子正则表达式去匹配,匹配结果以一个数组的形式返回
/https:\/\/([^\/]+)/.exec("https://map.baidu.com/x/y/z")[1];

// 会匹配两次,第一次使用整个正则表达式去匹配,第二次使用子正则表达式去匹配,匹配结果以一个数组的形式返回
"https://map.baidu.com/x/y/z".match(/https:\/\/([^\/]+)/)[1];

// 会采用子正则表达式去匹配,并返回与第一个子表达式匹配的结果
"https://map.baidu.com/x/y/z".replace(/^https:\/\/([^\/]+)(\/[a-z])+$/, "$1");

执行结果

使用 ES6 的方法实现数组去重

let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
let set = new Set(array);
let arr = Array.from(set);

设计一个函数实现 add(3)(4)

function add(a) {
    return function(b) {
        return a + b;
    }
}

add(3)(4)

ES6的写法

add = a => b => a + b
add(3)(4)

对ES6写法做一个变形

add = a => (b => a + b)

再变

add = function (a) {
    return (b => a + b)
}

再变

add = function (a) {
    return function (b) {
        return a + b;
    }
}

使用Ajax实现一个表单提交功能,并跳转到提交的地址,(可以使用 jQuery 或 Zepto)

$.ajax({
    url: "http://page/login",
    type: "post",
    contentType: "application/json; charset=utf-8",
    data:  JSON.stringify({
        username: "meishadevs",
        password: "000000"
    }),

    success:function (res) {
        // 跳转到首页
        window.location = "http://page/home"
    },

    error:function (error) {
        console.log("error:", error);
    }
}); 

在完成上一题后使用 Promise 再实现一遍

function sendJSON(url) {
  // 创建一个 promise 对象
  let promise = new Promise(function(resolve, reject) {
    let xhr = new XMLHttpRequest();

    // 新建一个 http 请求
    xhr.open("POST", url, true);

    // 设置状态的监听函数
    xhr.onreadystatechange = function() {
      if (this.readyState !== 4) {
        return;
      }

      // 当请求成功或失败时,改变 promise 的状态
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };

    // 设置错误监听函数
    xhr.onerror = function() {
      reject(new Error(this.statusText));
    };

    // 设置响应的数据类型
    xhr.responseType = "json";

    // 设置请求头信息
    xhr.setRequestHeader("Accept", "application/json");

    // 发送 http 请求
    xhr.send(null);
  });

  return promise;
}

JavaScript中的基本数据类型

Number、String、Boolean、Null、Undefined

一道响应式布局的题目

call、apply的作用与区别

call 和 apply 都是为了改变函数体内部 this 的指向,它们的第一个参数都是调用函数的对象,call方法接收由若干个参数组成的参数列表,apply方法接收的是一个包含多个参数的数组

例如使用call获取一组数字中的最大值

Math.max.call(null, 1, 3, 5, 8, 2)

例如使用apply获取一组数字中的最大值

Math.max.apply(null, [1, 3, 5, 8, 2])

标准盒模型和怪异盒模型的区别

标准盒模型的 box-sizing 属性的值为 content-box
怪异盒模型的 box-sizing 属性的值为 border-box
标准盒模型中 width = 内容的宽度
怪异盒模型中 width = 内容的宽度 + padding + border

em 与 rem 的区别

rem 表示根节点(html标签)的字体大小的倍数
当 em 作为 font-size 的单位时,表示相对于父元素的 font-size 值的倍数
当 em作为其他属性单位时,代表自身字体大小的倍数

localStorage 与 sessionStorage 的区别

使用 localStorage 保存的数据,除非手动清除,否则会永久保存
使用 sessionStorage 保存的数据仅在当前会话下有效,关闭页面或浏览器后会被清除

元素层叠

参考张鑫旭大神的文章:深入理解CSS中的层叠上下文和层叠顺序

使用原型现继承

使用 __proto__ 实现继承(不推荐使用这种方式)

//创建animal对象
var animal = {
    name: "animal",

    eat: function () {
        console.log(this.name + " is eating");
    }
};

//创建dog对象
var dog = {
    name: "dog",

    //指向animal对象(dog继承自animal)
    __proto__: animal
};

//创建cat对象
var cat = {
    name: "cat",

    //指向animal对象(cat继承自animal)
    __proto__: animal
};

dog.eat();
cat.eat();

使用 prototype 实现继承

//创建animal对象
var animal = {
    name: "animal",

    eat: function () {
        console.log(this.name + " is eating");
    }
};

//创建构造函数Dog
function Dog() {
    this.name = "dog";
}

//创建构造函数Cat
function Cat() {
    this.name = "cat";
}

//设置Dog的原型为animal(Dog继承自animal)
Dog.prototype = animal;

//设置Cat的原型为animal(Cat继承自animal)
Cat.prototype = animal;

//创建dog对象
var dog = new Dog();

//创建cat对象
var cat = new Cat();

dog.eat();
cat.eat();

JavaScript 中事件绑定的方式

button.onclick = function() {}

button.addEventListener("click", function () {});

设计一个函数实现判断一个数据的数据类型是不是数组

function isArray(num) {
    return num instanceof Array;
}

什么是浏览器的同源策略?

协议相同、域名相同、端口号相同

什么是浏览器的标准模式和怪异模式?

参考MDN上的一篇文章:怪异模式和标准模式

预处理CSS有什么优点和缺点?

优点:可以实现重用、自动加前缀等
缺点:浏览器不能直接识别,需要转换成 CSS

Web性能优化的手段有哪些?

1、减少HTTP请求数
2、使用CDN
3、给HTTP头部添加过期时间
4、使用Gzip压缩
5、样式表置于页面最前面
6、把JavaScript脚本放在最后面
7、使用外部的JavaScript和CSS
8、压缩JavaScript和CSS
9、如果使用小图标,可以将小图标制成一张雪碧图

常见的 HTTP 状态码有哪些?

参考我网上找到的一篇文章:HTTP常见状态码 200 301 302 404 500 - starof - 博客园

下面代码的执行结果

 var a = 1;
(function () {
    console.log(a);
    var a = 2;
    console.log(a);
})()

输出的结果是 undefined, 2
因为这里存在变量提升,所以上面的代码可以写成下面的形式

 var a = 1;
(function () {
    var a;
    console.log(a);
    a = 2;
    console.log(a);
})()

下面代码的输出结果

 var User = {
    count: 1,
    getCount: function () {
        return this.count;
    }
};

var func = User.getCount;
console.log(User.getCount());
console.log(func());

输出的结果是 1, undefined,因为第一个console输出中this指向的是User对象,count是User对象的属性,第二个console输出中this指向的是window对象,window对象中没有count属性,所以输出 undefined

如何理解this

1、构造函数中的this指向新创建的实例对象

 function Person(name, age) {
    this.name = name;
    this.age = age;

    this.printThis = function () {
        console.log(this);
    }
}

var person = new Person("meishadevs", 24);
person.printThis();

执行结果

2、普通函数中的this指向函数的调用者

function printThis() {
    console.log(this);
}

printThis();

执行结果

3、自执行函数中的this指向window对象

(function () {
    console.log(this);
})();

执行结果

4、箭头函数中的this指向函数定义时所在的对象

// 定义箭头函数,打印箭头函数中的 this
let printThis = () => {
  console.log(this);
}

let o = {
  print: function() {
    printThis()
  }
};

// 在全局调用箭头函数
printThis();

// 在对象的方法中调用箭头函数
o.print()

执行结果
通过执行结果可知我们定义的箭头函数,不管是在哪里使用 this 指向都没有发生变化都是指向函数定义时所在的对象

写出以字母开头,可以包含字母或数字的4—10位的用户密码的正则表达式

/^[a-zA-Z][a-zA-Z0-9]{3,9}$/.test(password);

实现 child 元素在 parent 元素中水平垂直居中

方法一:position + transform

.parent {
    position: relative;
}

.child {
    transform: translate(-50%, -50%);
    position: absolute;
    left: 50%;
    top: 50%;
}

方法二:使用flex布局

.parent {
    display: flex;
    justify-content: center;
    align-items: center;
}

DOM事件流包括那三个阶段

第一阶段:从window对象传导到目标节点,称为“捕获阶段”(capture phase)
第二阶段:在目标节点上触发,称为“目标阶段”(target phase)
第三阶段:从目标节点传导回window对象,称为“冒泡阶段”(bubbling phase)

写出js代码合并下列两个数组,并去重

let arr1 = [2, 6, 1, 3, 8];
let arr2 = [5, 2, 7, 6, 4];

实现代码

let arr1 = [2, 6, 1, 3, 8];
let arr2 = [5, 2, 7, 6, 4];
let arr3 = arr1.concat(arr2);
let set = new Set(arr3);
let arr4 = Array.from(set);
console.log(arr4);

下面这段代码的输出结果是,如何使它输出1、2、3、4

for (var i = 1; i < 5; i++) {
    setTimeout(function () {
        console.log(i);
    });
}

输出4个5,使用两种方法可以输出1、2、3、4

方法1:使用自执行函数

for (var i = 1; i < 5; i++) {
    (function (num) {
        setTimeout(function () {
            console.log(num);
        });
    })(i);
}

方法2:将var改成let,因为使用var声明的变量没有局部作用域,为了解决这个问题才在ES6中引入了let

for (let i = 1; i < 5; i++) {
    setTimeout(function () {
        console.log(i);
    });
}

4,4,10,10,加减乘除,怎么出24点?四个数字分别只能用一次

(10 * 10 - 4) / 4

如果你有无穷多的水,一个容积为3L的和5L的提桶,你如何准确称出4L的水

第一步:将装5L水的水桶装满                                               
装5L水的水桶中装了5L水 
装3L水的水桶没有装水

   第二步:将装5L水的水桶中的水倒入只能装3L水的水桶中,并倒满只能转3L水的水桶   
装5L水的水桶中装了2L水
装3L水的水桶中装了3L水

第三步:将装3L水的水桶中的水倒掉                                       
装5L水的水桶中装了2L水 
装3L水的水桶为空

第四步:将装5L水的水桶中的2L水倒入装3L水的水桶中                           
装5L水的水桶为空       
装3L水的水桶中装了2L水

第五步:将装5L水的水桶装满                                                
装5L水的水桶中装了5L水
装3L水的水桶中装了2L水

第六步:将装满5L水的水桶中的水倒入装3L水的水桶中,并倒满只能装3L水的水桶    
装5L水的水桶中装了4L水 
装3L水的水桶中装了3L水

如何实现快速排序

var quickSort = function (arr) {

    //如果数组中只有一个元素
    if (arr.length <= 1) {

        //直接返回改数组
        return arr;
    }

    //获得数组中中间值的索引(基准的索引)
    var pivotIndex = Math.floor(arr.length / 2);

    //获得数组中的中间值(数组中的基准)
    //并将该值从原数组中删除
    var pivot = arr.splice(pivotIndex, 1)[0];

    //创建数组,用于保存原数组中小于基准的值
    var left = [];

    //创建数组,用于保存原数组中大于基准的值
    var right = [];

    //遍历原数组
    for (var i = 0; i < arr.length; i++) {

        //如果原数组的值小于基准
        if (arr[i] < pivot) {

            //将数组的值保存到left数组中
            left.push(arr[i]);

        //如果原数组的值大于或等于基准
        } else {
            //将数组的值保存到right数组中
            right.push(arr[i]);
        }
    }

    //使用递归不断重复这个过程
    return quickSort(left).concat([pivot], quickSort(right));
};

var array = [85, 24, 63, 45, 17, 31, 96, 50];
console.log('排序前:', array);

var arr = quickSort(array);
console.log('排序后:', arr);

http 请求中的三次握手

参考链接

meishadevs欢迎任何形式的转载,但请务必注明出处,尊重他人劳动成果。
转载请注明: 【文章转载自meishadevs:平时遇到的前端面试题

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器