前端
一点也不简单

2019前端面试题积累

目录

1.const的值什么时候可以修改

对于基本类型来说const定义的就是一个常量,一旦被赋值(初始化)就不可以修改。定义一个常量但是不赋值(初始化),会报错:Missing initializer in const declaration;如果修改一个常量则会报错:Assigment to constant variable。

对于数组和对象这样的引用类型来说

发现确实被修改了,name这该怎么解释呢???实际上,const在赋值(初始化)了一个引用类型的时候,它只是保证引用类型的指针不变化,然而修改对象的属性不会变动对象的指针,所以修改一个赋值(初始化)为引用类型的const是完全被允许的

我们尝试了一下修改const为引用类型的指针

结果,不出意外的报错了。所以,const赋值(初始化)了一个引用类型的时候,是不可以去改变它的指针。

2.null和undefined的区别

null: Null类型,代表一个空值,也代表一个空对象指针,表示将来可能被指向某一个对象,使用typeof运算得到 “object”,所以你可以认为它是一个特殊的对象值。

undefined: Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined。

3.React性能优化

shouldComponentUpdate

react在每个组件生命周期更新的时候都会调用一个shouldComponentUpdate(nextProps, nextState)函数。它的职责就是返回true或false,true表示需要更新视图,false表示不需要,默认返回为true,即便你没有显示地定义 shouldComponentUpdate 函数。这就不难解释上面发生的资源浪费了。

无状态组件

当组件仅是接收 props,并将组件自身渲染到页面时,该组件就是一个 ‘无状态组件(stateless component)

高阶组件

React.addons.Perf插件来检测是否需要继续优化

3.vue/react的生命周期

4.es6的了解

es6是一个新的标准,它包含了许多新的语言特性和库,是JS最实质性的一次升级, 比如’箭头函数’、’字符串模板’、’generators(生成器)’、’async/await’、’解构赋值’、’class’等等,还有就是引入module模块的概念。

https://juejin.im/post/5b1d1fd6f265da6e410e137c

5.箭头函数

可以让this指向固定化,这种特性很有利于封装回调函数

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错     误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作Generator函数。

6.说说你对Promise的理解

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件监听——更合理和更强大。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点:
1) 对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)

2) 一旦状态改变,就不会再变,任何时候都可以得到这个结果。

7.怎么理解async/await的

字面上看: async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。

async 起什么作用

这个问题的关键在于,async 函数是怎么处理它的返回值的!

我们当然希望它能直接通过 return 语句返回我们想要的值,但是如果真是这样,似乎就没 await 什么事了。所以,写段代码来试试,看它到底会返回什么:

async function testAsync() {
    return "hello async";
}

const result = testAsync();
console.log(result);

看到输出就恍然大悟了——输出的是一个 Promise 对象。

Promise { 'hello async' }

所以,async 函数返回的是一个 Promise 对象。

await 到底在等啥

一般来说,都认为 await 是在等待一个 async 函数完成。不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值(换句话说,就是没有特殊限定)。

async/await 帮我们干了啥

上面已经说明了 async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。

async/await相对于promise来说,是更大的进步,promise需要.then链来解决回调问题,如果需要多个promise来组成then链,呢么书写会非常复杂就像这样:

/**
 * 传入参数 n,表示这个函数执行的时间(毫秒)
 * 执行的结果是 n + 200,这个值将用于下一步骤
 */
function takeLongTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 200), n);
    });
}

function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(n) {
    console.log(`step2 with ${n}`);
    return takeLongTime(n);
}

function step3(n) {
    console.log(`step3 with ${n}`);
    return takeLongTime(n);
}

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => step2(time2))
        .then(time3 => step3(time3))
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt");
        });
}

doIt();

// c:\var\test>node --harmony_async_await .
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1507.251ms

输出结果 result 是 step3() 的参数 700 + 200 = 900。doIt() 顺序执行了三个步骤,一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 计算的结果一致。

如果用 async/await 来实现呢,会是这样:

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time2);
    const result = await step3(time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt");
}

doIt();

结果和之前的 Promise 实现是一样的,但是这个代码看起来是不是清晰得多,几乎跟同步代码一样

8.箭头函数与普通函数的区别

箭头函数:

let fun = () => {
   console.log('我是箭头函数')
}

普通函数:

function fun () {
   console.log('wishing普通函数')
}

箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种只包含一个表达式,连{ … }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ … }和return。

箭头函数是匿名函数,不能作为构造函数,不能使用new

let FunConstructor = () => {
    console.log('lll');
}

