2021前端面试(JavaScript以及es6)持续更新

前言 :js的起源、历史

开始之前,先聊点轻松的,先来了解一下js的发展历程吧~
任何新语言的出现肯定是与他当时的需求有关系的,js全称是Javascript,诞生于1995年。最初他的诞生就是为了表单提交的时候做提示用的,在js问世之前,所有的表单都必须提交到服务端才能校验必填项。

  • 比如你想申请一个qq号,各种信息填了一大堆,提交完才知道,你手机号少输入了一位重新输入,
    那肯定砸电脑的心都有了,这个时候,js出生了,因为是跟用户做实时交互的,所以最早叫livescript,
  • 至于为什么叫Javascript,当时为了蹭蹭Java的热度,上户口的时候就改成了Javascript
  • 随着前后端分离技术发展、项目工程化,js现在已得到很大的发展,更是衍生了React、Vue等框架提高我们的开发效率,同时也出现了ts一定程度上祢补了js弱语言的缺点,相信在未来的某一天,js会站上更新的高度

虽然 JavaScript和 ECMAScript 基本上是同义词,但 JavaScript远远不限于 ECMA-262 所定义的那样。
没错,完整的 JavaScript 实现包含以下几个部分(见图 1-1):

  • 核心(ECMAScript)
  • 文档对象模型(DOM)
  • 浏览器对象模型(BOM)

html中的js

JavaScript 是通过script元素插入到 HTML 页面中的。这个元素可用于把 JavaScript 代码嵌入到
HTML 页面中,跟其他标记混合在一起,也可用于引入保存在外部文件中的 JavaScript。本章的重点可
以总结如下。

  1. 要包含外部 JavaScript 文件,必须将 src 属性设置为要包含文件的 URL。文件可以跟网页在同
    一台服务器上,也可以位于完全不同的域。
  2. 所有script元素会依照它们在网页中出现的次序被解释。在不使用 defer 和 async 属性的
    情况下,包含在script元素中的代码必须严格按次序解释。
  3. 对不推迟执行的脚本,浏览器必须解释完位于script元素中的代码,然后才能继续渲染页面
    的剩余部分。为此,通常应该把script元素放到页面末尾,介于主内容之后及body标签 之前。
  4. 可以使用 defer 属性把脚本推迟到文档渲染完毕后再执行。推迟的脚本原则上按照它们被列出 的次序执行。
  5. 可以使用 async 属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异
    步脚本不能保证按照它们在页面中出现的次序执行。
  6. 通过使用noscript元素,可以指定在浏览器不支持脚本时显示的内容。如果浏览器支持并启
    用脚本,则noscript元素中的任何内容都不会被渲染

js为什么是单线程

js从诞生之初就是单线程,那为什么是单线程呢?
为了让我们这些菜鸡更容易入门?当然不是。
js主要的用途就是操作DOM,以及与用户的交互,这就决定了他只能是单线程,
比如你这个线程创建了一个DOM,那个线程给删除了,这时候浏览器应该以哪个为准,
所以这个应该永远不会变,你前端发展的能造火箭了,js肯定也是单线程的。

Null,undefined区别

  • 在 JavaScript 中 null 表示 “什么都没有”。
  • null是一个只有一个值的特殊类型。表示一个空对象引用。

null 和 undefined 的值相等,但类型不等:

typeof undefined             // undefined
typeof null                  // object
null === undefined           // false
null == undefined            // true

在这里插入图片描述

NaN

在这里插入图片描述
在这里插入图片描述

Number底层转化原则

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

String详解

转为字符串方法:

  • 第一种 [value].toString()

在这里插入图片描述

普通对象.toString()的结果是 “[object Object]”
为什么?
Object.prototype.toString方法不是用来转化为字符串的,是用来检测数据类型的!!!

  • 第二种 字符串拼接
    在这里插入图片描述
    一道练习题:
    在这里插入图片描述

Boolean详解

在这里插入图片描述

object对象之普通对象

普通对象
[key:value,…]任何一个对象都是由0到多组键值对(属性名:属性值)组成的(并且属性名不能重复,重复的话会覆盖)
在这里插入图片描述
在这里插入图片描述

object对象之数组对象

数组对象
属于特殊对象。
也有属性值,属性名,不过属性名是默认的,从0开始连续递增(也叫索引),我们设置的是属性值
天生默认一个属性名length,存储数组的长度
在这里插入图片描述

js堆栈内存

在这里插入图片描述

js中的数据类型检测

在这里插入图片描述
typeof
在这里插入图片描述

tips
cosole.log(typeof typeof typeof [])
出现2个以上typeof 同时 检测结果都是字符串

= =和 = = =区别

= =:值相同即相等(类型不同则先转化为相同类型在比较)
= = =:必须值和类型都相同。

有关双等号的转化机制,详情点击链接https://www.jb51.net/article/126928.htm

