- 1、讲一下let、var、const的区别
- 2、面向对象中new都做了哪些事情(面试可让其实现一个new的伪代码)
- 3、什么是闭包, 闭包的应用场景有哪些
- 4、简述一下关于数组方法中 forEach/map/filter()区别和用法
- 5、说一下基础数据类型和引用数据类型都包含哪些
- 6、其它类型值转换为boolean类型时, 哪五个值为false, 其余都为true
- 7、vue中组件的通信方式有哪些
- 8、vue中computed和watch的区别是什么
- 9、vue中数组更新检测中的变异方法有哪些
- route的区别">10、简述一下vue-router中
route的区别
- 11、在vue-router中怎样实现路由的懒加载
- 12、描述一下vuex的原理及其中几个核心概念的作用
- 13、对比一下前端三大框架, 各自的优势是什么
- 14、开放题:我们怎样去选择一款JavaScript框架
- 15、什么算作跨域,解决前端跨域问题的方案有哪些
- 16、减少http请求次数或者请求文件大小的方法
- 17、css中水平居中的方式有哪些
- 18、css中怎样实现单行文本省略和多行文本省略
- 19、分别阐述一下vue和react中常用的生命周期
- 20、说明一下null和undefined的区别
- 21、传输协议的分类有哪些
- 22、Get和POST请求的区别
- 23、怎样把JQ对象转换为JS对象
- 24、简述一下JQ的插件机制
- 25、localStorage vs sessionStorage 区别
- 26、localStorage vs cookie 区别
- 27、x 和 x 的区别
- 28、谈一谈对async、await的理解
- 29、说一下冒泡排序的原理
- 30、数组去重
- 31、说一下知道的JavaScript的设计模式, 并简要说明一下其中的2种
- 32、实现一个对象的深拷贝
1、讲一下let、var、const的区别
【答案】:
- var 没有块级作用域,支持变量提升。
- let 有块级作用域,不支持变量提升。不允许重复声明,暂存性死区。不能通过window.变量名进行访问.
- const 有块级作用域,不支持变量提升,不允许重复声明,暂存性死区。声明一个变量一旦声明就不能改变,改变报错。
2、面向对象中new都做了哪些事情(面试可让其实现一个new的伪代码)
【答案】:
- 做了哪些事情
1、现在内存中创建一个新的空对象
2、new会让this指向这个新的对象
3、执行构造函数, 给这个对象添加属性和方法
4、返回这个心的对象
- 实现伪代码
function _new(){
let obj = new Object();
let Con = [].shift.call(arguments);
obj.__proto__ = Con.prototype;
let result = Con.apply(obj,arguments);
return typeof result === 'object' ? result : obj
}
3、什么是闭包, 闭包的应用场景有哪些
【答案】:语雀-闭包
概念:
- 闭包实际上是一种函数,所以闭包技术也是函数技术的一种,闭包能做的事情函数几乎都能做
- 闭包技术花式比较多,用法也是比较灵活的,一般开发人员在学习闭包的时候都会遇到瓶颈,主要是因为闭包技术的分界线并不明显,几乎无法用一个特点去区分
- 当一个内部函数被外部函数的变量引用时,就形成了一个闭包
应用场景:
- 函数节流
- 自定义js模块
- 封装全局变量
- 高级排它
4、简述一下关于数组方法中 forEach/map/filter()区别和用法
【答案】:
// forEach -> 用来遍历数组中的每一项
// 1.数组中有几项,那么我们传递进去的匿名回调函数就执行几次
// 2.每一次执行匿名函数的时候,还给其传递了三个参数值:数组中的当前项item,当前项的索引index,原始的数组arry
// 3.理论上forEach执行时没有返回值的,对原来的数组没有任何影响
// 4.forEach方法中的this是ary,但是回调函数中的this默认是window
ary.forEach(function(item, index, arry) {
console.log(item, index, arry);
}, obj); // 5.不管forEach,还是map都支持第二个参数值,作用是:把匿名函数中的this进行修改
// map -> 和forEach非常相似,都是用来遍历数组的
// 与forEach区别
// 1.map的回调函数中是支持return的返回值的,return是什么就相当于把数组中的那一项变为什么,但是并不会影响原数组,只是把克隆的这一份改变了
// 2.
let a = ary.map(function(item, index, arry) {
return item * 10;
});
console.log(a);
// filter 是否操作原数组 -> No
// 返回结果 -> 过滤后的新数组
// 回调函数的返回结果 -> 如果返回true,表示这一项放到新数组中
var arr = [1, 2, 3, 4, 5];
var a = arr.filter((item, index) => {
return item>2 && item<5;
});
console.log(a);//[3,4]
5、说一下基础数据类型和引用数据类型都包含哪些
// 基础数据类型
number
string 字符串
boolean 布尔
null 空对象指针
undefined 未定义
// 引用数据类型
object 对象数据类型
{} 普通对象
[] 数组
/^$/ 正则
Math 数学方法
Date 日期
function 函数数据类型
6、其它类型值转换为boolean类型时, 哪五个值为false, 其余都为true
【答案】:
- 0, NaN, “”, null, undefined
7、vue中组件的通信方式有哪些
【答案】:ref、
8、vue中computed和watch的区别是什么
【答案】:
computed属性名自定义,可以监听一个或者多个它所依赖的数据项; watch一次只能监听一个属性,而这个属性接收两个参数,一个是新值一个是旧值
computed里的自定义属性不能与data里的属性重复,否则会报错
watch里监听的属性必须是已经存在的,其要么是data里的,要么是computed里计算出来的
watch是允许异步操作的,并在我们得到最终结果前,设置中间状态,这些都是计算属性无法做到的
computed是一个对象时,有哪些选项? - get, set
computed和methods有什么区别? - methods是方法,可以接受参数,而computed不能;computed是可以缓存的,而methods不会;一般在v-for里,需要动态绑定值时,只能使用methods而不能使用computed,因为computed不能传参
computed是否能够依赖其它组件的数据? - computed可以依赖其它computed,甚至是其它组件的data
watch是一个对象时,有哪些选项? - handler(执行的函数),deep(是否深度监听),immediate(是否立即执行)
9、vue中数组更新检测中的变异方法有哪些
【答案】:push(), pop(), shift(), unshift(), splice(), sort(), reverse() 【会改变调用了这些方法的原始数组】
10、简述一下vue-router中
route的区别
【答案】:我们可以在任何组件内通过this.$router访问路由器
(方法,编程式导航),也可以通过this.$route访问当前路由
(属性参数)
11、在vue-router中怎样实现路由的懒加载
【答案】:当在打包构建的时候,javascript包会变得非常大,影响加载的速度;结合vue的异步组件和webpack的代码分割功能,可以轻松的实现路由的懒加载
// -> 一般情况下我们都会使用webpack动态import语法来定义代码分块点
// -> 如果不成功的话,可以先安装babel-plugin-syntax-dynamic-import插件,修改.babelrc文件,加入"plugins": ["syntax-dynamic-import"]
component: ()=>import('../components/Home.vue'),
12、描述一下vuex的原理及其中几个核心概念的作用
【答案】:
1、State --> State是单一的状态树,作为'唯一的数据源 ' 存在, 当一个组件需要多个状态的时候,我们可以使用mapState辅助函数来帮助我们生成计算属性
2、Getter --> 有时候我们需要从store中的state中派生出一些状态,如果有多个组件用到此属性,我们要复制很多遍这个函数,但是并不理想,vuex则提供了getter的概念; getter像计算属性一样可以根据依赖被缓存起来,并且只有当他的依赖发生改变的时候才会被重新计算
3、Mutation --> 更改Vuex的store中状态的唯一方法是提交mutation; mutation类似于事件:每一个mutation都有一个字符串类型的type(事件类型)和handler(回调函数,而这个函数就是我们实际进行状态更改的地方,并且会接收state作为其第一个参数); 我们不能直接地调用mutation回调函数,需要一个类似于事件注册的过程
4、Action --> action类似于mutation,但是和其又有很多不同点; Action提交的是mutation,而不是直接变更状态;Action支持任意的异步操作; 分发action,可以通过store.dispatch('xxx')
13、对比一下前端三大框架, 各自的优势是什么
【答案】:
三大框架的对比
14、开放题:我们怎样去选择一款JavaScript框架
【答案】:
1. 根据项目需求
2. 是否支持A级浏览器
3. 是否有利于团队协作开发
4. 是否成熟(包括文档是否健全、社区是否支持充足、扩展性)
5. 代码的执行速度、性能如何
6. 代码是否能模块化
7. 代码的可重用性怎么样
15、什么算作跨域,解决前端跨域问题的方案有哪些
【答案】:简单的理解就是:因为javascript同源策略的限制; 当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域【不同域之间相互请求资源,就算作’跨域’】
方案:jsonp、cors、websocket、postMessage、nginx
16、减少http请求次数或者请求文件大小的方法
【答案】:
采用CSS雪碧图技术
合并压缩(css/js)
采用图片懒加载技术
采用json格式进行数据传输
音频处理
304缓存处理(主要由服务器端进行处理)
使用字体图标代替icon图标
采用CDN加速
17、css中水平居中的方式有哪些
【答案】:
1、父级text-align:center, 子级display:inline-block;
2、display:table方式
3、定位方式
4、flex布局
5、display:grid网格布局
18、css中怎样实现单行文本省略和多行文本省略
【答案】:
/*文本-省略号 截断*/
.ellipsis{
word-wrap: normal;/* for IE */
-webkit-text-overflow: ellipsis;
-moz-text-overflow: ellipsis;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
/*多行位置截断*/
.line-clamp {
overflow : hidden;
-webkit-text-overflow: ellipsis;
-moz-text-overflow: ellipsis;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;/*行数*/
-webkit-box-orient: vertical;
}
19、分别阐述一下vue和react中常用的生命周期
【答案】:
vue
• beforeCreate - 组件实例刚刚创建,还未进行数据观测和事件的配置
• created - 组件实例创建完成,并且进行数据的观测和事件的配置
• beforeMount - 模板编译之前,还没有挂载
• mounted - 模板编译之后,已经挂载了,此时才会渲染完成,才能看到页面上数据的展示
• beforeUpdate - 组件更新之前
• updated - 组件更新完成
• beforeDestroy - 组件销毁之前
• destroyed - 组件销毁之后
react
1.组件加载时触发的函数
constructor componentWillMount render componentDidMount
2.组件数据更新的时候触发的生命周期函数
shouldComponentUpdate componentWillUpdate render componentDidUpdate
3.在父组件里改变props传值的时候触发的
componentWillReceiveProps
4.组件销毁的时候触发的
componentWillUnmount
20、说明一下null和undefined的区别
【答案】:null一般都是暂时没有,预期中以后会有的(可能以后也没有达到预期):在Js中null一般都是手动先赋值为null,后期再给其具体赋值; undefined完全没在预料之内的
21、传输协议的分类有哪些
【答案】:
• http - 超文本传输协议(client+server传输的内容,除了文本以外,还可以传输图片、音视频等文件流)
• https - 比http更加安全,因为数据内容的传输通道是经过ssl加密的
• ftp - 资源文件传输协议,一般用于客户端把资源文件上传到服务器端
22、Get和POST请求的区别
【答案】:
get 参数长度有限制
get会把请求的数据附加在url上
get是明文传输
get请求能缓存
post 参数长度无限制
post请求会把数据附加在请求体中
post不是明文传输
post不能缓存
23、怎样把JQ对象转换为JS对象
【答案】:
var $body = $("body");
$body[0] // -> 在集合中获取指定索引的内容(获取的内容就是原生JS对象)
$body.get(索引) // -> 等价于上面的,获取指定索引的对象,获取到的是JS对象
$body.eq(索引) // -> 获取指定索引位置的对象,但是获取的结果还是JQ对象
24、简述一下JQ的插件机制
【答案】:
• $.extend() -> 把方法扩展到JQ对象上,这个操作一般是用来完善类库的
• $.fn.extend() -> 把方法扩展到JQ原型上,供JQ实例(DOM集合)使用,这个一般是用来写JQ插件的
25、localStorage vs sessionStorage 区别
【答案】:
• localStorage属于永久存储到本地,不管是刷新页面还是关掉页面或者关掉浏览器,存储的内容不会消失,只有我们自己手动的去删除才会消失(不管是杀毒软件还是浏览器自带的清除历史记录功能都不能把localStorage存储的内容移除掉)
• sessionStorage属于临时的会话存储,只要当前的页面不关闭,信息就可以存储下来,但是页面一旦关闭,存储的信息就会自动清除(F5刷新页面只是把当前的DOM结构等进行重新的渲染,会话并没有关闭)
26、localStorage vs cookie 区别
【答案】:
• cookie
• 兼容所有浏览器
• 存储内容的大小是有限制的,一般同源下只能存储4KB的内容
• 存储的内容是有过期时间的
• localStorage
• 不兼容IE6-8
• 存储的内容也有大小限制,一般同源下只能存储5MB的内容
• 存储的内容是永久存储到本地
27、x 和 x 的区别
【答案】:
// 后缀表达式 x++ x-- ==> 先用x的当前值作为表达式的值,再进行自增自减操作 ==> 先用后变【先用变量的值参与运算,变量的值再进行自增自减运算】
var a, b ;
a = 20;
b = 30;
var res = (a++) + (b++);
console.log(res, a, b); // 50 21 31
// 前缀表达式 ++x --X ==> 先完成变量的自增自减运算, 再用x的值作为表达式的值 ==> 先变后用【变量的值先变, 再用变量的值参与运算】
var a, b ;
a = 20;
b = 30;
var res = (++a) + (++b);
console.log(res, a, b); // 52 21 31
28、谈一谈对async、await的理解
【答案】:async
async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。
进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
29、说一下冒泡排序的原理
【答案】:
//首先明确冒泡排序的思想:当前项和后一项进行比较,如果当前项大于后一项,两者交换位置
//明晰冒泡排序的规律:
(1)轮数:arry.length-1
(2)每一轮比较的次数:arry.lengh-1-i
(3)交换位置的方法:
1) 拿一个第三者
var a=12;
var b=13;
var c=null;
c=a;
a=b;
b=c;
2) 倒在一块,然后再分开
a=a+b;
b=a-b;
a=a-b;
//方法
function bubbleSort(arry){
var temp=null;
for(var i=0;i<arry.length-1;i++){
for(var j=0;j<arry.length-1-i;j++){
if(arry[j]>arry[j+1]){
temp=arry[j];
arry[j]=arry[j+1];
arry[j+1]=temp;
}
}
}
return arry;
}
如果数组简单一轮就可以达到呢?例如:var arry=[2,1,3,5,4];
优化方法:
1) 在第一轮设置一个变量var flag=false;
2) 要是有需要交换位置的,我们就让var flag=true;继续执行下一轮
3) 在下一轮开始之前又把var flag=false;
//优化后的方法如下:
function bubbleSort(arry){
var flag=false;
for(var i=0;i<arry.length-1;i++){
for(var j=0;j<arry.length-1-i;j++){
if(arry[j]>arry[j+1]){
arry[j]=arry[j]+arry[j+1];
arry[j+1]=arry[j]-arry[j+1];
arry[j]=arry[j]-arry[j+1];
var flag=true;
}
}
if(flag=true){
flag=false;
}else{
break;//已经排好序了,直接结束循环即可
}
}
}
30、数组去重
【答案】:
var arry = [1,2,2,2,3,3,5,5,7,7,9,8,8,9];
function deleteReapeat(arry){
var obj={};
for(var i=0;i<arry.length;i++){
var cur=arry[i];//数组当前项
if(obj[cur]==cur){//说明已经存在这一项了,cur重复了,需要进行删除
//把数组末尾的那一项拿过来替换当前项,再把数组末尾的那一项删除掉
arry[i]=arry[arry.length-1];
arry.length--;
//如果用splice删除的话,索引会发生改变,所以用i--来进行处理解决
i--;
continue;
}
obj[cur]=cur;
}
return arry;
}
function unique(array) {
return Array.from(new Set(array));
}
let w = unique([1, 1, 2, 3, 3]);
console.log(w) // => [1, 2, 3]
31、说一下知道的JavaScript的设计模式, 并简要说明一下其中的2种
【答案】:单例模式、工厂模式、适配器模式、装饰器模式、代理模式、外观模式
设计模式
// 工厂模式
// 理解: • 你去购买汉堡,直接点餐、取餐,并不会自己亲手做
//• 商店要封装做汉堡的工作,做好直接给买者
class Product {
constructor(name) {
this.name = name;
}
init() {
console.log('init')
}
fn1() {
console.log('fn1')
}
}
// Creator就是一个工厂,里面有一个加工函数create
class Creator {
create(name) {
return new Product(name)
}
}
let creator = new Creator();
let p = creator.create('p1');
p.init();
p.fn1();
// 单例模式
// • 系统中被唯一使用的
// • 一个类只有一个实例
class SingleObject {
login() {
console.log('login');
}
}
SingleObject.getInstance = (function() {
let instance;
return function() {
if (!instance) {
instance = new SingleObject();
}
return instance;
}
})();
let obj1 = SingleObject.getInstance();
obj1.login();
32、实现一个对象的深拷贝
function deepClone(obj) {
if (obj.isArray) {
var result = [];
} else {
var result = {};
}
for (let key in obj) {
if (typeof (obj[key]) == 'object') {
result[key] = deepClone(obj[key]);
} else {
result[key] = obj[key];
}
}
return result;
}