let fc = new FunConstructor();

箭头函数不绑定arguments,取而代之用rest参数…解决

function A(a){
  console.log(arguments);
}
A(1,2,3,4,5,8);  //  [1, 2, 3, 4, 5, 8, callee: ƒ, Symbol(Symbol.iterator): ƒ]


let B = (b)=>{
  console.log(arguments);
}
B(2,92,32,32);   // Uncaught ReferenceError: arguments is not defined


let C = (...c) => {
  console.log(c);
}
C(3,82,32,11323);  // [3, 82, 32, 11323]

箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值

var obj = {
  a: 10,
  b: () => {
    console.log(this.a); // undefined
    console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  },
  c: function() {
    console.log(this.a); // 10
    console.log(this); // {a: 10, b: ƒ, c: ƒ}
  }
}
obj.b(); 
obj.c();
var obj = {
  a: 10,
  b: function(){
    console.log(this.a); //10
  },
  c: function() {
     return ()=>{
           console.log(this.a); //10
     }
  }
}
obj.b(); 
obj.c()();

箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响。(无法改变this指向)

let obj2 = {
    a: 10,
    b: function(n) {
        let f = (n) => n + this.a;
        return f(n);
    },
    c: function(n) {
        let f = (n) => n + this.a;
        let m = {
            a: 20
        };
        return f.call(m,n);
    }
};
console.log(obj2.b(1));  // 11
console.log(obj2.c(1)); // 11

箭头函数没有原型属性

var a = ()=>{
  return 1;
}

function b(){
  return 2;
}

console.log(a.prototype);  // undefined
console.log(b.prototype);   // {constructor: ƒ}

箭头函数不能当做Generator函数,不能使用yield关键字

总结:

  • 箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
  • 普通函数的this指向调用它的那个对象

9.vue里子组件如何向父组件传值

通过this.$emit定义一个方法,父组件通过this.$on来触发

10.js怎么判断一个对象是不是一个对象

instanceof操作符

var obj = {};
alert(obj instanceof Object); // true

对象的constructor属性

var obj = {};
alert(obj.constructor === Object); // true

Object.prototype.toString.call(obj) === ‘[Object Object]’

$.isPlainObject(Array)

11.es7新增了什么

1、Array.prototype.includes()方法

该方法接收两个参数:要搜索的值和搜索的开始索引。
 当第二个参数被传入时,该方法会从索引处开始往后搜索(默认索引值为0)。若搜索值在数组中存在则返回true,否则返回false。
 ['a', 'b', 'c', 'd'].includes('b')         // true
 ['a', 'b', 'c', 'd'].includes('b', 1)      // true
 ['a', 'b', 'c', 'd'].includes('b', 2)      // false
 ES6里数组的另一个方法indexOf与其区别:
 1、简便性:
   indexOf返回的是某个元素在数组中的下标值,若想判断某个元素是否在数组里,我们还需要做额外的处理,即判断该返回值是否>-1。而includes则不用,它直接返回的便是Boolean型的结果。
 2、精确性
 两者使用的都是 === 操作符来做值的比较。
 但是includes()方法有一点不同,两个NaN被认为是相等的,即使在NaN === NaN结果是false的情况下。
 这一点和indexOf()的行为不同,indexOf()严格使用===判断。

2、求幂运算符(**)

** 是一个用于求幂的中缀算子,比较可知,中缀符号比函数符号更简洁,这也使得它更为可取。
 基本用法
 3 ** 2           // 9
 效果同:
 Math.pow(3, 2)   // 9

12.原型链

大体上解答是:我们创造的每一个函数都有一个prototype(原型)属性。这个属性是一个指针,指向原型对 象。在默认情况下,所有的原型对象都会有一个constructor(构造函数)属性,这个属性包含一个指向prototype属相所在的指针。当调用构造函数创建一个新实例之后,该实例内部将包含一个指针(内部属性),指向构造函数的原型对象。

详细:https://juejin.im/post/5ae95290518825672c00c0a4

13.了解 JavaScript 的递归

什么时候可以用:

凡是需要您构建或遍历树状数据结构的问题基本都可以通过递归来解决

什么是递归

函数的递归就是在函数中调用自身
函数必须一步一步地接近终止条件 
必须有一个终止递归的条件,否则会死循环

14.关于this的指向问题

https://www.cnblogs.com/dongcanliang/p/7054176.html

15.理解堆和栈,以及他们的区别

http://www.blogjava.net/flysky19/articles/95964.html

Jquery的ready()与Javascrpit的load()

