前端面试题总结

导读:本篇文章讲解 前端面试题总结,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

手写题:实现柯里化

预先设置一些参数

柯里化是什么:是指这样一个函数,它接收函数 A,并且能返回一个新的函数,这个新的函数能够处理函数 A 的剩余参数

function createCurry(func, args) {
  var argity = func.length;
  var args = args || [];

  return function () {
    var _args = [].slice.apply(arguments);
    args.push(..._args);

    if (args.length < argity) {
      return createCurry.call(this, func, args);
    }

    return func.apply(this, args);
  }
}
复制代码

前端进阶面试题详细解答

快排–时间复杂度 nlogn~ n^2 之间

题目描述:实现一个快排

实现代码如下:

function quickSort(arr) {
  if (arr.length < 2) {
    return arr;
  }
  const cur = arr[arr.length - 1];
  const left = arr.filter((v, i) => v <= cur && i !== arr.length - 1);
  const right = arr.filter((v) => v > cur);
  return [...quickSort(left), cur, ...quickSort(right)];
}
// console.log(quickSort([3, 6, 2, 4, 1]));
复制代码

代码输出结果

function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property;
};

function SubType(){
    this.subproperty = false;
}

SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
    return this.subproperty;
};

var instance = new SubType();
console.log(instance.getSuperValue());
复制代码

输出结果:true

实际上,这段代码就是在实现原型链继承,SubType继承了SuperType,本质是重写了SubType的原型对象,代之以一个新类型的实例。SubType的原型被重写了,所以instance.constructor指向的是SuperType。具体如下:

页面有多张图片,HTTP是怎样的加载表现?

  • HTTP 1下,浏览器对一个域名下最大TCP连接数为6,所以会请求多次。可以用多域名部署解决。这样可以提高同时请求的数目,加快页面图片的获取速度。
  • HTTP 2下,可以一瞬间加载出来很多资源,因为,HTTP2支持多路复用,可以在一个TCP连接中发送多个HTTP请求。

说一下JSON.stringify有什么缺点?

1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式
2.如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的结果将只得到空对象;
3、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
4、如果obj里有NaNInfinity-Infinity,则序列化的结果会变成null
5JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
6、如果对象中存在循环引用的情况也无法正确实现深拷贝;
复制代码

什么是原型什么是原型链?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

</body>
<script>
    function Person () {    }    var person  = new Person();    person.name = 'Kevin';    console.log(person.name) // Kevin

    // prototype
    function Person () {    }    Person.prototype.name = 'Kevin';    var person1 = new Person();    var person2 = new Person();    console.log(person1.name)// Kevin
    console.log(person2.name)// Kevin

    // __proto__
    function Person () {    }    var person = new Person();    console.log(person.__proto__ === Person.prototype) // true

    //constructor
    function Person() {    }    console.log(Person === Person.prototype.constructor) // true

    //综上所述
    function Person () {    }    var person = new Person()    console.log(person.__proto__ == Person.prototype) // true
    console.log(Person.prototype.constructor == Person) // true
    //顺便学习一下ES5得方法,可以获得对象得原型
    console.log(Object.getPrototypeOf(person) === Person.prototype) // true

    //实例与原型
    function Person () {    }    Person.prototype.name = 'Kevin';    var person = new Person();    person.name = 'Daisy';    console.log(person.name) // Daisy
    delete person.name;    console.log(person.name) // Kevin

    //原型得原型
    var obj = new Object();    obj.name = 'Kevin',    console.log(obj.name) //Kevin

     //原型链
     console.log(Object.prototype.__proto__ === null) //true
     // null 表示"没用对象" 即该处不应该有值

     // 补充
     function Person() {     }     var person = new Person()     console.log(person.constructor === Person) // true
     //当获取person.constructor时,其实person中并没有constructor属性,当不能读取到constructor属性时,会从person的原型
     //也就是Person.prototype中读取时,正好原型中有该属性,所以
     person.constructor === Person.prototype.constructor

     //__proto__
     //其次是__proto__,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于Person.prototype中,实际上,它
     // 是来自与Object.prototype,与其说是一个属性,不如说是一个getter/setter,当使用obj.__proto__时,可以理解成返回了
     // Object.getPrototypeOf(obj)
     总结:          1、当一个对象查找属性和方法时会从自身查找,如果查找不到则会通过__proto__指向被实例化的构造函数的prototype     2、隐式原型也是一个对象,是指向我们构造函数的原型     3、除了最顶层的Object对象没有__proto_,其他所有的对象都有__proto__,这是隐式原型     4、隐式原型__proto__的作用是让对象通过它来一直往上查找属性或方法,直到找到最顶层的Object的__proto__属性,它的值是null,这个查找的过程就是原型链