Math常用属性和方法

  • Math.abs([number value])获取绝对值(传的不是number类型,先转化为number)
  • Math.ceil/floor([number value]) 把一个数向上/下取整。
    Math.ceil(-12.1) =>-12
    Math.floor(-12.1) => -13
  • Math.round()四舍五入
    Math.round(-12.5) => -12
  • Math.max/min([value1],[value2]…)获取一堆数中的最大值/最小值
    Math.max([1,2,3,4]) => NAN,不能传数组。
  • Math.sqrt()开平方
    Math.sqrt(-9) => NAN,负数不能开平方。
  • Math.pow(2,10)=>2的10次方=>1024。
  • Math.random()获取0-1之前的随机小数。获取【N-M】之间的随机整数?
    公式:Math.round(Math.random()*(M-N)+N)

数组中常用的方法

实现数组增删改查的方法(会改变原数组)

  • push:向数组末尾增加内容,可以多个
    返回新增后数组的长度。
    基于原生js:arr[arr.length]=“value”
  • unshift 向开头添加元素,可以添加多个
  • shift 删除数组第一项,加参数不生效。
  • pop 删除数组中最后一项
  • splice:实现数组的增删改查
    @params(n,m,x)
    n、m都是数字,从索引n开始删除m个元素,m不写默认删除到末尾
    x替换掉删除部分(m可为0,即向索引n前添加x)
    @return
    把删除的部分用新数组存储起来返回

不会改变元数组

  • slice:实现数组的查询
    @params(n,m)
    n、m都是数字,从索引n开始找到m(不包含m)
    @return
    把找到的部分用新数组存储起来返回
  • concat实现数组拼接
  • toString 把数组转化为字符串
  • join:把数组转为字符串(可以指定分隔符)
    @params 指定分隔符
    @return 转为后的字符串
  • includes \ indexOf \ lastIndexOf:查找包含

遍历数组中的每一项

forEach、filter、map、find、reduce、some、every

闭包

  • 一句话可以概括:闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放。

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包应用
在这里插入图片描述

什么是事件委托、事件冒泡(事件代理)

事件冒泡
事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点
如何阻止事件冒泡
e.cancelBubble = true;
e.stopPropagation();

cancelBubble 与 stopPropagation 区别。 他们的不同之处是:stopPropagation符合W3C标准.适用于FireFox等浏览器,不支持IE.而cancelBubble方法不符合W3C的标准.且只支持IE浏览器,所以很多时候,我们都要结合起来用。

   var body = document.querySelector("body");
   body.addEventListener("click",function (e) {
       alert("body");
       e.cancelBubble = true;
       e.stopPropagation();
   })

原文链接:https://blog.csdn.net/qq_36537108/article/details/87304803

在这里插入图片描述

事件委托
JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。一般是把一组元素的事件委托到他的父元素上,委托的优点是减少内存消耗,节约效率

防抖节流

防抖: 一个事件需要执行n秒,n秒内再次触发重新计时
例子: 模糊搜索,使用echarts改变浏览器宽度希望重新渲染

<body> 
	<input type="text" id="input">
</body>
<script type="text/javascript">
    var input = document.getElementById("input")
	
	function debounce(fn,delay){
		let timer
		return function(value){
			clearTimeout(timer)
			timer = setTimeout(function(){
					fn(value)
			},delay)
		}
	}
	function fn(value){
		console.log(value)
	}
     var deb = debounce(fn,1000)
	input.addEventListener('keyup',function(e){
		deb(e.target.value)
	})	
</script>

节流: n秒内只运行一次,若在n秒内重复触发,只有一次生效
例子 不断发送登录请求

	<body>
		<button id="btn">555</button>
		<script type="text/javascript">
			function throttle(fn,wait){
				let timeout 
				return function(){
					if(!timeout){
						timeout = setTimeout(function(){
							fn()
							timeout = null
						},wait)
					}
				}
			}

			function handle(){
				console.log(Math.random())
			}		
			document.getElementById("btn").onclick = throttle(handle,2000)
		</script>
	</body>

js eventLoop

先同步后异步
先微任务后宏任务

在这里插入图片描述在这里插入图片描述

判断数据类型种方法

call、apply、bind区别和js 的this指向

https://blog.csdn.net/xuehangongzi/article/details/80841167?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control

原型、原型链

继承

深拷贝、浅拷贝

排序算法

https://segmentfault.com/a/1190000020072884

promise

定义:

Promise 是异步编程的一种解决方案 。

两个特点 :

1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。除了异步操作的结果,其他操作都无法改变这个状态。

2)一旦状态改变,就不会再变。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。

缺点

  • 无法取消Promise,一旦新建它就会立即执行,无法中途取消。

  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

基本使用

const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 异步操作结果 */){
    resolve(value);
  } else {
    reject(error);
  }
});

 promise.then((res) => {
            console.log(res);
        }, (err) => {
            console.log(err);
        })

回调地狱

