2018前端常见基础面试题(精炼版)

本章内容都是作者手动整理并且尽量缩减内容,
目的就是可以让开发者短时间内回顾知识碎片和面试问题。

常规

1.js如何查找元素以及他们的区别
document.querySelector('#id'); //静态获取节点(js新增的节点无法获取)
document.getElementById('#Id'); //性能更快更高效,动态获取节点
$('#id'); //使用了第一种原生js封装而成的
2.html新特性

①添加了新元素 footer header section nav progress audio video
②新增了 canvas 画布功能,该标签是图形容器,需通过js实现图画
③新增元素拖曳功能

首先设置元素可拖曳
然后可以调用相关事件:
拖动什么 - ondragstart 和 setData()
放到何处 - ondragover
进行放置 - ondrop

④HTML5地理定位功能(需要用户同意)
⑤新增 input的类型:date week month time email tel
⑥新增web存储:sessionStorage、localStorage、webStorge
扩展:session local webStorge cookie的区别
cookie:存储空间只有4kb,在用户设定的期限后过期。
session:用户关闭当前标签页后失效,不同的标签页不共享session
local:除非浏览器中删除文件或者js删除否则一直存在
webStorge:大小扩展到 5mb,接口功能多,使用较复杂
⑦html5使用了离线存储功能,利用缓存离线访问,连网后再更新
⑧webStock:是一种浏览器和服务器可以相互通讯的协议,即服务器也可以主动发消息给浏览器。
⑨一些css3动画等

3.最常用的 Number 方法

数字转字符串

常用4中方法
let kolento = 1000+'';
kolento.toString();
kolento.toLocalString();
String(kolento);
区别扩展:
toString与toLocalString转化数字和时间的格式不同
String与上面2种相比,可以转化 null 与 undefine,
其他2种会报错,也就是他的使用范围更大
4.最常用 String 方法

①获取字符串长度

let kolento = 'hello';
kolento.length; 返回5

②返回指定位字符

let kolento = 'hello'
kolento.charAt(0) //返回第一个字符 h

③连接2个或者多个字符串

var a = 'aaa';
var b = 'bbb';
var c= 'ccc';
a.contact(b); //返回aaabbb
a.contact(b,c); //返回aaabbbccc

④检索字符串中的某个值

var kolento = 'hello';
kolento.indexOf('h'); //返回0,如果找不到返回 -1
kolento.match('h'); //返回值h,和相关对象信息

⑤替换字符串中的字符

let kolento = 'hello kolento kolento';
document.write(kolento.replace('kolento','Amiee'));
 //返回 hello Amiee kolento
document.write(kolento.replace(/kolento/g,'Amiee'));
 //返回 hello Amiee Amiee

⑥提取字符串的局部,并且返回一个新字符串
string.slice(start,end),返回内容不包括start,但是包括end(指定end情况下)

string.substr(start,length)
start:必须,开始下标,负数代表从尾部计算
length:返回长度

substring() 方法用于提取字符串中介于两个指定下标之间的字符
string.substring(start,stop) ,返回内容不包括start和stop,并且不接受负数参数

var str = 'hello happy world';
str.slice(1); //返回 ello happy world! ,开始1没有end
str.slice(4,9); //返回 lo hap 开始4,9结束
str.slice(-2)); 返回 d!,从末尾开始截取 开始-1,结尾-2

str.substr(0,7) //返回hello p
他们的区别在于第二个参数的意思不同

str.substring(2,5); //返回llo 
返回内容不包括start和stop,并且不接受负数参数

⑦split方法将字符串分割成字符
string.split(separator,howmany)
separator : 分割符号
howmany:返回的数组长度

"2:3:4:5".split(":")    //将返回["2", "3", "4", "5"]
"|a|b|c".split("|") //将返回["", "a", "b", "c"]
"hello".split("", 3)    //可返回 ["h", "e", "l"]

注意:js的字符串都是不可变的,所有的转化修改都是返回一个新的字符串。而不是修改原始的字符串。

5.最常用 arr 方法

①返回数组长度其中的个数

let kolento = [1,2,3,4,5]
kolento.length //返回5 

②连接2个或更多数组

var arr = new Array(3)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"

var arr2 = new Array(3)
arr2[0] = "James"
arr2[1] = "Adrew"
arr2[2] = "Martin"
arr.concat(arr2)
//返回 George,John,Thomas,James,Adrew,Martin

③数组组合成字符串

var arr = new Array(3);
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
arr.join();// George,John,Thomas 不添加分割符号,默认逗号
arr.join(".");// George.John.Thomas