</script>
</html>
复制代码

Vuex有哪些基本属性?为什么 Vuex 的 mutation 中不能做异步操作?

有五种,分别是 State、 Getter、Mutation 、Action、 Module
1、state => 基本数据(数据源存放地)
2、getters => 从基本数据派生出来的数据
3、mutations => 提交更改数据的方法,同步
4、actions => 像一个装饰器,包裹mutations,使之可以异步。
5、modules => 模块化Vuex

1、Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现,这样可以方便地跟踪每一个状态的变化,从而能够实现一些工具帮助更好地了解我们的应用。
2、每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。
复制代码

说一下怎么取出数组最多的一项?

// 我这里只是一个示例
const d = {};
let ary = ['赵', '钱', '孙', '孙', '李', '周', '李', '周', '周', '李'];
ary.forEach(k => !d[k] ? d[k] = 1 : d[k]++);
const result = Object.keys(d).sort((a, b) => d[b] - d[a]).filter((k, i, l) => d[k] === d[l[0]]);
console.log(result)
复制代码

localStorage sessionStorage cookies 有什么区别?

localStorage:以键值对的方式存储 储存时间没有限制 永久生效 除非自己删除记录
sessionStorage:当页面关闭后被清理与其他相比不能同源窗口共享 是会话级别的存储方式
cookies 数据不能超过4k 同时因为每次http请求都会携带cookie 所有cookie只适合保存很小的数据 如会话标识
复制代码

常见的水平垂直方式有几种?

//利用绝对定位,先将元素的左上角通过 top:50%和 left:50%定位到页面的中心,然后再通过 translate 来调整元素的中心点到页面的中心。该方法需要考虑浏览器兼容问题。
.parent {
    position: relative;
}

.child {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
}
//利用绝对定位,设置四个方向的值都为 0,并将 margin 设置为 auto,由于宽高固定,因此对应方向实现平分,可以实现水平和垂直方向上的居中。该方法适用于盒子有宽高的情况:
.parent {
    position: relative;
}

.child {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
}
//利用绝对定位,先将元素的左上角通过 top:50%和 left:50%定位到页面的中心,然后再通过 margin 负值来调整元素的中心点到页面的中心。该方法适用于盒子宽高已知的情况
.parent {
    position: relative;
}

.child {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -50px;     /* 自身 height 的一半 */
    margin-left: -50px;    /* 自身 width 的一半 */
}
//使用 flex 布局,通过 align-items:center 和 justify-content:center 设置容器的垂直和水平方向上为居中对齐,然后它的子元素也可以实现垂直和水平的居中。该方法要**考虑兼容的问题**,该方法在移动端用的较多:
.parent {
    display: flex;
    justify-content:center;
    align-items:center;
}
//另外,如果父元素设置了flex布局,只需要给子元素加上`margin:auto;`就可以实现垂直居中布局
.parent{
    display:flex;
}
.child{
    margin: auto;
}
复制代码

组件之间的传值有几种方式

1、父传子
2、子传父
3、eventbus
4、ref/$refs
5、$parent/$children
6、$attrs/$listeners
7、依赖注入(provide/inject)
复制代码

Vue的生命周期是什么 每个钩子里面具体做了什么事情

Vue 实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载 等⼀系列过程,称这是Vue的⽣命周期。
1、beforeCreate(创建前) :数据观测和初始化事件还未开始,此时 data 的响应式追踪、event/watcher 都还没有被设置,也就是说不能访问到data、computed、watch、methods上的方法和数据。
2、created(创建后) :实例创建完成,实例上配置的 options 包括 data、computed、watch、methods 等都配置完成,但是此时渲染得节点还未挂载到 DOM,所以不能访问到 `$el` 属性。
3、beforeMount(挂载前) :在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。此时还没有挂载html到页面上。
4、mounted(挂载后) :在el被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html 页面中。此过程中进行ajax交互。
5、beforeUpdate(更新前) :响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM 还没有被渲染。
6、updated(更新后):在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
7、beforeDestroy(销毁前) :实例销毁之前调用。这一步,实例仍然完全可用,`this` 仍能获取到实例。
8、destroyed(销毁后) :实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染期间不被调用。
另外还有 `keep-alive` 独有的生命周期,分别为 `activated``deactivated` 。用 `keep-alive` 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 `deactivated` 钩子函数,命中缓存渲染后会执行 `activated` 钩子函数。
复制代码

什么是 JavaScript 中的包装类型?

在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象,如:

const a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
复制代码

在访问'abc'.length时,JavaScript 将'abc'在后台转换成String('abc'),然后再访问其length属性。

JavaScript也可以使用Object函数显式地将基本类型转换为包装类型:

