(自己整理的,有错误和不足的话,大佬请指出,共同学习)
一:js
1.什么是回调地狱,怎么解决回调地狱问题
经常出现很多将函数作为参数,传入到方法中,然后在方法中调用该方法,常见的就是定时器,各种DOM操作,各种异步请求
异步的JavaScript程序,或者说使用了回调函数的JavaScript程序
一个函数作为参数需要依赖另一个函数执行调用。
A、拆解 function:将各步拆解为单个的 function
B、通过 Promise 链式调用的方式
function buildCatList(list, returnVal) {
return new Promise(function (resolve, reject) {
setTimeout(function (name) {
var catList = list === ‘’ ? name : list + ‘,’ + name
resolve(catList)
}, 200, returnVal)
})
}
buildCatList('', 'Panther').then(function (res) {
return buildCatList(res, 'Janguar')
}).then(function (res) {
return buildCatList(res, 'Lion')
}).then(function (res) {
console.log(res)
})
C、通过ES8的异步函数 async / await
async 表示这是一个 async 函数,await 只能用在这个函数里面
await 表示在这里等待 Promise 返回结果后,再继续执行
await 后面跟着的应该是一个 Promise 对象(当然,其他返回值也没关系,只是会立即执行)
await 等待的虽然是 Promise 对象,但不必写 .then() ,可以直接得到返回值
2.遍历数组
var arr = [1,2,3,4,5,6];
for(let i= 0; i<arr.length; i++){
console.log(下标是${i}的元素的值为:${arr[i]}
);
}
for(let i in arr){
console.log(下标是${i}的元素值为:${arr[i]}
);
}
var i =0;
for(var ele of arr){
console.log(下标是${i++}的元素值为:${ele}
);
}
arr.forEach(function(ele,index){
console.log(小标是${index}的元素的值为:${ele}
);
})
4、数组排序
1、冒泡排序
var arr = [1,9,4,2,6,5,3,2]
var news =‘’
for(var i = 0 ; i < arr.length ; i++){
for(var j =0 ; j < arr.length-i ;j++){
if(arr[j]>arr[j+1]){ //从小到大排序
news=arr[j]
arr[j]=arr[j+1]
arr[j+1]=news
}
}
} console.log(news)
2,快速排序 取中间值 大的放一边,小的放一边
3. sort数字排序
console.log(arr.sort(
function(a,b){
return a-b
}
)); [1, 2, 2, 3, 4, 5, 6, 9]
5、获得数组中最大值,最小值
1、Math.max
因为Math.max参数里面不支持Math.max([params,param2])也就是数组
console.log(Math.max(…arr));
console.log(Math.min(…arr));
2、数组排序后,取收尾下标值,获取
6、数组去重
1.利用for嵌套for,然后splice去重(ES5中最常用)
下面展示一些 内联代码片
。
function unique(arr){
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null,
NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}]
//NaN和{}没有去重,两个null直接消失了
2.利用indexOf去重
// 封装函数
function unique(arr) { //unique 独特的
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) == -1)
newArr.push(arr[i]); // push() 在数组末尾添加元素
}
return newArr;
}
// 代码验证
console.log(unique([1, 2, 2, 3, 3, 3,]));// [1,2,3]
console.log(unique([NaN, NaN, true, true, 'a', 'a', undefined, undefined, {}, {}]));
// [NaN, NaN, true, "a", undefined, {…}, {…}]3.ES6 的 Set 对象
var arr =[1,2,3,3,1,4];
[...new Set(arr)]; //[1,2,3,4]
Array.from(new Set(arr) //[1,2,3,4]
7、字符串去重
var str = 'abcvvna'
console.log([...new Set(str)].join(''))
8、为Array对象添加一个去除重复项的方法
Array.prototype.uniq = function(){
return Array.from(new Set(this))
}
9、正则表达式 \d 匹配一个数字字符串 等价于 [0-9]
function containsNumber(str){
var b=/\d/;
return b.test(str)
}
10.数组的实例方法
-
push 压栈 在当前数组尾部添加数据 var arr = [1,2,3,4,5,6];
arr.push(8) 输出 [1,2,3,4,5,6,8];
-
pop 弹栈 在当前数组尾部删除数据 var arr = [1,2,3,4,5,6];
arr.pop() 输出 [1,2,3,4,5]; 长度改变
-
unshift 在当前数组头部添加数据 var arr = [1,2,3,4,5,6];
arr.unshift(8) 输出 [8,1,2,3,4,5,6];
-
shift 弹栈 在当前数组尾部删除数据 var arr = [1,2,3,4,5,6];
arr.shift() 输出 [1]; 返回的是被删除的元素
-
join 把数组转为字符串
var arr =["a","b","c","d","e","f"]
console.log(arr.join()); 输出 a,b,c,d,e,f
console.log(arr.join("-")); 输出 a-b-c-d-e-f
console.log(arr.join("")); 输出 abcdef
6、 indexOf 查找数组中是否存在指定的值
格式:数组对象.indexOf(key,[fromIndex])
key:代表要查找的值
fromIndex:可选参数,指的是从哪个索引(包含)开始往后查找。 如果省略,代表从0开始。
返回:如果存在返回数组元素的下标,否则返回-1;
注意:返回的是第一个相等的元素的下标。找到之后立即停止。
var arr = [34, 5, 76, 54, 34, 23, 56, 76]; console.log(arr.indexOf(76));//2 console.log(arr.indexOf(76, 3));//7
7、 lastIndexOf() 从最后一个元素开始往前找。但是元素的下标还是从前往后的。
8、slice 切割
作用:从当前数组中取出指定的元素,用这些元素生成一个新的数组。
格式:数组对象.slice(start,end)
start:截取的元素的起始坐标。包含。
end:截取的元素的结束坐标。不包含。
9、splice
splice有如下几个功能:
1.删除-用于删除元素,两个参数,第一个参数(要删除第一项的位置),第二个参数(要删除的项数)
2.插入-向数组指定位置插入任意项元素。三个参数,第一个参数(起始位置),第二个参数(0),第三个参数(插入的项数)
3.替换-向数组指定位置插入任意项元素,同时删除任意数量的项,三个参数。第一个参数(起始位置),第二个参数(删除的项数),第三个参数(插入任意数量的项)
具体看代码实现效果:
var list = [;
list.push(1);list.push(2);list.push(3);
console.log(list);l/[1,2,3]
川删除
list.splice(0,1);I/删除>从下标为0开始,项数为1console.log(list);// [2,3]
list.splice(0,2);l/删除>从下标为0开始,项数为2console.log(list);// []
//替换
list.splice(0,1,4);//替换>从下标为0开始,项数为1的数组元素替换成4console.log(list);l/ [4,2,3]
list.splice(0,2,4);/替换>从下标为0开始,项数为2的数组元素替换成4(即4,2整体替换成4)console.log(list);l/[4,3]
/添加
list.splice(1,0,5);//表示在下标为1处添加一项5console.log(list);l/[1,5,2,3]
10、 reverse 翻转
var arr9 = [1,2,3,4,5,6,7];
arr9.reverse(); console.log(arr9); [7,6,5,4,3,2,1];
11、 sort 数组排序
11.遍历数组方法
map()
let arr = [1,2,3]; arr = arr.map(item => { return item * 2 })
filter() find()
12.判断是数组还是对象 Array.isArray()
var arr10 =[1,2]
console.log(Array.isArray(arr10)); 数组返回 true
var obj={
1:5
}
console.log(Array.isArray(obj)); 对象返回 false
13.数值转换
Number() parseInt() parseFloat()
14转换为字符串 toString()
var a=2; a = a+‘’; console.log(a)
15条件操作符
let max =(num1 > num2) ? num1:num2
在这个例子中,max 将被赋予一个最大值。这个表达式的意思是,如果 num1 大于 num2(条件表
达式为 true),则将 num1 赋给 max。否则,将 num2 赋给 max。
16.
① async 表示应该立即开始下载脚本,但不能阻止其他页面动作,只对外部脚本文件有效
② defer 表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效
③ src:表示包含要执行的代码的外部文件。
17. var let const
var、let和count的区别?
都是一个对象声明
1.var可重复声明,并且有变量提升
console.log(a); //var a=undefined
var a=“111”;
var a=1111;
console.log(a);//1111
2.let不能进行重复声明,没有变量提升
块级作用域,只要是{ }就都是块级作用域
3.count通常用来声明一个常量,例如π
不可重复声明
值不可以修改,如果修改必须是对象,对象是引用数据类型
18.数据类型
Undefined Null Boolean Number String Symbol(符号)是ECMAScript新增地,复杂数据类型 Object(对象) function object array date
19 基本数据类型和复杂数据类型的区别
内存的分配不同
基本数据类型存放在栈内存中
复杂数据类型存放在堆内存中,栈中存储的变量,是指向堆中的引用地址
访问机制不同
基本数据类型是按值访问
复杂数据类型按引用访问,JS不允许直接访问保存在堆内存中的对象,在访问一个对象的时候,首先先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值
复制变量时不同(a=b)
基本数据类型: a=b;是将b中保存的原始值的副本赋值给新变量a,a和b完全独立,互不影响
复杂数据类型: a=b;将b保存的对象内存的引用地址赋值给了新变量a;a和b指向了同一个堆内存地址,其中一个值发生了改变,另一个也会发生改变
20模板字面量
let pageHTML = `
<div>
<a href="#">
<span>Jake</span>
</a>
</div>`;
21、 break 和 continue
break 和 continue 语句为执行循环代码提供了更严格的控制手段。其中,break 语句用于立即退
出循环,强制执行循环后的下一条语句。而 continue 语句也用于立即退出循环,但会再次从循环顶部
开始执行。
22、 let now = new Date();
let now = new Date(“5/23/2019”);
23、 RegExp 正则
g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
i:不区分大小写,表示在查找匹配时忽略 pattern 和字符串的大小写。
m:多行模式,表示查找到一行文本末尾时会继续查找。
y:粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
u:Unicode 模式,启用 Unicode 匹配。
s:dotAll 模式,表示元字符.匹配任何字符(包括\n 或\r)。
// 匹配字符串中的所有"at" let pattern1= /at/g;
24.集合引用类型
创建对象 Object
使用new操作符和Object构造函数 Let person = new Object();
使用 对象字面量 let person ={ name:“wsy”,age = 69 }
创建数组 Array();
构造函数 let colors =new Array(20);
字面量 let names = [];
25.class
类的内部还是一个函数 类面向对象
定义的方法放在原型中的好处 :通过该构造函数生成的实例所拥有的方法都是指向一个函数的索引
,这样可以节省内存。
constructor 为对象做属性初始值的
26. js的防抖和节流
1.什么是节流防抖
防抖 :持续触发事件时,在单位事件只触发最后一次事件,若在单位事件内还触发,则从新计算
节流:持续触发事件时,在单位时间只触发一次
2.什么时候用到节流防抖
防抖(debounce)
1.input的搜索
2.window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件
节流(throttle)
1.鼠标不断点击触发,mousedown(单位时间内只触发一次)
2.监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
*/
3. 防抖
<input type="text" class="username">
const inp = document.querySelector('.username')
function debounce(fn, time) {
let timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
fn.apply(this, arguments);//arguments是传入的参数
console.log(this,'this指向');
console.log(arguments,'arguments是什么');
}, time);
};
}
function sayHi(e) {
console.log(e.target.value);
}
// var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi, 5000)); // 防抖
27. 递归
递归(recursive)函数是“自己调用自己”的函数,主函数调用一个函数,这个函数内部又在此调用这个函数,一直调用自己,调用的条件逐渐逼向边界,最后从边界开始返回,即可以说是“后调用的先返回”。
function DiGui(n){
if(n == 1){
return 1
}else{
return n*DiGui(n-1)
}
}
console.log(DiGui(3));
28. this指向
1.默认绑定规则 独立调用指向window
2.隐式绑定规则 谁调用指向谁
3.显示绑定 call() apply() bind()
5 箭头函数中的this
向外层作用域中,一层层找this,直到找到this的定义,箭头函数中的this是在定义函数的时候绑定的不是在执行函数的时候绑定的
但是在Vue实例中,methods中如果用的是正常函数,那么它的this就指向Vue实例;如果是箭头函数,this就指向window对象。
1.全局环境下的this指向 window
function f1(){
console.log(this)
}
f1() //window
例子2 const foo = {
bar:10,
fn:function(){
console.log(this)
console.log(this.bar)
}
}
foo.fn() // {bar:10,fn:f} 10n
29. JavaScript中什么是基本数据类型什么是引用数据类型?以及各个数据类型是如何存储的?
1 基本数据类型有
Number,String,Boolean,Null,Undefined,Symbol(ES6新增数据类型),bigInt
2 引用数据类型统称为Object类型,细分的话有
Object,Array,Date,Function,RegExp
基本数据类型的数据直接存储在栈中;而引用数据类型的数据存储在堆中,每个对象在堆中有一个引用地址。引用类型在栈中会保存他的引用地址,以便快速查找到堆内存中的对象。
顺便提一句,栈内存是自动分配内存的。而堆内存是动态分配内存的,不会自动释放。所以每次使用完对象的时候都要把它设置为null,从而减少无用内存的消耗
20.在js中为什么 0.2+0.1 > 0.3
因为在js中,浮点数是用64位固定长度来表示的,其中1的位置表示符号位,11位表示指数位,剩下的52位是尾数为,由于只有52位表示尾数位,而0.1转为二进制是一个无限循环数0.0001100110011001100…(1100循环),由于只能存储52位尾数位,所以会出现精度缺失,把它存到内存中再取出来转换成十进制就不是原来的0.1了,就变成了0.100000000000000005551115123126,而为什么02+0.1是因为
21. 那为什么0.2+0.3=0.5呢?
0.2 和0.3分别转换为二进制进行计算:在内存中,它们的尾数位都是等于52位的,而他们相加必定大于52位,而他们相加又恰巧前52位尾数都是0,截取后恰好是0.1000000000000000000000000000000000000000000000000000也就是0.5
22.那既然0.1不是0.1了,为什么在console.log(0.1)的时候还是0.1呢?
在console.log的时候会二进制转换为十进制,十进制再会转为字符串的形式,在转换的过程中发生了取近似值,所以打印出来的是一个近似值的字符串
30.判断数据类型有几种方法
- typeof
缺点:typeof null的值为Object,无法分辨是null还是Object - instanceof
缺点:只能判断对象是否存在于目标对象的原型链上
function Foo() { }
var f1 = new Foo();
var d = new Number(1)
console.log(f1 instanceof Foo);// true
console.log(d instanceof Number); //true
console.log(123 instanceof Number); //false -->不能判断字面量的基本数据类型
- constructor
constructor是每个实例对象都拥有的属性
4.Object.prototype.toString.call()
一种最好的基本类型检测方式 Object.prototype.toString.call() ;它可以区分 null 、 string 、
boolean 、 number 、 undefined 、 array 、 function 、 object 、 date 、 math 数据类型。
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(123)); // "[object Number]"
console.log(Object.prototype.toString.call("abc")); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
function fn() {
console.log("ming");
}
var date = new Date();
var arr = [1, 2, 3];
var reg = /[hbc]at/gi;
console.log(Object.prototype.toString.call(fn));// "[object Function]"
console.log(Object.prototype.toString.call(date));// "[object Date]"
console.log(Object.prototype.toString.call(arr)); // "[object Array]"
31.instanceof原理
instanceof原理实际上就是查找目标对象的原型链
instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false。
下面展示一些 内联代码片
。
function instanceof(left, right) {
const rightVal = right.prototype
const leftVal = left.__proto__
// 若找不到就到一直循环到父类型或祖类型
while(true) {
if (leftVal === null) {
return false
}
if (leftVal === rightVal) {
return true
}
leftVal = leftVal.__proto__ // 获取祖类型的__proto__
}
}
25.为什么typeof null是Object
因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object
000 对象
1 整型
010 双精度类型
100字符串
110布尔类型
32.和=有什么区别
===是严格意义上的相等,会比较两边的数据类型和值大小
数据类型不同返回false
数据类型相同,但值大小不同,返回false
==是非严格意义上的相等,
两边类型相同,比较大小
两边类型不同,根据下方表格,再进一步进行比较。
Null == Undefined ->true
String == Number ->先将String转为Number,在比较大小
Boolean == Number ->现将Boolean转为Number,在进行比较
Object == String,Number,Symbol -> Object 转化为原始类型
33.call,apply,bind
call和 apply 的功能相同,区别在于传参的方式不一样:
fn.call(obj, arg1, arg2, …),调用一个函数, 具有一个指定的this值和分别地提供的参数(参数的列表)。
fn.apply(obj, [argsArray]),调用一个函数,具有一个指定的this值,以及作为一个数组(或类数组对象)提供的参数。
bind 和call/apply 有一个很重要的区别,一个函数被 call/apply 的时候,会直接调用,但是bind 会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
call:
Function.prototype.myCall = function (context) {
// 先判断调用myCall是不是一个函数
// 这里的this就是调用myCall的
if (typeof this !== 'function') {
throw new TypeError("Not a Function")
}
// 不传参数默认为window
context = context || window
// 保存this
context.fn = this
// 保存参数
let args = Array.from(arguments).slice(1) //Array.from 把伪数组对象转为数组
// 调用函数
let result = context.fn(...args)
delete context.fn
return result
}
34.:字面量创建对象和new创建对象有什么区别,new内部都实现了什么,手写一个new
字面量:
字面量创建对象更简单,方便阅读
不需要作用域解析,速度更快
new内部:
1.创建一个新对象
2.使新对象的__proto__指向原函数的prototype
3.改变this指向(指向新的obj)并执行该函数,执行结果保存起来作为result
4.判断执行函数的结果是不是null或Undefined,如果是则返回之前的新对象,如果不是则返回result
手写new
// 手写一个new
function myNew(fn, …args) {
// 创建一个空对象
let obj = {}
// 使空对象的隐式原型指向原函数的显式原型
obj.proto = fn.prototype
// this指向obj
let result = fn.apply(obj, args)
// 返回
return result instanceof Object ? result : obj
}
35.什么是作用域,什么是作用域链?
规定变量和函数的可使用范围称作作用域
每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链。
36.什么是执行栈,什么是执行上下文?
执行栈
1.首先栈特点:先进后出
2.当进入一个执行环境,就会创建出它的执行上下文,然后进行压栈,当程序执行完成时,它的执行3.上下文就会被销毁,进行弹栈。
4.栈底永远是全局环境的执行上下文,栈顶永远是正在执行函数的执行上下文
5.只有浏览器关闭的时候全局执行上下文才会弹出
37、什么是闭包?闭包的作用?闭包的应用?
下面展示一些 内联代码片
。
function AA (){
let num =1
return function BB(){
console.log(num);
}
}
console.log(AA());
let CC = AA()
CC()
//let CC = AA() //这里是调用了一个AA()函数, 但是AA()函数所返回的是一个函数引用
// CC() //所以要赋值给CC再加个括号() 调用一次方法.
什么是闭包
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
function outer() {
var a = ‘变量1’
var inner = function () {
console.info(a)
}
return inner // inner 就是一个闭包函数,因为他能够访问到outer函数的作用域
}
闭包的作用
函数执行,形成私有的执行上下文,使内部私有变量不受外界干扰,起到保护和保存的作用
38、什么是原型?什么是原型链?
##1.什么是原型对象
1.在Javascript中,当系统加载构造函数后,会自动在内存中生成一个对象,这个对象就是原型对象。两者之间在内存中表现为相对独立,不存在谁包含谁的关系。但是两者之间又有一些关联,在构造函数的内部存在一个prototype属性指向原型对象,同时在原型对象的内存也存在一个属性constructor其指向了构造函数。
##2. 构造函数 原型对象 实例对象的关系
##3 prototype和__proto__的区别和联系
prototype是构造函数访问原型对象,__proto__是对象实例访问原型对象。
任意一个函数(包括构造函数)都有一个prototype属性,指向该函数的原型对象
一个构造函数实例化的对象,都有一个__proto__属性 指向构造函数的原型对象
function a() {
//console.log(“I’am a function.”);
}
//b是实例化对象,a是构造函数
var b = new a();
console.log(b.proto == a.prototype);
原型:
原型分为隐式原型和显式原型,每个对象都有一个隐式原型,它指向自己的构造函数的显式原型。
原型链: 多个__proto__组成的集合成为原型链
所有实例的__proto__都指向他们构造函数的prototype
所有的prototype都是对象,自然它的__proto__指向的是Object()的prototype
所有的构造函数的隐式原型指向的都是Function()的显示原型
Object的隐式原型是null
39、说一说 JS 中的常用的继承方式有哪些?以及各个继承方式的优缺点。
原型继承、构造函数继承、组合继承、寄生组合继承、ES6的extend
1.原型链继承
优点:父类方法可以复用
缺点:父类所有的引用类型数据(对象,数组)会被子类共享,
改变一个子类的数据,其他数据会受影响,一起变化
缺点2:子类实例不能给父类构造函数传参
function Person(){
this.name = "小明"
this.eats = ["苹果"]
this.getName = () =>{
console.log(this.name);
}
}
Person.prototype.get = () =>{
console.log("Person.prototype上的方法");
}
function Student(){}
Student.prototype = new Person()
const stu1 = new Student()
stu1.name = "小花"
stu1.eats.push("香蕉")
console.log(stu1.name);
console.log(stu1.eats);
console.log("+++++++++++++++++++++++++++++++++");
const stu2 = new Student()
console.log(stu2.name);
console.log(stu2.eats);
2.构造函数的继承
优点:父类所有的引用类型数据(对象,数组)会被子类共享,
缺点:子类不能访问父类原型属性上的方法和参数
function Person() {
this.name = "小明"
this.eats = ["苹果"]
this.getName = () => {
console.log(this.name);
}
}
Person.prototype.get = () => {
console.log("Person.prototype上的方法");
}
function Student() {
Person.call(this)
}
const stu1 = new Student()
3.组合继承
优点:1.父类可以服用
2.父类所有的引用类型数据(对象,数组)不会被子类共享,
缺点:调用两次父类的构造函数 会用两份一样的属性和方法 会影响性能
function Person() {
this.name = "小明"
this.eats = ["苹果"]
this.getName = () => {
console.log(this.name);
}
}
Person.prototype.get = () => {
console.log("Person.prototype上的方法");
}
function Student() {
Person.call(this)
}
Student.prototype = new Person()
const stu1 = new Student()
4.寄生组合继承
优点:1.父类可以服用
2.父类所有的引用类型数据(对象,数组)不会被子类共享,
缺点:调用两次父类的构造函数 会用两份一样的属性和方法 会影响性能
function Person() {
this.name = "小明"
this.eats = ["苹果"]
this.getName = () => {
console.log(this.name);
}
}
Person.prototype.get = () => {
console.log("Person.prototype上的方法");
}
function Student() {
Person.call(this)
}
const Fn =function(){
Fn.prototype = Person.prototype
}
Student.prototype = new Fn()
const stu1 = new Student()
40、什么是内存泄漏
内存泄露是指不再用的内存没有被及时释放出来,导致该段内存无法被使用就是内存泄漏
41、为什么会导致的内存泄漏
内存泄漏指我们无法在通过js访问某个对象,而垃圾回收机制却认为该对象还在被引用,因此垃圾回收机制不会释放该对象,导致该块内存永远无法释放,积少成多,系统会越来越卡以至于崩溃
42、垃圾回收机制都有哪些策略
标记清除法
垃圾回收机制获取根并标记他们,然后访问并标记所有来自它们的引用,然后在访问这些对象并标记它们的引用…如此递进结束后若发现有没有标记的(不可达的)进行删除,进入执行环境的不能进行删除
引用计数法
当声明一个变量并给该变量赋值一个引用类型的值时候,该值的计数+1,当该值赋值给另一个变量的时候,该计数+1,当该值被其他值取代的时候,该计数-1,当计数变为0的时候,说明无法访问该值了,垃圾回收机制清除该对象
43、深拷贝和浅拷贝
1.JSON转换方案
缺点:数据类型为function或者数值为undefined情况下无法复制
2. Object.assign({},obj111)
缺点:只能深拷贝一级属性,二级及以上属性就是浅拷贝
3. 扩展运算符 {...obj1}
缺点:只能深拷贝一级属性,二级及以上属性就是浅拷贝
4. slice() / concat()
缺点:只能深拷贝一级属性,二级及以上属性就是浅拷贝
5. 递归
深拷贝还是得递归
// ----------------------------------------------浅拷贝
// 只是把对象的属性和属性值拷贝到另一个对象中
var obj1 = {
a: {
a1: { a2: 1 },
a10: { a11: 123, a111: { a1111: 123123 } }
},
b: 123,
c: "123"
}
// 方式1
function shallowClone1(o) {
let obj = {}
for (let i in o) {
obj[i] = o[i]
}
return obj
}
// 方式2
var shallowObj2 = { ...obj1 }
// 方式3
var shallowObj3 = Object.assign({}, obj1)
let shallowObj = shallowClone1(obj1);
shallowObj.a.a1 = 999
shallowObj.b = true
console.log(obj1); //第一层的没有被改变,一层以下就被改变了
// ----------------------------------------------深拷贝
// 简易版
function deepClone(o) {
let obj = {}
for (var i in o) {
// if(o.hasOwnProperty(i)){
if (typeof o[i] === "object") {
obj[i] = deepClone(o[i])
} else {
obj[i] = o[i]
}
// }
}
return obj
}
var myObj = {
a: {
a1: { a2: 1 },
a10: { a11: 123, a111: { a1111: 123123 } }
},
b: 123,
c: "123"
}
var deepObj1 = deepClone(myObj)
deepObj1.a.a1 = 999
deepObj1.b = false
console.log(myObj);
44、宏任务和微任务
js单线程 微任务(Promise)先执行
执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。
微process.nextTick (node.js中进程相关的对象), Promise, Object.observer, MutationObserver。
宏script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering.
45、Promise
promise是js中异步编程(axios)的新的解决方案(旧的就是单纯使用回调函数)解决回调地狱
Promise 是一个构造函数 用来封装一个异步操作,获取其成功和失败的结果
let promise = new Promise(function(resolve,reject){
const time = Date.now()
if(time % 2 === 1){
resolve(`成功 基数是:${time}`)
}else{
reject(`失败 偶数是:${time}`)
}
})
.then(
function(value){
console.log(value);
},
function(reson){
console.log(reson);
}
)
问题一:Promise如何改变状态
1.resolve 2.reject 3. 在执行器中 抛出异常那个会变成rejected
抛出异常是指在执行器函数中 并不是在异步函数中
问题二:promise.then()返回的新的promise的执行结果状态由什么决定
(1)简单表达:有then()指向的回调函数执行的结果决定
(2)详细表达:
① 如果抛出异常,新的promise变为rejected,reson为抛出的异常
② 如果返回的是非promise的任意值,新的promise变为resolved,value为返回的值
③ 如果返回的是一个新的promise 此promise的结果就会变成新的promise的结果
问题三:怎么中断promise链
在回调函数中返回一个pedding状态的promise对象
return new Promise(()=>{})
问题四:promise常用的api
.then .catch
.all 参数是promise实例 // 零秒之后输出 [1,2,3] p2,p3的输出等待p1结束后输出
// 都是成功状态 输出全部的成功状态,
// 若有失败状态 输出第一个失败状态
let p1 = new Promise(function(resolve,reject){
setTimeout(()=>{
resolve(1)
},2000)
})
let p2 = Promise.resolve(2)
let p3 = Promise.resolve(3)
let p4 = Promise.all([p1,p2,p3])
p4.then(
function(values){
console.log(values);
},
function(reson){
console.log(reson);
}
)
Promise.race
说明:返回一个新的promise,第一个完成懂得promise的结果状态是最终的结果状态
// promise 构造函数上的方法 .reject 获取失败状态的promise
/ promise 构造函数上的方法 .resolve获取失败状态的promise
二、Webpack
1.webpack是什么?
一种前端资源构建工具,一个静态模块打包器(nodule bundle)
前端所有资源文件(js/json/css/img…)都会作为模块处理
它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)
2.Webpack 五个核心概念分别是什么?
Entry
入口(Entry)指示 Webpack 以哪个文件为入口起点开始打包,分析内部构件依赖图
Output
输出(Output)指示 Webpack 打包后的资源 bundles 输出到哪里去,以及如何命名
Loader
Loader 能让 Webpack 处理非 JavaScript/json 文件(Webpack 自身只能处理 JavaScript/json )
Plugins
插件(Plugins)可以用于执行范围更广的任务,包括从打包优化和压缩到重新定义环境中的变量
Mode
模式(Mode)指示 Webpack 使用相应模式的配置,只有development(开发环境)和production(生产环境)两种模式
3.有哪些常见的Loader?它们是解决什么问题的?
1.css-loader:将 css 文件变成 CommonJS 模块加载 js 中,里面内容是样式字符串
2.style-loader:创建 style 标签,将 js 中的样式资源插入进行,添加到 head 中生效
3.url-loader:在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
4.file-loader:打包其他资源(除了css/js/html 资源)
5.html-loader:处理 html 文件中的 img
6.babel-loader:把 ES6 转换成 ES5
7.eslint-loader:通过 ESLint 检查 JavaScript 代码
4.有哪些常见的Plugin?它们是解决什么问题的?
1.html-webpack-plugin:可以复制一个有结构的html文件,并自动引入打包输出的所有资源(JS/CSS)
2.clean-webpack-plugin:重新打包自动清空 dist 目录
3.mini-css-extract-plugin:提取 js 中的 css 成单独文件
4.optimize-css-assets-webpack-plugin:压缩css
5.uglifyjs-webpack-plugin:压缩js
6.commons-chunk-plugin:提取公共代码
5.webpack的构建流程是什么?
1.初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
2.开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
3.确定入口:根据配置中的 entry 找出所有的入口文件;
4.编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
5.完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
6.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
6.webpack的热更新是什么?
热更新又称热替换(Hot Module Replacement),缩写为HMR,基于devServer,生产环境不需要devServer,所以生产环境不能用HMR功能
作用:优化打包构建速度,一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度
1.样式文件:可以使用HMR功能,因为style-loader内部实现了
2.JS文件:默认没有HMR功能,需要修改js代码,添加支持HMR功能。入口文件做不了HMR功能,只能处理非入口js文件
3.HTML文件:默认没有HMR功能,同时会导致 html 文件不能热更新(即修改没有任何反应)
解决方案:
修改entry入口,将html文件引入
entry:[‘./src/js/index.js’,‘./src/index.html’]
1
不用做HMR功能,因为只有一个html文件
7.如何利用webpack来优化前端性能?
开发环境下:
开启HMR功能,优化打包构建速度
配置 devtool: ‘source-map’,优化代码运行的性能
生产环境下:
1.oneOf 优化:默认情况下,假设设置了7、8个loader,每一个文件都得通过这7、8个loader处理(过一遍),浪费性能,使用 oneOf 找到了就能直接用,提升性能
2.开启 babel 缓存:当一个 js 文件发生变化时,其它 js 资源不用变
3.code split 分割:将js文件打包分割成多个bundle,避免体积过大
4.懒加载和预加载
5.PWA 网站离线访问
6.多进程打包:开启多进程打包,主要处理js文件(babel-loader干的活久),进程启动大概为600ms,只有工作消耗时间比较长,才需要多进程打包,提升打包速度
8.Webpack的基本功能有哪些?
代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
文件优化:压缩 JavaScript、CSS、html 代码,压缩合并图片等
代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
9.前端为什么要进行打包和构建?
代码层面:
体积更小(Tree-shaking、压缩、合并),加载更快
编译高级语言和语法(TS、ES6、模块化、scss)、兼容性和错误检查(polyfill,postcss,eslint)
研发流程层面:
统一、高效的开发环境、统一的构建流程和产出标准、集成公司构建规范(提测、上线)
三、Vue
1. vue的优点
轻量级框架 双向数据绑定 组件化 视图数据、结构分离, 指令,插件化
2. vue组件之间传值、传数据
3. v-show和 v-if相同点和不同点
v-show 利用css属性display来决定显示还是隐藏
v-if 本质是操作dom元素来进行切换,有一个销毁和重建的过程
4. 如何让css只在当前组件起作用
scoped
5. 如何获取dom 原生和vue中
vue中:使用ref ref=“name”
this.$refs.name.style.backgroundColor=“red”
原生的:document.getElementById(“id”)
6. v-model的使用
Message is: {{ message }}
v-model用于表单的双向绑定,其实他就是一个语法糖,两部分操作 v-bind绑定一个value属性 v-on指令给当前元素绑定input事件 ## 7. computed 计算属性和watch 监听器的区别 computed 1. 支持缓存,只有依赖数据发生改变,才会重新进行计算 2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化 3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值 4. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed 5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法 watch 1. 不支持缓存,数据变,直接会触发相应的操作; 2.watch支持异步; 3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值; 4. 当一个属性发生变化时,需要执行对应的操作;一对多; 5. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数, immediate:组件加载立即触发回调函数执行, deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。 监听的对象也可以写成字符串的形式
<template>
<div>
<input type="text" v-model="user_info.name">
</div>
</template>
<script>
export default{
data(){
return:{
user_info:{
name:'blue'
}
}
},
watch:{
""user_info.name":function(){
consoe.log("name变了")
}
}
}
</script>
8. $nextTick的使用
Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM,
methods:{
testClick:function(){
let that=this;
that.testMsg="修改后的值";
that.$nextTick(function(){
console.log(that.$refs.aa.innerText); //输出:修改后的值
});
}
什么时候需要用的Vue.nextTick()??
(1) created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中
(2) 改变DOM元素的数据后基于新的dom做点什么,对新DOM一系列的js操作都需要放进Vue.nextTick()的回调函数中;
9. vue组件中的data为什么必须是一个函数
因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。
相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。
10. vue中的数据双向绑定是什么,以及如何实现的
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法。
var obj = {};
Object.defineProperty(obj,'hello',{
set:function(newVal){
document.getElementById('a').value = newVal;
document.getElementById('b').innerHTML = newVal;
}
});
11.v-if和v-for的优先级
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。所以,不推荐v-if和v-for同时使用
12. assets和static的区别
相同点:assets和static两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下,这是相同点
不相同点:assets中存放的静态资源文件在项目打包时,也就是运行npm run build时会将assets中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在static文件中跟着index.html一同上传至服务器。static中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是static中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于assets中打包后的文件提交较大点。在服务器中就会占据更大的空间。
建议:将项目中template需要的样式文件js文件等都可以放置在assets中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css等文件可以放置在static中,因为这些引入的第三方文件已经经过处理,我们不再需要处理,直接上传。
13. vue常用的修饰符
.prevent 阻止默认事件 a链接的跳转
.stop 防止事件冒泡
.self 只会触发自己范围内的事件,不包含子元素;
Div嵌套一个button,两个都有点击事件,谁的事件有.self 就执行谁的
.once 只出发一次
14. vue的两个核心点
数据驱动:ViewModel,保证数据和视图的一致性
当创建 Vue 实例时,vue 会遍历 data 选项的属性,利用 Object.defineProperty 为属性添加 getter 和 setter 对数据的读取进行劫持(getter 用来依赖收集,setter 用来派发更新),并且在内部追踪依赖,在属性被访问和修改时通知变化。
每个组件实例会有相应的 watcher 实例,会在组件渲染的过程中记录依赖的所有数据属性(进行依赖收集,还有 computed watcher,user watcher 实例),之后依赖项被改动时,setter 方法会通知依赖与此 data 的 watcher 实例重新计算(派发更新),
组件系统:应用类UI可以看作全部是由组件树构成
15. 什么是MVVM
MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。
16. vue组件封装的过程
1. 建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。
2. 准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
3. 准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
4. 封装完毕了,直接调用即可
17. vue初始化页面闪动问题
使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。
首先:在css里加上[v-cloak] {
display: none;
}。
如果没有彻底解决问题,则在根元素加上style=“display: none;” :style=“{display: ‘block’}”
html
{{context}}
css [v-cloak]{
display: none;
}
18. vue修改打包后静态资源路径的修改
将 config/index.js 里的 assetsPublicPath 的值改为 ‘./’ 。
build: {
assetsPublicPath: ‘./’,
}
19. vue生命周期
beforecreate
Created:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据
beforemounte
Mounted: 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行
beforeupdate updated
beforedestroy destroyed
##20.vue获取数据在哪个周期函数
答:一般 created/beforeMount/mounted 皆可.
比如如果你要操作 DOM , 那肯定 mounted 时候才能操作.
21. 第一次页面加载会触发哪几个钩子?
beforeCreate, created, beforeMount, mounted
##22.在哪个阶段有
e
l
,
在
哪
个
阶
段
有
el,在哪个阶段有
el,在哪个阶段有data
在$el就是组件的根节点
d
a
t
a
就
是
数
据
在
c
r
e
a
t
e
中
有
d
a
t
a
,
在
m
o
u
n
t
e
d
中
有
data就是数据 在create中有data,在mounted中有
data就是数据在create中有data,在mounted中有el
如果加入了keep-alive会多两个生命周期 (缓存组件的),第一次进入组件会执行哪些生命周期,第二次或者第n次进入组件会执行哪些生命周期
Activated:组件激活时调用,deactivated:组件销毁之前调用,这一步,实例仍完全可用
22. vuex有哪几种属性?
有五种,分别是 State、 Getter、Mutation 、Action、 Module
state => 基本数据(数据源存放地)
getters => 从基本数据派生出来的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步。
modules => 模块化Vuex
23 Vuex是单项数据流还是双向数据流
单项数据流
24 Vuex中的mutations和actions区别
mutations:都是同步事务
actions:提交mutations的 不是直接变更状态 可以包含任意异步
25 Vuex如何做到持久化
Vuex本身不是持久化存储 使用localStorage
export default{
state:{
pathList:'这是地址管理',
num:localStorage.getItem('num') || 1
},
getters:{},
mutations:{
add(state){
state.num++
localStorage.setItem('num',state.num)
}
},
actions:{}
}
2.使用插件 vuex-parsist
23. 什么是虚拟dom 及其优缺点
虚拟 DOM,其实就是用对象的方式取代真实的 DOM 操作,把真实的 DOM 操作放在内存当中,在内存中的对象里做模拟操作。当页面打开时浏览器会解析 HTML 元素,构建一颗 DOM 树,将状态全部保存起来,在内存当中模拟我们真实的 DOM 操作,操作完后又会生成一颗 dom 树,两颗 DOM 树进行比较,根据 diff 算法比较两颗 DOM 树不同的地方,只渲染一次不同的地方。
##25.什么是插槽
占位符:父组件可以在这个占位符中填充任何模板代码,
匿名插槽,具名插槽,作用域插槽,element-ui中常见, 封装一些公共组件中常用到插槽
Router
动态路由,嵌套路由,命名路由,
编程式导航;this.
r
o
u
t
e
r
.
p
u
s
h
(
‘
/
’
)
T
h
i
s
.
router.push(‘/’) This.
router.push(‘/’)This.router.push({path:’/’})
传参 this.KaTeX parse error: Expected '}', got 'EOF' at end of input: …名路由传 用this.route.params接受
name:‘home’,
Params:{userId:123}
})
如果 用path跳转和params传参的话,用this.
r
o
u
t
e
接
受
是
接
不
到
的
传
参
t
h
i
s
.
route接受是接不到的 传参 this.
route接受是接不到的传参this.router.push({ //用命名路由传 用this.KaTeX parse error: Expected 'EOF', got '}' at position 56: …s:{userId:123} }̲) 传参 this.router.push({ //用命名路由传 用this.KaTeX parse error: Expected 'EOF', got '}' at position 55: …s:{userId:123} }̲) Query传参参数地址栏拼…router.push({ 用this.$route.query接受
Name:’About’,
Query:{id:1234}
})
通过props解耦
Routers:[
{path:’/user/:id’,computed:User,props:true} //第一种
{path:’/user2’,computed:User,props:{id:1111}} //第二种
{path:’/user/:id’,computed:User,props:function(toute){
Return:{id:123-
}
}}
]
//接收组件
路由重定向,路由模式,路由守卫,路由元信息,
路由组件传参:
<router-link :to=”{name:’user’,params:{userId:123}}”></router-link>
<router-link :to=”{name:’user’,query:{userId:123}}”></router-link>
##26.Vue中query与params两种传参的区别
query语法:
this.$router.push({path:“地址”,query:{id:“123”}}); 这是传递参数
this.$route.query.id; 这是接受参数
params语法:
this.$router.push({name:“地址”,params:{id:“123”}}); 这是传递参数
this.$route.params.id; 这是接受参数
区别:
1.首先就是写法得不同,query 得写法是 用 path 来编写传参地址,而 params 得写法是用 name 来编写传参地址,你可以看一下编写路由时候得相关属性,你也可以输出一下 路由对象信息 看一下
2.接收方法不同, 一个用 query 来接收, 一个用 params 接收 ,总结就是谁发得 谁去接收
3.query 在刷新页面得时候参数不会消失,而 params 刷新页面得时候会参数消失,可以考虑本地存储解决
4.query 传得参数都是显示在url 地址栏当中,而 params 传参不会显示在地址栏
27. $route 和 $router 的区别
r
o
u
t
e
r
是
V
u
e
R
o
u
t
e
r
的
实
例
,
在
s
c
r
i
p
t
标
签
中
想
要
导
航
到
不
同
的
U
R
L
,
使
用
router是VueRouter的实例,在script标签中想要导航到不同的URL,使用
router是VueRouter的实例,在script标签中想要导航到不同的URL,使用router.push方法。返回上一个历史history用$router.to(-1)
$route为当前router跳转对象。里面可以获取当前路由的name,path,query,parmas等。
##28 .router 和routes
router是实例,routes路由配置项 是路由的结合
##29. router-link和router-view
利用router-link的to属性进行页面跳转
Router-view是视图渲染时候的容器,组件就是渲染在router-vview组件的位置
##30.:vue-router 有哪几种导航钩子
全局守卫
全局前置守卫:router.beforeEach eg:比如没有登录
全局解析守卫:router.beforeResolve
全局后置钩子:router.afterEach
路由独享守卫
你可以直接在路由配置上定义 beforeEnter
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
组件内守卫
beforeRouteEnter:在渲染该组件的对应路由被验证前调用
beforeRouteUpdate: 在当前路由改变,但是该组件被复用时调用
beforeRouteLeave:在导航离开渲染该组件的对应路由时调用
##31.路由懒加载
Component:()=>import(‘…/views/About.vue’)
路由跳转的时候才需要加载,一进入页面不会加载
使用原因:在单页应用中,如果没有应用懒加载,运用 webpack 打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,延时过长,不利于用户体验,而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时
原理:vue 异步组件技术:异步加载,vue-router 配置路由 , 使用 vue 的异步组件技术 , 实现按需加载。
32.vue-router的两种模式
答:hash模式:即地址栏 URL 中的 # 符号;
history模式:window.history对象打印出来可以看到里边提供的方法和记录长度。利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)。
##33.你都做过哪些 Vue 的性能优化
这里只列举针对 Vue 的性能优化 整个项目的性能优化是一个大工程 可以另写一篇性能优化的文章 哈哈
对象层级不要过深,否则性能就会差
不需要响应式的数据不要放到 data 中(可以用 Object.freeze() 冻结数据)
v-if 和 v-show 区分使用场景
computed 和 watch 区分使用场景
v-for 遍历必须加 key,key 最好是 id 值,且避免同时使用 v-if
大数据列表和表格性能优化-虚拟列表/虚拟表格
防止内部泄漏,组件销毁后把全局变量和事件销毁
图片懒加载
路由懒加载
第三方插件的按需引入
适当采用 keep-alive 缓存组件
防抖、节流运用
##34.vue-loader作用:
解析和转换.vue文件。提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理,使其js可以写es6、style样式可以scss或less、
##35.为什么使用key?
需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点。
作用主要是为了高效的更新虚拟DOM。
##36.单页面应用和多页面应用区别及优缺点
单页面应用(SPA),通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。
多页面(MPA),就是指一个应用中有多个页面,页面跳转时是整页刷新
单页面的优点:
用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小;前后端分离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。
单页面缺点:
不利于seo;导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多。
四、Css
1.css引入方式
(1)内联样式(行内样式)
CSS
(2)内部样式 (3)外部样式(推荐)
2.@import和link的区别?
- @import是CSS提供加载样式的一种方式,只能用于加载CSS。link标签除了可以加载CSS外,还可以做很多其它的事情,比如定义rel连接属性等。
- 加载顺序的差别。当一个页面被加载的时候,link引用的CSS会同时被加载,@import引用的CSS会等到页面全部被下载完再被加载。所以有时候浏览@import加载CSS的页面时开始会没有样式(就是闪烁),网速慢的时候会比较明显。
- 兼容性的差别。@import在IE5以上才能识别,而link标签无此问题。
- 使用dom控制样式时的差别。当使用javascript控制dom去改变样式的时候,只能使用link标签,因为dom操作元素的样式时,用@import方式的样式也许还未加载完成。
5.使用@import方式会增加HTTP请求,会影响加载速度,所以谨慎使用该方法。
3. 选择器
1 全局选择器 *{}
2 元素选择器 p a div
3 类选择器 class .
4 id选择器 id #
选择器优先级
元素选择器的权重为0001,class选择器的权重为0010,id选择器的权重为0100,内联样式的权重为1000
行内样式>ID选择器>类选择器>元素选择器
5 后代选择器 div p
6 子代选择器 div>p
7 相邻兄弟选择器 选择紧跟E元素后的F元素,用加好表示,选择相邻的第一个兄弟元素。
h1元素
第一个元素
第二个元素
h1+p{color:red;} 伪类选择器 (1):link “链接”:超链接点击之前(只适用于a) (2):visited “访问过的”:链接被访问过之后(只适用于a) (3):hover “悬停”:鼠标放到标签上的时候(适用于所有标签) (4):active “激活”: 鼠标点击标签,但是不松手时。(适用于所有标签) :first-child 选择器 :first-child 选择器匹配其父元素中的第一个子元素。 li:first-child{ background:yellow; } :last-child 选择器 :last-child选择器用来匹配父元素中最后一个子元素。 p:last-child{ background:#ff0000; } :nth-child ()选择器 :nth-child(n) 选择器匹配父元素中的第 n 个子元素,元素类型没有限制。 n 可以是一个数字,一个关键字,或者一个公式。 伪对象选择器 ul::before{content:"这是ul的伪元素"; color: blue;} ul::after{content:"这是之后的伪元素";} 属性选择器4.盒模型
标准和模型和怪异和模型的区别,及相互转化
标准盒的实际宽度 就是width 怪异盒的实际 是width+border+padding
box-sizing: content-box; 转为标准盒模型
box-sizing: border-box; 转为怪异盒模型
5.弹性盒模型
弹性容器通过设置 display 属性的值为 flex 将其定义为弹性容器。
5.1 父元素上有什么属性
(1)flex-direction属性,
flex-direction 属性指定了弹性子元素在父容器中的位置。属性值如下:
row:横向从左到右排列(左对齐),默认的排列方式。
row-reverse:反转横向排列(右对齐,从后往前排,最后一项排在最前面。
column:纵向排列。
column-reverse:反转纵向排列,从后往前排,最后一项排在最上面。
(2)justify-content 属性
内容对齐(justify-content)属性应用在弹性容器上,把弹性项沿着弹性容器的主轴线(main axis)对齐,属性值如下:
①flex-start:
弹性项目向行头紧挨着填充。这个是默认值。第一个弹性项的main-start外边距边线被放置在该行的main-start边线,而后续弹性项依次平齐摆放。
②flex-end:
弹性项目向行尾紧挨着填充。第一个弹性项的main-end外边距边线被放置在该行的main-end边线,而后续弹性项依次平齐摆放。
④space-between:
弹性项目平均分布在该行上。如果剩余空间为负或者只有一个弹性项,则该值等同于flex-start。否则,第1个弹性项的外边距和行的main-start边线对齐,而最后1个弹性项的外边距和行的main-end边线对齐,然后剩余的弹性项分布在该行上,相邻项目的间隔相等。
⑤space-around:
弹性项目平均分布在该行上,两边留有一半的间隔空间。如果剩余空间为负或者只有一个弹性项,则该值等同于center。否则,弹性项目沿该行分布,且彼此间隔相
(3) align-items 属性
align-items 设置或检索弹性盒子元素在侧轴(纵轴)方向上的对齐方式。
①flex-start:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴起始边界。
②flex-end:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴结束边界。
③center:弹性盒子元素在该行的侧轴(纵轴)上居中放置。(如果该行的尺寸小于弹性盒子元素的尺寸,则会向两个方向溢出相同的长度)。
5.2 子元素上的属性
flex-grow flex-grow 根据弹性盒子元素所设置的扩展因子作为比率来分配剩余空间。
默认为0,即如果存在剩余空间,也不放大。
如果只有一个子元素设置,那么按扩展因子转化的百分比对其分配剩余空间。0.1即10%,1即100%,超出按100%
6.margin需要注意的问题
(1)外边距合并问题
垂直方向上外边距相撞时,取较大值
注意:浮动元素的外边距不合并
(2)margin-top问题
当给子元素设置margin-top时,父元素会跟着子元素一起下来:解决方法:
①父元素设置overflow:hidden;
②父元素或者子元素设置float
③父元素设置border:1px solid transparent;
④父元素设置padding-top:1px;
7.怎么清除浮动
(1)设置父布局的高度
(2)受影响的元素加clear属性
clear:left | right | both;
(3)overflow清除浮动
这种情况下,父布局不能设置高度。
父级标签的样式里面加: overflow:hidden;
(4)空div法
在最后一个浮动的盒子的后面,新添加一个标签。然后设置clear清除浮动。
这种情况下,父布局不能设置高度。
8.display有什么属性值 及其作用
none 此元素不会被显示。
block 此元素将显示为块级元素,此元素前后会带有换行符。
inline inline 默认。此元素会被显示为内联元素,元素前后没有换行符。
inline-block 行内块元素
Flex 弹性盒模型
9. css3有哪些新特性 举例说明
圆角 border-radius: 15px 50px 30px 5px;
盒阴影 box-shadow: 10px 10px green;
h-shadow 水平阴影的位置 必须 v-shadow 垂直阴影的位置 必须
字阴影 text-shadow: h-shadow v-shadow blur color;
背景颜色渐变 background: linear-gradient(direction, color-stop1, color-stop2, …);
10,响应式设计有哪些
媒体查询media
多列 column-count
11.元素水平垂直居中
1、一个已知高宽的div在不同分辨率屏幕垂直,水平居中 ,css实现
div{
position:absolute;
width:200px;
height:200px;
top:50%;
left:50%;
margin-left:-100px;
margin-top:-100px;
}
12.画一个三角形
.triangle{
width: 0;
height: 0;
border:100px solid transparent;
border-bottom:100px solid blue;
}
13 常见的兼容性问题?
不同浏览器的标签默认的margin和padding不一样。*{margin:0;padding:0;}
五、HTML
1.from表单中post和get提交数据的区别:
1、数据提交方式,get把提交的数据url可以看到,post看不到
2、get一般用于提交少量数据,post用来提交大量数据