④数组的添加与删除
pop(a) 删除返回数组的最后一项
push(a,b) 在数组最后添加一项或者多项,用逗号隔开
shift(a) 删除数组的第一项
unshift(a,b,c) 添加数组的第一项

splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。
arrayObject.splice(index,howmany,item1,.....,itemX)
index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany:必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, ..., itemX:可选。向数组添加的新项目。

var arr = new Array(6)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
arr[3] = "James"
arr[4] = "Adrew"
arr[5] = "Martin"
arr.splice(2,3,"William")
document.write(arr) //George,John,William,Martin

⑤颠倒数组的顺序

var a = 'hello';
s.reserve(); //返回 olleh

⑥slice方法截取数组中选定的部分
arrayObject.slice(start,end)截取内容不包括start,但是包括end,end是可选参数

let arr = [1,2,3,4,5]
arr.slice(1,3); //[2,3]
arr.slice(3); //[4,5]

⑦sort方法用于对数组进行排序
⑧toString() / toLocaleString()方法 ,数组转化成字符串

6.js各种循环之间的区别

①for循环:适合数组循环,性能一般
②for key in和for value of,适合json对象的循环
前者村换键,后者循环值,后者是es6新增

for(var key in obj){
  // key 键,obj代表每个对象,obj[key]代表相对应的值
} 
for(var value of obj){
  // value代表键,obj代表每个对象
} 

let aArray = ['a',123,{a:'1',b:'2'}]
for(let key in aArray){
    console.log(key); //返回 0 1 2
}
for(var value of aArray){
    console.log(value); a 123 {a:'1',b:'2'}
}

③forEach与map

let array = ['a','b','c']
array.forEach((currentValue, index, arr)=>{
  console.log(currentValue); // a b c  必选参数
  console.log(index); //0 1 2 可选参数
  console.log(arr); // abc abc abc 可选参数
})

array.map(function(currentValue,index,arr){
   console.log(currentValue); // a b c  必选参数
  console.log(index); //0 1 2 可选参数
  console.log(arr); // abc abc abc 可选参数
})

以上2者区别:
1.forEach是允许修改原始数组数据的,map的循环则是返回一个新数组。
2.forEach适合你不需要改变数据的时候使用,map可以在你改变数据的情况下使用。
3.map的性能高于forEach,快百分之70%左右

④jquery中的each

$(selector).each(function(index,element){
  //都是必须的参数
  //index - 选择器的 index 位置
  //element - 当前的元素(也可使用 "this" 选择器)
})

⑤filter过滤
filter为“过滤”、“筛选”之意。指数组filter后,返回过滤后的新数组。用法跟map极为相似:

var arr = [
  {"name":"apple", "count": 2},
  {"name":"orange", "count": 5},
  {"name":"pear", "count": 3},
  {"name":"orange", "count": 16},
];
var newArr = arr.filter((value,index,arr)=>{
  // value 当前元素的值 例如 {"name":"apple", "count": 2}
  // index 0 1 2 等
  // arr 整个数组
  return value.name === "orange"; //返回2个name是orange的数组
});
7.window.location , window.location.href , window,location.replace的区别

有3个页面 a,b,c

如果当前页面是c页面,并且c页面是这样跳转过来的:a->b->c
1:b->c 是通过window.location.replace("..xx/c") 此时b页面的url会被c页面代替,并且点击后退按钮时会回退到a页面(最开始的页面)

2:b->c是通过window.location.href("..xx/c") 此时b页面的路径会被c页面代替,但是点击回按钮后页面回退的是b页面

两者的区别: 两者后退时所回退的页面不一样

8.js各种初始化之间的区别

此处列举了4种常见的初始化方式




首页





运行下面代码。弹出A、B、D、E的顺序:A=B>D=E。
其中A和B都是在页面加载完,但是不包括图片多媒体数据加载完的情况。
C和D是在页面所有资源加载完后运行的。

9.css如何清除浮动
.clearfix:after{
   content:".";/*加一段内容*/
   display:block;/*让生成的元素以块级元素显示,占满剩余空间*/
   height:0;/*避免生成的内容破坏原有布局高度*/
   clear:both;/*清除浮动*/
   visibility:hidden;/*让生成的内容不可见*/
  }
.clearfix{zoom:1;/*为IE6,7的兼容性设置*/}
10.css中有哪些办法让一个 div 水平垂直居中

①flex布局
首先是他的兼容性,用在手机端问题不大