$.ajax('url1',(data1)=>{
  //数据处理
    $.ajax(data1['url2'],(data2)=>{
    //数据处理
        $.ajax(data2['url3'],(data3)=>{
         //数据处理
            $.ajax(data3['url4'],(data4)=>{
               //数据处理
                console.log("finalData",data4)
            })
        })
    })
})
new Promise((resolve, reject) => {
            //第一次网络请求
            setTimeout(() => {
                resolve('data1111')
            }, 1000)
        }).then((data) => {
            //第一次操作
            console.log(data)
            return new Promise((resolve, reject) => {
                //第2次网络请求
                setTimeout(() => {
                    resolve('data2222')
                }, 1000)
            })
        }).then((data) => {
            //第2次操作
            console.log(data)
            return new Promise((resolve, reject) => {
                //第3次网络请求
                setTimeout(() => {
                    resolve('data3333')
                }, 1000)
            })
        }).then((data) => {
            //第3次操作
            console.log("finalData",data)
        })

promise.all

一共有三个接口A、B、C,必须三个接口都成功以后,才能发起第四个请求,怎么实现呢?

let getInfoA = new Promise((resolve, reject) => {
    console.log('小A开始执行了')
    resolve()
}).then(res => {
    let getInfoB = new Promise((resolve, reject) => {
        console.log('小B开始执行了')
        resolve()
    }).then(res => {
        let getInfoC = new Promise((resolve, reject) => {
            console.log('小C开始执行了')
            resolve()
        }).then(res => {
            console.log('全都执行完了!')
        })
    })
})
  /**
         * 使用promise all
         * */
        var random1 = Math.floor((Math.random() * 5000))
        var random2 = Math.floor((Math.random() * 5000))
        var random3 = Math.floor((Math.random() * 5000))

        console.log(random1, random2, random3);

        let getInfoA = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('111执行完毕')
                resolve()
            }, random1)
        })

        let getInfoB = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('222执行完毕')
                resolve()
            }, random2)
        })

        let getInfoC = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('333执行完毕')
                resolve()
            }, random1)
        })

        Promise.all([getInfoA, getInfoB, getInfoC]).then(res => {
            console.log('全都执行完了!')
            //发起第四次请求
        })

promise.race

需求,同样是接口A、B、C,只要有一个响应了,我就可以调接口D

let getInfoA = new Promise((resolve, reject) => {
    console.log('小A开始执行了')
    setTimeout((err => {
        resolve('小A最快')
    }),1000)
})
let getInfoB = new Promise((resolve, reject) => {
    console.log('小B开始执行了')
    setTimeout((err => {
        resolve('小B最快')
    }),1001)
})
let getInfoC = new Promise((resolve, reject) => {
    console.log('小C开始执行了')
    setTimeout((err => {
        resolve('小C最快')
    }),1002)
})
Promise.race([getInfoA, getInfoB, getInfoC]).then(res => {
    console.log(res)
})

promise+ajax

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();
  });
  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出错了', error);
});

axios

axios是一个基于promise的HTTP库,可以在浏览器和node.js中。

  • 从浏览器中创建XMLHttpRequests
  • 从node.js创建http请求
  • 支持promise API
  • 拦截请求和响应
  • 转化请求数据和响应数据
  • 取消请求
  • 自动转化JSON数据
  • 客户端支持防御XSRF

取消请求

var CancelToken = axios.CancelToken
var source = CancelToken.source()
axios.get('url',{
    cancelToken:source.token
}).catch((thrown)=>{
    if(axios.isCancel(thrown)){
        console.log("Request canceled!",thrown.message)
    }else{
        //handle error
    }
})

source.cancel('Operation canceled by user.')

项目实战

Generator函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。

async、await是Generator函数的语法糖,原理是通过Generator函数加自动执行器来实现的,这就使得async、await跟普通函数一样了,不用再一直next执行了。

1、函数前面会加一个async修饰符,来证明这个函数是一个异步函数;

2、await 是个运算符,用于组成表达式,它会阻塞后面的代码

3、await 如果等到的是 Promise 对象,则得到其 resolve值。

then链式调用虽然解决了“回调地狱式的异步串行编程”,但是链式调用也带来了另一个问题,数据隔绝。即链式之间无法实现数据完全共享,他们之间只有一个通道实现数据共享,then的返回值。

p.then(()=>{
        return 数据库连接
}).then((数据库连接)=>{
        return 数据库连接.查询表数据
}).then((表数据)=>{
        对表数据做处理
        // 数据处理完成后,我想关闭数据库连接,可是发现无法获取到数据库连接
})

async function fn() {
        数据库连接 = await 获取数据库连接

        表数据 = await 数据库连接.查询表数据

        处理表数据

        关闭(数据库连接)

}

移动端h5离线缓存

manifest

for in 和 for of区别

https://blog.csdn.net/aerchi/article/details/80221274

暂时性死区(TDZ)

定义:只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

“暂时性死区”也意味着typeof不再是一个百分之百安全的操作。

typeof x; // ReferenceError
let x;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值