面试题
1. es6新语法有什么?
let与const
暂时性死区,变量声明之前不能访问,变量不能同名覆盖,const声明的变量在初始化之后不能修改,对象只能修改自身属性值,不能修改引用地址
arrow functions(箭头函数)
用箭头函数来写比原来的function写法要简洁很多(针对匿名函数使用)。箭头函数与传统的JavaScript函数主要区别在于以下几点:1.对 this 的关联。函数内部的 this 指向,取决于箭头函数定义的位置,而非箭头函数的调用对象。2.new 不可用。箭头函数不能使用 new 关键字来实例化对象,不然会报错。3.this 不可变。函数内部 this 不可变,在函数体内整个执行环境中为常量。4.没有arguments对象。更不能通过arguments对象访问传入参数。5.箭头函数没有prototype属性
template string((字符串模板)
// ES6中字符串模板使用反引号 ` ` 表示,字符串模板中可以解析变量和函数,使用 ${ } 解析
var sname = "小错";
function fnAge(){
return 18;
}
var str = `大家好,我叫${sname},我今年${fnAge()}岁了`;
alert( str );
字符串模板非常有用,当我们要插入大段的html内容到文档中时,传统的写法非常麻烦
var box = document.getElementById('box');
var val1 = 11, val2 = 22, val3 = 33;
box.innerHTML = '<ul><li>'+val1+'</li><li>'+val2+'</li><li>'+val3+'</li></ul>';
box.innerHTML = '<ul>'+
'<li>'+val1+'</li>'+
'<li>'+val2+'</li>'+
'<li>'+val3+'</li>'+
'</ul>';
使用ES6字符串模板:
box.innerHTML = `
<ul>
<li>${val1}</li>
<li>${val2}</li>
<li>${val3}</li>
</ul>
`;
函数后面跟字符串模板,函数内部第一个参数一定是数组
Destructuring(解构赋值)
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。解构赋值:解析结构进行赋值。
Let a = 1;
Let b = 2;
[b,a] = [a,b]
函数的默认参数
三个点(...)
扩展运算符用三个点号表示,其功能是把数组或类数组对象(部署了iterator接口)展开成一系列用逗号隔开的参数序列。
rest运算符也是三个点,其功能与扩展运算符恰好相反,把逗号隔开的参数序列组合成一个数组
Set 和 Map
ES6 提供了两种新的数据结构 Set 和 Map。
使用ES6的 for of 遍历(数组,类数组)
for in:
-
一般用于遍历对象的可枚举属性。以及对象从构造函数原型中继承的属性。对于每个不同的属性,语句都会被执行。
-
不建议使用for in 遍历数组,因为输出的顺序是不固定的。
-
如果迭代的对象的变量值是null或者undefined, for in不执行循环体,建议在使用for in循环之前,先检查该对象的值是不是null或者undefined
for of
- for…of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
Symbol类型
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。
数组新增方法
Array.from,Array.of,find,findIndex,fill,includes
ES6 类与继承
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念。新的class写法让对象原型的写法更加清晰、更像面向对象编程的语法,也更加通俗易懂。
Object扩展
Object.getOwnPropertySymbols(obj)
Object.setPrototypeOf(obj1,obj2)
Object. getOwnPropertyDescriptors(obj)
Object.values(obj)
Object.entries(obj)
Object.assign(target,source)//方法是一种对象浅拷贝,如果对象属性是引用类型,只能是拷贝引用地址
Object.is(val1,val2)//方法用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
ES6 模块化
2. let,var,const区别
- var 声明的变量存在变量提升,let & const 声明的变量,在声明之前使用会报错,而 const 声明必须在声明的同时为其赋值;
- ES6 新增了块级作用域,变量以及函数声明在块级作用域内的表现与在函数作用域内的声明不同,但是一些浏览器可以有自己的规则,保证老代码的运行正确;
- const 声明的变量如果是基础类型,不能被修改。如果是引用类型,则可以修改引用类型的属性。
3. let作用域问题
JS里的作用域可以分为 : 1.全局作用域 2.局部作用域 3.块级作用域
重点:
var 在 单独的 { } 中声明的变量,是一个全局变量
let 在 单独的 { } 中声明的变量 , 是一个局部变量
也就是说在块级作用域下,var声明的变量是全局变量 , let声明的变量是局部变量
{
var b = 2
let a = 0
}
console.log(b)
console.log(a)
// a is not defined
function xx(){
var a = 0
}
console.log(a)
// a is not defined
最后,无论是块级作用域还是局部作用域,省略变量前面的let或者var就会变成一个全局变量
4.async await原理如何实现的
他们的前身,来源于 generator + co,这样的⼀个组合,来实现了⼀个异步解决的最优解,不单纯的靠回调函数和Promise。⽽是把异步代码,同步化。
// 定义了一个promise,用来模拟异步请求,作用是传入参数++
function getNum(num){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num+1)
}, 1000)
})
}
//自动执行器,如果一个Generator函数没有执行完,则递归调用
function asyncFun(func){
var gen = func();
function next(data){
var result = gen.next(data);
if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
}
next();
}
// 所需要执行的Generator函数,内部的数据在执行完成一步的promise之后,再调用下一步
var func = function* (){
var f1 = yield getNum(1);
var f2 = yield getNum(f1);
console.log(f2) ;
};
asyncFun(func);
async/await非常好理解,基本理解了Generator函数之后,几句话就可以描述清楚。这里没有过多的继续阐述Generator函数的内部执行逻辑及原理,如果有对此有深入理解的童鞋,欢迎补充说明。
5.手写节流
function throttle(delay,fnName){
var lastTime,timer;
return function (){
var nowTime = Date.now();// 当前的时间
if (lastTime && (nowTime - lastTime) < delay) {
clearTimeout(timer);
timer = setTimeout(function (){
lastTime = Date.now();
fnName();
},delay)
} else {
lastTime = nowTime;
fnName();
}
}
}
// 函数防抖:降低事件触发的频率
// 在指定时间内如果重复触发事件,只执行最后一次
// 函数节流:降低事件触发的频率
// 在指定时间内如果重复触发事件,每隔一段时间执行一次事件
6.跨域问题
第一种:通过服务端代理请求。如PHP,服务端语言php是没有跨域限制的。
第二种:jsonp跨域- jsonp跨域就是利用script标签的跨域能力请求资源- 既然叫jsonp,显然目的还是json,而且是跨域获取
第三种:CORS 跨域资源共享(xhr2)- CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)- 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制- 整个CORS通信过程,都是浏览器自动完成,不需要用户参与- 对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样- 实现CORS通信的关键是服务器,只要服务器实现了CORS接口,就可以跨源通信
第四种:nginx代理跨域
7.jsonp如何请求的
Jsonp原理:jsonp跨域利用script标签的跨域能力请求资源
Jsonp步骤:利用js创建一个标签,把json的url赋给script的src属性,把这个script插入到页面里,让浏览器去跨域获取资源 jsonp只针对get请求
8.手写下url链接
https://www.baidu.com/?a=5&b=6#1232
9.fetch返回的是什么
const result = fetch('http://localhost:8000/api/goods/detail?id=1318002')
.then(response=>{
console.log(response);
//
return response.json()
/*
body: (...)
bodyUsed: true
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "cors"
url: "http://localhost:8000/api/goods/detail?id=1318002"
*/
})
.then(data=>{
console.log(data);
// data服务器返回的具体数据
})
console.log(result);//Promise {<pending>}
10.vue组件的通信
1、props/$emit
父组件通过绑定属性来向子组件传递数据,子组件通过 props 属性来获取对应的数据;子组件通过 $emit 事件向父组件发送消息,将自己的数据传递给父组件。
props使得父子之间形成一种单向数据流,父元素更新的时候,子元素的状态也会随之改变。但反之会导致你的应用的数据流向难以理解。
2、$emit/$on
eventBus事件总线
描述:
这个方法是通过创建一个空的 vue 实例,当做 $emit 事件的处理中心(事件总线),通过他来触发以及监听事件,方便的实现了任意组件间的通信,包含父子,兄弟,隔代组件。
3、Vuex
在做中大型的单页应用的时候,例如需要多人协作开发,全局维护登录状态等,我们可以选择vuex来进行状态管理。
11.手写下简单的类似于vue双向绑定的实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" id="ipt">
<p id="txt"></p>
<script>
var data = {// 数据
msg: '',
num: 123
}
ipt.oninput = function (){
data.msg = ipt.value;
}
Object.defineProperty(data,'msg',{
configurable: true,
enumerable: true,
get(){
return this._msg;
},
set(val){
this._msg = val;
txt.innerText = val;
ipt.value = val;
}
});
</script>
</body>
</html>

浙公网安备 33010602011771号