2018前端常见基础面试题(精炼版)_第1张图片
flex布局兼容性
里面内容会自定居中
.parents {display:flex;justify-content:center;align-items: center;}

②定义table、table-cell

.parents {display:table;width:300px;height:300px;}
.child {display:table-cell;verital:middle;text-align:center;}

③定位窗体居中,常用在弹窗上

.child {position:fixed;width:300px;height:300px;top:50%;left:50%;
margin:-150px 0 0 -150px;}
11.谈谈对ES6的认识

具体解释:https://www.jianshu.com/p/287e0bb867ae
①新增变量声明,新增变量块作用域
const:声明常量
let:声明变量
②字符串模版,代码与变量拼接的时候特别好用。
③箭头函数
继承当前上下文的 this 指向
代码省略
④拓展的对象功能
ES5我们对于对象都是以键值对的形式书写,是有可能出现键值对重名的。例如:

    function people(name, age) {
        return {
            name: name,
            age: age
        };
    }

键值对重名,ES6可以简写如下:

    function people(name, age) {
        return {
            name,
            age
        };
    }

⑤解构赋值
⑥import(导入模块) 和 export(导出模块)

12.对json的了解

是一种轻量级的数据交换格式
格式简单,容易读写
把json字符串转化为json对象

var obj =eval('('+ str +')');
var obj = str.parseJSON();
var obj = JSON.parse(str);

json对象转化json字符串

var last = obj.toJSONstring();
var last = JSON.stringify(obj);
13.jq怎么添加删除元素

添加元素:
append():在末尾添加元素
prepend():在开头添加元素
after():在某个指定元素后添加元素
before():在某个指定元素前添加元素
删除元素:
a.remove(): 删除a
a.empty():删除a的子元素

14.数组去重

①js双层循环
首先定义一个新数组,数组中存放老数组的第一个元素。
然后循环老数组与新数组对比,如果值不相同就插入进新数组,最后形成一个没有重复的数组。