var a = 'abc'
Object(a) // String {"abc"}
复制代码

也可以使用valueOf方法将包装类型倒转成基本类型:

var a = 'abc'
var b = Object(a)
var c = b.valueOf() // 'abc'
复制代码

看看如下代码会打印出什么:

var a = new Boolean( false );
if (!a) {
    console.log( "Oops" ); // never runs
}
复制代码

答案是什么都不会打印,因为虽然包裹的基本类型是false,但是false被包裹成包装类型后就成了对象,所以其非值为false,所以循环体中的内容不会运行。

说一下常见的HTTP状态码?说一下状态码是302和304是什么意思?你在项目中出现过么?你是怎么解决的?

    <!-- 状态码:由3位数字组成,第一个数字定义了响应的类别 -->
    <!-- 1xx:指示消息,表示请求已接收,继续处理 -->
    <!-- 2xx:成功,表示请求已被成功接收,处理 -->
    <!-- 200 OK:客户端请求成功
         204 No Content:无内容。服务器成功处理,但未返回内容。一般用在只是客户端向服务器发送信息,而服务器不用向客户端返回什么信息的情况。不会刷新页面。
         206 Partial Content:服务器已经完成了部分GET请求(客户端进行了范围请求)。响应报文中包含Content-Range指定范围的实体内容
 -->
    <!-- 3xx 重定向 -->
    <!-- 301 Moved Permanently:永久重定向,表示请求的资源已经永久的搬到了其他位置。
         302 Found:临时重定向,表示请求的资源临时搬到了其他位置
         303 See Other:临时重定向,应使用GET定向获取请求资源。303功能与302一样,区别只是303明确客户端应该使用GET访问
         307 Temporary Redirect:临时重定向,和302有着相同含义。POST不会变成GET
         304 Not Modified:表示客户端发送附带条件的请求(GET方法请求报文中的IF…)时,条件不满足。返回304时,不包含任何响应主体。虽然304被划分在3XX,但和重定向一毛钱关系都没有
 -->
    <!-- 4xx:客户端错误 -->
    <!-- 400 Bad Request:客户端请求有语法错误,服务器无法理解。
         401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。
         403 Forbidden:服务器收到请求,但是拒绝提供服务
         404 Not Found:请求资源不存在。比如,输入了错误的url
         415 Unsupported media type:不支持的媒体类型
 -->
    <!-- 5xx:服务器端错误,服务器未能实现合法的请求。 -->
    <!-- 500 Internal Server Error:服务器发生不可预期的错误。
         503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常,
 -->
复制代码

Set 和 Map有什么区别?

1、Map是键值对,Set是值得集合,当然键和值可以是任何得值
2、Map可以通过get方法获取值,而set不能因为它只有值
3、都能通过迭代器进行for...of 遍历
4、Set的值是唯一的可以做数组去重,而Map由于没有格式限制,可以做数据存储
复制代码

说一下HTTP和HTTPS协议的区别?

1HTTPS协议需要CA证书,费用较高;HTTP协议不需要
2HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;
3、使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;
4HTTP协议连接很简单,是无状态的;HTTPS协议是具有SSLHTTP协议构建的可进行加密传输、身份认证的网络协议,HTTP更加安全
复制代码

null和undefined区别

首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。

undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。

undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会影响对 undefined 值的判断。我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。

当对这两种类型使用 typeof 进行判断时,Null 类型化会返回 “object”,这是一个历史遗留的问题。当使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。

如何提取高度嵌套的对象里的指定属性?

有时会遇到一些嵌套程度非常深的对象:

const school = {
   classes: {
      stu: {
         name: 'Bob',
         age: 24,
      }
   }
}
复制代码

像此处的 name 这个变量,嵌套了四层,此时如果仍然尝试老方法来提取它:

const { name } = school
复制代码

显然是不奏效的,因为 school 这个对象本身是没有 name 这个属性的,name 位于 school 对象的“儿子的儿子”对象里面。要想把 name 提取出来,一种比较笨的方法是逐层解构:

const { classes } = school
const { stu } = classes
const { name } = stu
name // 'Bob'
复制代码

但是还有一种更标准的做法,可以用一行代码来解决这个问题:

const { classes: { stu: { name } }} = school

console.log(name)  // 'Bob'
复制代码

可以在解构出来的变量名右侧,通过冒号+{目标属性名}这种形式,进一步解构它,一直解构到拿到目标数据为止。

什么是闭包

闭包是一种特殊的对象,它由两部分组成:执行上下文(代号 A),以及在该执行上下文中创建的函数 (代号 B),当 B 执行时,如果访问了 A 中变量对象的值,那么闭包就会产生,且在 Chrome 中使用这个执行上下文 A 的函数名代指闭包。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/94138.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!