window.onload()

必须等待网页全部加载完毕(包括图片等),然后再执行JS代码

$(document).ready()

只需要等待网页中的DOM结构加载完毕,就能执行JS代码

不想让别人盗用你的图片,访问你的服务器资源该怎么处理?

(1)设置Referer:适合不想写代码的用户,也适合喜欢开发的用户
(2)签名URL:适合喜欢开发的用户

H5和css3新特性

详情见文章:https://www.cnblogs.com/ainyi/p/9777841.html

H5 新特性

 1.语义化标签:header、footer、section、nav、aside、article
 2.增强型表单:input 的多个 type
 3.新增表单元素:datalist、keygen、output
 4.新增表单属性:placehoder、required、min 和 max
 5.音频视频:audio、video
 6.canvas
 7.地理定位
 8.拖拽
 9.本地存储:localStorage - 没有时间限制的数据存储;sessionStorage - 针对一个 session 的数据存储,当用户关闭浏览器窗口后,数据会被删除
 10.新事件:onresize、ondrag、onscroll、onmousewheel、onerror、onplay、onpause
 11.WebSocket:单个 TCP 连接上进行全双工通讯的协议

CSS3 新特性

1.选择器
2.背景和边框
3.文本效果
4.2D/3D 转换
5.动画、过渡
6.多列布局
7.用户界面 

ajax接收到了二进制io流的图片要怎么处理

要点:转换为blob对象

var url = serverUrlBase + "/server/images/" + mapid + "/files/png";
            var xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.responseType = "blob";
            xhr.setRequestHeader("client_type", "DESKTOP_WEB");
            xhr.setRequestHeader("desktop_web_access_key", _desktop_web_access_key);
            xhr.onload = function() {
                if (this.status == 200) {
                    var blob = this.response;
                    var img = document.createElement("img");
                    img.onload = function(e) {
                        window.URL.revokeObjectURL(img.src); 
                    };
                    img.src = window.URL.createObjectURL(blob);
                    $("#imgcontainer").html(img);    
                }
            }
            xhr.send();

原文地址:https://yq.aliyun.com/articles/623464

webpack打包文件太大怎么办?

webpack 把我们所有的文件都打包成一个 JS 文件,这样即使你是小项目,打包后的文件也会非常大。可以从去除不必要的插件,提取第三方库,代码压缩,代码分割,设置缓存几个方面着手优化。

webpack 和 gulp对比

gulp

gulp强调的是前端开发的工作流程,我们可以通过配置一系列的task,定义task处理的事务(例如文件压缩合并、雪碧图、启动server、版本控制等),然后定义执行顺序,来让gulp执行这些task,从而构建项目的整个前端开发流程。

PS:简单说就一个Task Runner

webpack

webpack是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图片、js文件、css文件等)都看成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源。

PS:webpack is a module bundle

两者区别

虽然都是前端自动化构建工具,但看他们的定位就知道不是对等的。
gulp严格上讲,模块化不是他强调的东西,他旨在规范前端开发流程。
webpack更是明显强调模块化开发,而那些文件压缩合并、预处理等功能,不过是他附带的功能。

总结

gulp应该与grunt比较,而webpack应该与browserify(网上太多资料就这么说,这么说是没有错,不过单单这样一句话并不能让人清晰明了)。

gulp与webpack上是互补的,还是可替换的,取决于你项目的需求。如果只是个vue或react的单页应用,webpack也就够用;如果webpack某些功能使用起来麻烦甚至没有(雪碧图就没有),那就可以结合gulp一起用。

详细:https://www.cnblogs.com/lovesong/p/6413546.html

闭包的作用

 函数内部变量外用 || 在一个函数内部嵌套一层或多层函数
 可以将内部变量外用
 副作用: 
 违背垃圾回收机制
 ie下回造成内存泄漏
 解决副作用方案: 
 变量使用结束后删除(var a = 1) a = null
 var obj = { a: 1}  最快最好的 

sessionStorage 和 localStorage \ cookie 的区别:

git相关的知识考点

git add 干嘛的?---将需要提交的文件放到暂存区
git commit 干嘛的?---提交代码
查看历史记录怎么做?---git log
版本回退怎么做?--- git reset --hard HEAD^
发现自己回退错了,怎么取消回退?--- git reset --hard commitId
怎么撤销修改?--- git checkout --file

赞(1) 打赏
未经允许不得转载:专注前端开发和vps技术交流的博客-纸飞机 » 2019前端面试题积累

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

微信扫一扫打赏