function unique(arr){
 var res = [arr[0]];
 for(var i=1; i

②ES6数组去重

 let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
 let set = new Set(array);
 console.log(set);
 // => Set {1, 2, 3, 4, 5}
15.浅拷贝与深拷贝的区别

简单的来说,如果b复制了a,但是在修改b的同时,a也改变了,则是浅拷贝。因为还是指向了原来的地方,如果只改变了自身,说明是深拷贝。
案例:

let a=[0,1,2,3,4],
    b=a;
a[0]=1;
console.log(a,b);
2018前端常见基础面试题(精炼版)_第2张图片
demo

这里明明只是修改了a数组,但是b也跟着发生了变化。

这里就要说一下基本数据类型和引用数据类型了。
基本数据类型:number,string,boolean,undefine,null
引用数据类型:obj,arr,function等

我们的基本数据类型是存储在栈内存中,let a = 1

image.png

当你b=a复制时,栈内存会新开辟一个内存,例如这样:
2018前端常见基础面试题(精炼版)_第3张图片
image.png

他们各自有自己的值,所以当你修改a=2的时候,并不会对b造成影响,因为他们有自己对应的值。当然,let a=1,b=a;虽然b不受a影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。

引用数据类型,他们的属性名存在栈内存中,但是属性值存储在 堆内存中


2018前端常见基础面试题(精炼版)_第4张图片
image.png

当b=a复制的时候,其实只是复制了他的地址,而不是里面的值


2018前端常见基础面试题(精炼版)_第5张图片
image.png

而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了

如果我们在堆内存中开辟一个新的地址给b,b单独引用地址就算是深拷贝了。


2018前端常见基础面试题(精炼版)_第6张图片
demo

这样修改a是不会影响b的

16.如何进行深拷贝

对象:
①首先判断类型,声明一个新对象保持继承链
②循环对象的key,输出key对应的值
③在循环中js动态添加新对象的属性和值完成深拷贝

var clone = function (obj) { 
    if(obj === null) return null 
    if(typeof obj !== 'object') return obj;
    if(obj.constructor===Date) return new Date(obj); 
    var newObj = new obj.constructor ();  //保持继承链
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {   //不遍历其原型链上的属性
            var val = obj[key];
            newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除与函数名的耦合
        }
    }  
    return newObj;  
}; 
17.添加删除一个js对象的属性和值
添加:
var x = {a:1,b:2}
x.c=3
//返回 {a:1,b:2,c:3}

删除:
delete x.c //返回 {a:1,b:2}
18.vue的生命周期

具体可以看我的这篇文章
https://www.jianshu.com/p/3afd8785b7f5
主要是这几个生命周期钩子
beforeCreated()
created()
beforeMounted()
mounted()
beforeUpdate()
updated()
activated()
deactivated()
beforeDestory()
destoryed()

1.在created钩子中可以对data数据进行操作,这个时候可以进行ajax请求将返回的数据赋给data
2.在mounted钩子对挂载的dom进行操作
3.在使用vue-router时有时需要使用来缓存组件状态,这个时候created钩子就不会被重复调用了,如果我们的子组件需要在每次加载的时候进行某些操作,可以使用activated钩子触发。
4.beforeDestroy,页面组件内容销毁前使用,所有对象数据都会清空。

19.计算属性与监听的区别

当我们需要根据一个值来做一些操作的时候,可以使用计算属性,但是这个操作复杂,还牵扯到异步交互的时候,推荐使用监听属性更加合适。

20.v-if 与 v-show的区别

v-if:返回false时,元素节点都是删除的,返回true,重新渲染节点。
v-show:返回false时,元素节点为 display:none,true时 display:block

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if较好

21.父子组件如何通信

具体可以看我的这篇文章
https://www.jianshu.com/p/00b7c4428574

父组件通信子组件
父组件在引用的子组件标签上添加动态的属性值
子组件中通过props获取父组件中的属性名,能够得到他的属性值

父组件
  
子组件



子组件通信父组件
由子组件向父组件沟通的事件为:emit
我们可以调用内建的 $emit 方法并传入事件的名字,来向父级组件触发一个事件
还是以之前的代码的例子作解释:
子组件p标签绑定点击事件,点击事件中触发

22.vue双向绑定的原理

当一个js对象传给vue实例的时候,vue会遍历他的所有属性值,并且通过Object.defineProperty把他转化成getter/setter,这个方法只有高级浏览器可用,所以ie9以下的浏览器不兼容。
其中的每个组件都有watch对象监听,当里面的值发生改变的时候,会调用setter,然后导致相关联的组件更新,并且更新视图。

23.vue的状态管理 vuex如何使用

具体可以看我的这篇文章
https://www.jianshu.com/p/bc25eebcf15d

为什么要使用vuex
父组件:app
子组件:a,b
app与a,b之间的通讯没问题,但是a,b之间的通讯比较麻烦。
这里我们就可以使用vuex解决

我们可以在目录中新建一个js文件,store.js

import Vue from 'vue'
import App from './App'
import router from './router'
import Vuex from 'vuex'

Vue.use(Vuex);
Vue.config.productionTip = false

/* eslint-disable no-new */


const store = new Vuex.Store({
  state:{
    products:[
      {name: '鼠标', price: 20},
      {name: '键盘', price: 40},
      {name: '耳机', price: 60},
      {name: '显示屏', price: 80}
    ]
  }
})

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: ''
})

核心概念:
state,可以看成所有组件公共的data
可以通过 this.$store.state.products来引用

getter,可以看成是所有组件的 computed 计算属性
获取方法

export default {
    data () {
        return {
            products : this.$store.getters.saleProducts 
        }
    }
}

Mutations,可以理解为 store 中的methods

store.js中的内容
  mutations:{
    minusPrice(state,payload){
      let newPrice=state.products.forEach(product=>{
        product.price-=payload
      })
    }
  }
vue文件中通过commit调用vuex中的方法
this.$store.commit('minusPrice',2);

action,类似于上者,是用来存放方法的,不同的时,他可以加入异步方法。
触发方法

this.$store.dispatch('minusPriceAsync',5)

store中属性作用总结
目前我们已经在store中使用了四种属性了,回顾一下
1.state:用于存储状态,相当于公共data,可以让所有引入的组件获取。
2.getters:相当于计算属性,可以以data中的数据源为基础,返回一个新的data,而且这个data是随着 state中数据的改变而改变的。
3.mutations:相当于methods,在这个属性中可以再添加方法,可以传递 state作为第一个参数,和第二个payload作为自定义参数。其他组件可以通过 commit 来调用这里的方法,来改变视图
4.action:大致和mutations类似,但可以用于异步操作。

modules
当状态很多难以管理的时候,可以通过 modules 进行分类管理,划分为modules (a,b,c)等。

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
25.如何进行响应式布局

大致思路如下
①首先需要添加meta标签


设置设备按照一比一的尺寸进行显示,并且禁止用户缩放页面

②使用媒介查询 @meida 在不同的分辨率下设置css
③单位尽量使用rem,宽度使用百分比

你可能感兴趣的:(2018前端常见基础面试题(精炼版))