- H5新特性
1.新增了语义化标签 header footer
2.新增了视频video 音频sudio
3.新增了canvas和svg绘图
4.新增了拖拽API(drapable)
5.新增了地理位置
6.新增了多线程技术web worker
7.新增了即时通讯web socket
- Css3新特性
- 增加了transiton渐变,Animation动画,选择器,阴影,弹性布局,媒体查询
- W3c标准
结构,行为,表现
- 文档类型需要声明(doctype)
- 编码格式需要声明(meta charset = ‘utf-8’)
- javascript需要定义
- css需要定义
- 标签名称和标签内属性名字小写等
- 浏览器兼容
不同浏览器中标签的内外间距不同 图片有默认间距
- 怎么解决兼容
Ie浏览器可以使用css Hack的方式解决,具体做法是根据不同Ie版本分别在前面使用* - + 等开发效率低
谷歌实在属性前面加上-webkit 火狐是 -moz
可以使用webpack当中的postcss加载器来解决
- 伪类,为元素,块级元素,行内元素,行内块元素
块级元素:div p h1-h6 ul ol li dl dt dd tr
行内块元素:img input
行内元素:span a font strong em i
- 伪类:用于当已有元素处于某个状态时。为其添加样式,这个状态时根据用户行为而动态变化的 hover active link focus first-child
- 伪元素:用于创建一些不在文档树中的元素,并为其添加样式 (选择某个给其添加样式) before after
- 如何使用媒体查询/媒体查询原理
根据屏幕尺寸的不同,动态设置html字体大小,html字体大小即为rem大小,通过给其他标签设置rem来实现不同尺寸屏幕大小
em是相对于父级标签的字体大小来定义的
rem是相对于html标签的字体大小来定义的
- 常用的适配手段
- 媒体查询
- 使用各种UI框架
- 弹性布局
flex时Fiexible Box的缩写,意为弹性布局,用来为盒模型提供最大的灵活性传统的 布局方式,基于盒模型,依赖displat+position+float 。他对于那些特殊的布局非常 不方便 比如垂直居中
Flex布局可以快速且方便的对子元素进行水平和垂直方向的排列,且可以设置元素的起始位置和排列方式,相比于传统的布局,既不需要定位也不需要请浮动
- BFC
Block formatting context块级格式化上下文,它是独立的渲染区域,只有Block-level box参与,规定了内部的Block-level box如何布局,并且与这个区域外部毫无关系
作用:避免margin重叠,清楚浮动
对BFC规范(块级格式化上下文)的理解
BFC 块级格式化上下文 一块独立的区域,有自己的规则,bfc中的元素与外界的元素互不影响
BFC是一块用来独立的布局环境,保护其中内部元素不受外部影响,也不影响外部。
怎么触发BFC
1. float的值left或right
2. overflow的值不为visible(默认)
3. display的值为inline-block、table-cell、table-caption
4. position的值为absolute(绝对定位)或fixed固定定位
规则:
1、BFC的区域不会与float box重叠。
2、BFC是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。
3、计算BFC的高度时,浮动元素也会参与计算。
4、内部的Box会在垂直方向上一个接一个放置。
5、Box垂直方向的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠。
BEC的应用
1、可以用来自适应布局
利用BFC的这个原理可以实现两栏布局,左边定宽,右边自适应。不会相互影响,哪怕高度不相等。
给左边盒子加浮动,右边盒子加overflow:hidden;变成BFC,就可以消除外部左边盒子因浮动对他的影响
2、可以清除浮动
一个父元素中的子元素,设置浮动时,父元素没有设置高度,这时子元素脱离文档流,父元素感知不到子元素的高度,造成父元素的塌陷。 这时候给父元素添加overflow:hidden / auto,变成BFC就可以解决这种问题。
什么是回流什么是重绘以及区别?
回流:
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree.
重绘:
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘.
区别:
回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流,当页面布局和几何属性改变时就需要回流
- 清楚浮动的方式有哪些?
- 浮动元素后新增标签,并且设置属性clear:both
- 浮动元素的父标签设置属性 overflow:hidden
- 设置伪类选择器 XX:after{clear:both}
从浏览器地址栏输入url到显示页面的步骤
· 浏览器根据请求的 URL 交给 DNS 进行域名解析,找到真实 IP 地址,向服务器发起请求;
· 服务器交给后台处理完成后返回数据,浏览器接收文件(HTML、CSS、JS、images等);
· 浏览器对加载到的资源(HTML、CSS、JS、images等)进行语法解析,建立相应的内部数据结构(如HTML的DOM);
· 载入解析到的资源文件,渲染页面,完成。
页面导入时,使用link和@import有什么区别
页面中使用CSS的方式主要有3种:行内添加定义style属性值,页面头部内嵌调用和外面链接调用,其中外面引用有两种:Link引入和@import导入,两者都是外部引用CSS的方式,但是存在一定的区别:
1、从属关系: link是标签,@import是css提供的.
2. 加载差异: link: 结构和样式同时加载;而@import 先加载结构,后加载样式
3. 兼容性:link没有兼容问题,@import不兼容ie5以下的浏览器.
4.可操作性: link可以通过js操作dom插入link标签改变样式,而@import不能
- Js函数
- 函数(方法)是油时间驱动的或者当它被调用时执行的可重复使用的代码块
- 函数可以看做一个功能 内部封装了一些操作,只有我们去调用的时候才会执行
- this指向
This永远指向最后一个调用它的那个对象
如何解决this指向问题?
- 使用箭头函数
- 写法不同:箭头函数使用箭头定义,普通函数没有
- 箭头函数不能用于构造函数,普通函数可以用于构造函数,以次创建对象 实例
- 箭头函数的this指向不同
箭头函数本身没有this 它的this 是父级普通函数的this
在普通函数中,this总是指向调用它的对象,如果用作构造函数,它指向创建的实例对象
- 箭头函数不具有arguments对象
- 它是函数一创建就有的
- 是一个类数组(并不是一个真正的数组)
- 方法调用的时候。可以得到所有传进来的参数
5. 箭头函数不能当做generator函数 不能使用yield关键字
6. 箭头函数不具有prototype原型对象
7. 箭头函数不具有super
- 函数内部_this = this
- 使用apply call bind
1.都可以更改this指向
2.call,bind后面的第一个参数是指向的对象,第二个参数是往对象传的值
3、apply后面的第一个参数是指向的对象,第二个参数是数组,数组里面是 往对象传的值(arguments 全部参数)
4.call和apply更改this指向会自动调用,bind需要手动调用
xw.say.call(xh,"实验小学","六年级");
xw.say.apply(xh,["实验小学","六年级"]);
xw.say.bind(xh,"实验小学","六年级")();
- new实例化一个对象
1、创建一个新对象,如:var person = {};
2、新对象的_proto_属性指向构造函数的原型对象。
3、将构造函数的作用域赋值给新对象。(也所以this对象指向新对象)
4、执行构造函数内部的代码,将属性添加给person中的this对象。
5、返回新对象person。
function Person(name) {
this.name = name
this.sayName= function () {
console.log(`我是 ${this.name}!`)
}
}
function myNew(that, ...args) {
const obj = Object.create(null)
obj.__proto__ = that.prototype
const res = that.call(obj, ...args)
return res instanceof Object ? res : obj
}
let person= myNew(Person, '小明')
person.sayWorld(); // 我是小明
13.JavaScript的事件流
事件冒泡:事件有最具体的元素接受,让后逐级向上传播
事件捕捉:事件由最不具体的节点接受,让后逐级向下,一直到最具体的
DOM事件流:三个阶段 事件捕捉 目标阶段 事件冒泡
14.防抖和节流
- 防抖
当持续触发事件时,一段时间内只能触发一次。将几次操作合并为一次操作进行
let telInput = document.querySelector('input');
telInput.addEventListener('input', function(e) {
let timeOut = null;
if(timeOut){
clearTimeout(timeOut)
}else{
timeOut = setTimeout(()=>{
$.ajax({})
},2000)
}
})
- 节流
当持续触发事件时,保证一定时间内只调用一次事件处理函数
let throttle = function(func, delay) {
let prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function demo() {
//do something
//ajax({})
//...
}
box.addEventListener('touchmove', throttle(demo, 2000));
- promise generator aysnc/await
promise比较简单,也是最常用的,主要就是将原来用 回调函数异步编程的方法 转成 relsove和reject触发事件;
对象内含有四个方法,then()异步请求成功后
catch()异步请求错误的回调方法
finally()请求之后无论是什么状态都会执行
resolve()将现有对象转换为Promise对象
all()此方法用于将多个Promise实例包装成一个新的promise 实例。
race()也是将多个Promise实例包装成一个新的promise实例
reject()返回一个状态为Rejected的新Promise实例。
有点:让回调函数变成了规范的链式写法,程序流程可以看的很清楚
缺点:编写的难度比传统写法高,阅读代码也不是一眼可以看懂
const promise = new Promise((resolve, reject) => {
// do something here ...
if (success) {
resolve(value); // fulfilled
} else {
reject(error); // rejected
}
});
generator是一个迭代生成器,其返回值为迭代器(lterator),是ES6标准引入的新的数据类型,主要用于异步编程,它借鉴于Python中的generator概念和语法;
generator函数内有两个重要方法,1 yield表达式 2.next()
Generator 函数是分段执行的,yield表达式是暂停执行的标记,而 next方法可以恢复执行
优点:1.利用循环,每调用一次,就使用一次,不占内存空间 2.打破了普通函数执行的完整性
缺点: 需要用next()方法手动调用,直接调用返回无效iterator
function fn(){ // 定义一个Generator函数
yield ‘hello’;
yield ‘world’;
return ‘end’;
}
var f1 =fn(); // 调用Generator函数
console.log(f1); // fn {[[GeneratorStatus]]: “suspended”}
console.log(f1.next()); // {value: “hello”, done: false}
console.log(f1.next()); // {value: “world”, done: false}
console.log(f1.next()); // {value: “end”, done: true}
console.log(f1.next()); // {value: undefined, done: true}
async:异步函数
await:同步操作
es7中提出来的异步解决方法,是目前解决异步编程终它基极解决方案,于promise为基础,其实也就是generator的高级语法糖,本身自己就相当于一个迭代生成器(状态机),它并不需要手动通过next()来调用自己,与普通函数一样
async就相当于generator函数中的*,await相当于yield,
async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
function getSomething() {
return "something";
}
async function testAsync() {
return Promise.resolve("hello async");
}
async function test() {
//await是在等待一个async函数完成
const v1 = await getSomething();
//await后面不仅可以接Promise,还可以接普通函数或者直接量
const v2 = await testAsync();
console.log(v1, v2);
}
- 原型,原型链,构造函数,继承
构造函数原型:每一个构造函数的内部都有一个 prototype 属性,这个属性时一个 指针,指向另一个对象,这个对象包含了可以由该构造函数的所有实例共 享的属性和方法。
对象原型:当我们使用构造函数新建一个对象后,在这个对象的内部将包含一个指 针,这个指针指向构造函数的 prototype 属性对应的值,这个指针称为 对象的原型。
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是 Object.prototype,然后Object.prototype.__proto _ _为null。
原型:每个JavaScript对象创建的时候,都会与之关联另一个对象,这个对象就是我们所说的原型,每个对象都会从原型中继承属性
在JavaScript中,每个函数都有一个prototype属性,这个属性指向函数的原型对象
每个对象都会有一个—proto——属性,整个属性指向的是该对象的原型
每个原型都有一个constructor属性,指向该关联的构造函数
原型链:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的指针,如果我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应的,另一个原型中也包含一个指向另一个原型的指针,假如另一个原型又是另一个原型的实例的实例,就构成了实例与原型的链条,这就是所谓的原型链
构造函数:它是在创建对象时候执行的,而且只执行一次,并先于其他成员函数执行,构造函数不需要人为调用,也不能被人为调用,一般声明为公有的,每个构造函数应该为每个数据成员提供初始化
继承:继承是子类对象里藏着一个父类对象。可以认为,创建子类对象时,也就同时创建了一个隐藏的父类对象。
- 子类继承了父类的方法和属性,但是子类不能访问父类的private方法和属性
- 使用子类的引用可以调用父类的公有属性
- 使用子类的引用可以调用父类的方法
- 就好像子类的引用可以一物两用,既可以当做父类的引用使用,又可以当子类 的引用使用
- js 基本数据类型
1.基本数据类型:js 一共有六种基本数据类型,分别是 Undefined、Null、Boolean、Number、 String,还有在 ES6 中新增的 Symbol 类型。
Symbol 代表创建后独一无二且不可变的数据类型,它的出现我认为 主要是为了解决可能出现的全局变量冲突的问题。
2.引用数据类型: 引用数据类型统称为 Object 对象,主要包括对象、数组、函数、日 期和正则等等。
3.判断数据类型的方法:
1.基本类型判断:在 JavaScript 里 使用 typeof 来判断数据类型,只 能区分基本类型,即’number’,’string’,’ undefined’,’boolean’, ‘object ‘,"function"六种
2.引用类型判断:区别对象、数组、函数可以使用 Object.prototype.toString.call 方法。判断某个对象值属于哪种 内置类型。
原理:在 Object.prototype.toString 方法被调用时,他会找this 对象的[[Class]]属性的值,将这个值与object字符串拼接并 返回。[[Class]]是一个内部属性,所有的对象都拥有该属性。 在规范中,[[Class]]的值是一个字符串值,表明了该对象的 类型。
3.对象类型判断:instanceof 运算符也常常用来判断对象类型。
Instanceof 是通过原型链去查找,找到某个对象的原型对象, 使用原型对象的constructor找到构造函数,看看构造函数与 Instanceof后面的是否相同,不相同,继续向上查找,直到尽头, 找到为True,没找到为false
4.constructor 似乎完全可以应对基本数据类型和引用数据类型 但如 果声明了一个构造函数,并且把他的原型指向了 Array 的原型,所 以这种情况下,constructor 也显得力不从心
18.null和undefined区别
undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。
当我们使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。
19.Array构造函数只有一个参数值时的表现
Array 构造函数只带一个数字参数的时候,该参数会被作为数组的预设长度这样创建出来的只是一个空数组,只不过它的 length 属性被设置成了指定的值。
- 闭包
1、概念
闭包函数:声明在一个函数中的函数,叫做闭包函数。
闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量, 即使在其外部函数被返回(寿命终结)了之后。
2、特点:1.让外部访问函数内部变量成为可能;2.局部变量会常驻在内存中;
3.可以避免使用全局变量,防止全局变量污染;4.会造成内存泄漏(有 一块内存空间被长期占用,而不被释放)
3、闭包的创建:
闭包就是可以创建一个独立的环境,每个闭包里面的环境都是独立的,互不干扰。闭包会发生内存泄漏,每次外部函数执行的时 候,外部函数的引用地址不同,都会重新创建一个新的地址。但凡是当前活动对象中有被内部子集引用的数据,那么这个时候,这个数据不删除,保留一根指针给内部活动对象。
闭包内存泄漏为: key = value,key 被删除了 value 常驻内存中; 局 部变量闭包升级版(中间引用的变量) => 自由变量;
4.应用场景:函数的防抖和节流
- 深浅拷贝
深拷贝是将一个对象从内存中完整的拷贝一份出来,开辟一个新的内存空间存放新对象,且修改新对象不会影响原对象。
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
实现浅拷贝
1.Object.assign():Object.assign() 方法可以把源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
2.Array.prototype.concat()
3.Array.prototype.slice()
4.函数库lodash的_.clone方法
5.展开运算符...
实现深拷贝
1.函数库lodash的_.cloneDeep方法
2.JSON.parse(JSON.stringify());
3.递归深拷贝
判断当前值是否为对象
1、如果不是对象,直接返回
2、如果是对象,创建结果数组,遍历对象,对当前值进行递归拷贝。
//递归实现深拷贝
function cloneDeep(obj) {
if (typeof obj == 'object') {
let cloneTarget = Array.isArray(obj) ? [] : {};
//递归拷贝
for (let key in obj) {
cloneTarget[key] = cloneDeep(obj[key]);
}
//返回递归拷贝后的结果
return cloneTarget;
} else {
//直接返回cuo
return obj;
}
}
- MAp,Set,WeakMap.WeakSet
Map 叫字典,以键值对的形式存储。
Map 的键可以为任意值,而 WeakMap 的键只能是弱引用对象,在进行垃 圾回收的时候不会考虑 WeakMap 对对象的引用。
Map的应用场景:数组去重,数据存储
WeakMap应用场景:保存DOM节点关联元数据。
Set 集合,与数组类似,但成员唯一且无序,无重复值。
Set 的元素可以为任意值,WeakSet 的元素只能为弱引用对象。
Set :数组去重,数据存储
WeakSet应用:给对象打标签,例如查询元素是不是被禁用。
Set的方法
add(value):新增
delete(value):存在即删除集合中value
has(value):判断集合中是否存在 value
Set转数组
Array.from 方法可以将 Set 结构转为数组
使用…剩余运算符
遍历
Set.prototype.keys():返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries():返回键值对的遍历器
Set.prototype.forEach((item,key)=>{}):使用回调函数遍历每个成员
Map的方法
set(key, value):向字典中添加新元素
get(key):通过键查找特定的数值并返回
has(key):判断字典中是否存在键key
delete(key):通过键 key 从字典中移除对应的数据
clear():将这个字典中的所有元素删除
遍历
Map.prototype.forEach((item,key)=>{}):遍历 Map 的所有成员。
Map.prototype.keys():返回键名的遍历器。
Map.prototype.values():返回键值的遍历器。
Map.prototype.entries():返回所有成员的遍历器。
23.数组扁平化
数组扁平化:将嵌套的数组进行降维处理。
可以使用数组拍平方法 Array.prototype.flat(),接受一个参数
不传参数时,默认“拉平”一层,可以传入一个整数,表示想要“拉平”的层数。
传入 <=0 的整数将返回原数组,不“拉平”
Infinity 关键字作为参数时,无论多少层嵌套,都会转为一维数组
如果原数组有空位,Array.prototype.flat() 会跳过空位。
实现数组拍平flat函数
实现思路:
1、遍历数组
2、判断当前数组是否为数组
3、展开一层数组
Array.prototype._flat = function (num = 1) {
//<=0不展开直接返回
if (num <= 0) {
return this;
}
let arr = [];
this.forEach((item) => {
if (Array.isArray(item)) {
//展开
arr = arr.concat(item._flat(num - 1));
} else {
arr.push(item);
}
})
num--;
return arr;
}
reduce拍平
Array.prototype._flat = function (num = 1) {
if (num <= 0) {
return this;
}
let arr = this;
let res = arr.reduce((sum, cur) => {
if (Array.isArray(cur)) {
sum = sum.concat(cur._flat(num - 1));
} else {
sum.push(cur);
}
return sum
}, []);
num--;
return res;
}
24.介绍一下遍历方法
For,,of: for…of 循环可以使用的范围包括数组、Set 和 Map 结构以及字符 串等可遍历对象
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
For...in:for…in 一般用于遍历对象,循环读取键名。
forEach():forEach() 方法用于调用数组的每个元素,并将元素传递给回调函 数。
reduce():reduce() 接收一个函数作为累加器,数组中的每个值(从左到右) 开始获取,最终计算为一个值。
array.reduce(function(total, currentValue, currentIndex, arr),initialValue)
map():map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数 处理后的值。
map和foreach有什么区别
forEach一般只用来遍历数组,不改变其数据。
map用来遍历数组并改变数据,返回新数组。
1、forEach()方法不会返回执行结果,而是undefined;map()方法会得 到一个新的数组并返回。
2、map能保证原始数组的不变。forEach 不能确保数组的不变性,只 有你不改变数据,原数组才会不变。
25.垃圾回收机制
JS的垃圾回收机制是,垃圾回收程序会定期找出那些不再继续使用的变量, 然后释放其内存。
垃圾回收实现方式主要有两种,标记清除和引用计数。
标记清除:垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后, 它会将所有在上下文中的变量,以及被在上下文中的变量引用的变 量的标记去掉。在此之后再被加上标记的变量就是待删除的了,随 后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们 的内存。
引用计数:引用计数是指每个值被引用的次数。当声明了一个变量并将一个 引用类型值赋给该变量时,则这个值的引用次数就是1。如果同 一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含 对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。 当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而 就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行 时,它就会释放那些引用次数为0的值所占用的内存。
- 作用域和作用域链
对作用域的理解:1.作用域包括全局作用域、函数作用域、块级作用域。
2.全局作用域中创建的变量,在任意地方都可以访问。
3.函数作用域中的变量,只有在函数内部才能访问。
4.块级作用域中的变量,只能在当前块中进行访问
对作用域链的理解(变量的一个搜索过程)
所谓作用域链,其实就是我们在某个作用域中获取某个变量的值,如果在该函数中 没有该变量的定义,则会到创建这个函数的那个域寻找,如果也没有,就会一层一 层的向上寻找,直到找到全局作用域还是没有找到,就结束。这个一层层搜索的过 程就是作用域链。
- js继承
1.原型链继承:将父类的实例作为子类的原型,这样根据原型链,子类就可以 访问到父类的属性和方法
优点:1、父类方法可以复用
缺点:1.父类的所有引用属性(info)会被所有子类共享,更改一个子类 的引用属性,其他子类也会受影响
2.子类型实例不能给父类型构造函数传参
2.构造函数继承:通过使用call()或apply()方法,Parent构造函数在 为Child的实例创建的新对象的上下文执行了,就相 当于新的Child实例对象上运行了Parent()函数中的 所有初始化代码,结果就是每个实例都有自己的info 属性。
优点:1.可以在子类构造函数中向父类传参数
2.父类的引用属性不会被共享
缺点:子类不能访问父类原型上的方法(即不能访问Parent.prototype 上定义的方法),因此所有方法属性都写在构造函数中,每次创 建实例都会初始化
- 组合继承:组合继承综合了原型链继承和构造函数继承,将两者的优点结 合了起来。基本的思路就是使用原型链继承原型上的属性和方法, 而通过构造函数继承实例属性,这样既可以把方法定义在原型上 以实现重用,又可以让每个实例都有自己的属性
优点:1.父类的方法可以复用
2可以在Child构造函数中向Parent构造函数中传参
3.父类构造函数中的引用属性不会被共享
4.寄生式继承:通过原型式继承的方法创建一个实例,然后为这个实例 添加属性和方法,最后返回这个实例。
5.寄生组合继承:寄生组合式继承在吸取了组合式继承的优点上,避免 了在子函数的原型上面创建不必要的、多余的属性
- 什么是纯函数
纯函数的概念:一个函数的返回结果只依赖其参数,并且执行过程中没有副作用。
- 什么是高阶函数
一个函数作为另外一个函数的参数或者一个函数的返回值为另外一个函数这种函数就称之为高阶函数。
- 事件循环
js执行机制:
1.先执行执行栈中的同步任务
2.异步任务(回调函数)先放入任务队列中(先不执行)
3.一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环
- 怎么阻止冒泡事件
w3c: event.stopPropagation()
IE: window.event.cancelBubble = true
- 怎么阻止默认事件
event.preventDefault()。
- 函数柯里化及其用途
柯里化,英语:Currying,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,
并且返回接受余下的参数而且返回结果的新函数的技术。
- return、break和continue的区别
return 必须写在函数内部,遇到return后函数内部剩余的代码不再执行,直接返回;还可以使用return返回一个值给外面使用
break 跳出循环,剩余的循环不再执行
continue 跳出本次循环,剩余的循环继续执行
什么是回调地域
回调地狱就是多层嵌套的问题。 每种任务的处理结果存在两种可能性(成功或失败),那么需要在每种任务执行结束后分别处理这两种可能性,需要多次异步请求的话,就会显得代码跳跃且乱。
页面性能优化
1、代码压缩:css、js代码代码压缩
2、Gzip压缩/Br压缩
3、推迟非关键资源的加载:异步加载的三种方式——async和defer、动态脚本创建
async属性
在script上边使用async属性,会异步执行引入的JavaScript。
如果是多个脚本,该方法不能保证脚本按顺序执行。
defer属性
在script上边使用defer属性,会延迟执行引入的JavaScript。
若果是多个脚本,可以确保设置defer属性的脚本按顺序执行。
动态创建script标签
window.onload方法确保页面加载完毕再将script标签插入到DOM中
- 利用浏览器缓存,减少服务器压力。
5、使用CDN
6、图片优化:懒加载、预加载。
7、针对一些行为进行节流和防抖,防止频繁向服务器发请求。
8、减少回流和重绘。
9、路由懒加载
JavaScript有几种类型的值?你能画一下他们的内存图吗?
基本数据类型存储在栈中,引用数据类型(对象)存储在堆中,指针放在栈中。
两种类型的区别是:存储位置不同;原始数据类型直接存储在栈中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;引用数据类型存储在堆中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能.
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
栈和堆的区别?
栈(stack):由编译器自动分配释放,存放函数的参数值,局 部变量等;
堆(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统释 放。
堆栈内存是什么:
基本数据类型:直接存储在栈内存中,占据空间小,大小固定,属于被频繁使用的数据。 引用数据类型:同时存储在栈内存与堆内存中,占据空间大,大小不固定。
引用数据:类型将指针存在栈中,将值存在堆中。 当我们把对象值赋值给另外一个变量时,复制的是对象的指针,指向同一块内存地址
attribute与property的区别?
attribute是dom元素在文档中作为html标签拥有的属性。
property是dom元素在js中作为对象拥有的属性。
所以,对于html的标准属性来说,attribute和property是同步的,是会自动更新的。但对于自定义属性,他们不同步。
、请描述一下 cookies,sessionStorage 和 localStorage 的区别?
cookie:一个大小不超过4K的小型文本数据,一般由服务器生成,可以设置失效时间;若没有设置时间,关闭浏览器cookie失效,若设置了 时间,cookie就会存放在硬盘里,过期才失效,每次http请求,header都携带cookie
localStorage:5M或者更大,永久有效,窗口或者浏览器关闭也会一直保存,除非手动永久清除或者js代码清除,因此用作持久数据,不参与和服务器的通信
sessionStorage关闭页面或浏览器后被清除。存 放数据大小为一般为 5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。
谈谈JS的运行机制
1. js单线程
JavaScript语言的一大特点就是单线程,即同一时间只能做一件事情。
2. js事件循环
js代码执行过程中会有很多任务,这些任务总的分成两类:
同步任务
异步任务
需要注意的是除了同步任务和异步任务,任务还可以更加细分为macrotask(宏任务)和microtask(微任务),js引擎会优先执行微任务
微任务包括了 promise 的回调、node 中的 process.nextTick 、对 Dom 变化监听的 MutationObserver。
宏任务包括了 script 脚本的执行、setTimeout ,setInterval ,setImmediate 一类的定时事件,还有如 I/O 操作、UI 渲 染等。
首先js 是单线程运行的,在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行。
在执行同步代码的时候,如果遇到了异步事件,js 引擎并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务
当同步事件执行完毕后,再将异步事件对应的回调加入到与当前执行栈中不同的另一个任务队列中等待执行。
任务队列可以分为宏任务对列和微任务对列,当当前执行栈中的事件执行完毕后,js 引擎首先会判断微任务对列中是否有任务可以执行,如果有就将微任务队首的事件压入栈中执行。
当微任务对列中的任务都执行完成后再去判断宏任务对列中的任务。
ES6 新增特性
新增了块级作用域(let,const)
提供了定义类的语法糖(class)
新增了一种基本数据类型(Symbol)
新增了变量的解构赋值
函数参数允许设置默认值,引入了 rest 参数,新增了箭头函数
数组新增了一些 API,如 isArray / from / of 方法;数组实例新增了entries(),keys() 和 values() 等方法
对象和数组新增了扩展运算符
ES6 新增了模块化(import/export)
ES6 新增了 Set 和 Map 数据结构
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例
ES6 新增了生成器(Generator)和遍历器(Iterator)
require与import的区别和使用(CommonJS规范和es6规范)
1、import是ES6中的语法标准也是用来加载模块文件的,import函数可以读取并执行一个JavaScript文件,然后返回该模块的export命令指定输出的代码。export与export default均可用于导出常量、函数、文件、模块,export可以有多个,export default只能有一个。
2、require 定义模块:module变量代表当前模块,它的exports属性是对外的接口。通过exports可以将模块从模块中导出,其他文件加载该模块实际上就是读取module.exports变量,他们可以是变量、函数、对象等。在node中如果用exports进行导出的话系统会系统帮您转成module.exports的,只是导出需要定义导出名。
require与import的区别
1,require是CommonJS规范的模块化语法,import是ECMAScript 6规范的模块化语法;
2,require是运行时加载,import是编译时加载;
3,require可以写在代码的任意位置,import只能写在文件的最顶端且不可在条件语句或函数作用域中使用;
4,require通过module.exports导出的值就不能再变化,import通过export导出的值可以改变;
5;require通过module.exports导出的是exports对象,import通过export导出是指定输出的代码;
- require运行时才引入模块的属性所以性能相对较低,import编译时引入模块的属性所所以性能稍高
简述 let const var 的区别 以及使用场景
var let 是用来声明变量的,而const是声明常量的 var
1.var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
2、一个变量可多次声明,后面的声明会覆盖前面的声明
3、在函数中使用var声明变量的时候,该变量是局部的作用域只在函数内部,而如果在函数外部使用 var,该变量是全局的
let
1、不存在变量提升,let声明变量前,该变量不能使用。就是 let 声明存在暂时性死区 2、let命令所在的代码块内有效,在块级作用域内有效,作用域只是在花括号里面
3、let不允许在相同作用域中重复声明,注意是相同作用域,不同作用域有重复声明不会报错
const
1、const声明一个只读的常量,声明后,值就不能改变
2、let和const在同一作用域不允许重复声明变量const声明一个只读的常量。一旦声明,常量的值就不能改变,但对于对象和数据这种 引用类型,内存地址不能修改,可以修改里面的值。
3、let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
4、能用const的情况下尽量使用const,大多数情况使用let,避免使用var。 const > let > var const声明的好处,一让阅读代码的人知道该变量不可修改,二是防止在修改代码的过程中无意中修改了该变量导致报错,减少bug的产生
map和forEach的区别
相同点
都是循环遍历数组中的每一项 forEach和map方法里每次执行匿名函数都支持3个参数,参数分别是item(当前每一项)、index(索引值)、arr(原数组),需要用哪个的时候就写哪个 匿名函数中的this都是指向window 只能遍历数组
注意:forEach对于空数组是不会调用回调函数的。
不同点
map方法返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。(原数组进行处理之后对应的一个新的数组。) map()方法不会改变原始数组 map()方法不会对空数组进行检测 forEach()方法用于调用数组的每个元素,将元素传给回调函数.(没有return,返回值是undefined)
解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值
常见的几种方式有
1.默认值
2.交换变量
3.将剩余数组赋给一个变量
结构数组和对象字符串区别
对象的解构与数组类似,但有所不同。数组的元素是按次序排列的,变量的取值由它的位置决定;
而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。字符串也是可以解构赋值的。字符串被转换成了一个类似数组的对象.
我在项目中:就是从目标对象或数组中提取自己想要的变量。最常用的场景是:element-ui,vant-ui按需引入,请求接口返回数据,提取想要数据。
for...in 迭代和 for...of 有什么区别
1、 推荐在循环对象属性的时候,使用 for...in,在遍历数组的时候的时候使用for...of。
2、 for in遍历的是数组的索引,而for of遍历的是数组元素值
3、for...of 不能循环普通的对象,需要通过和 Object.keys()搭配使用
4、for...in 便利顺序以数字为先 无法便利 symbol 属性 可以便利到公有中可枚举的
5、从遍历对象的角度来说,for···in会遍历出来的为对象的key,但for···of会直接报错
、js 延迟加载的方式有哪些?
js 的加载、解析和执行会阻塞页面的渲染过程,因此我们希望 js 脚本能够尽可能的延迟加载,提高页面的渲染速度。
我了解到的几种方式是:
将 js 脚本放在文档的底部,来使 js 脚本尽可能的在最后来加载执行。
给 js 脚本添加 defer属性,这个属性会让脚本的加载与文档的解析同步解析,然后在文档解析完成后再执行这个脚本文件,这样的话就能使页面的渲染不被阻塞。
给 js 脚本添加 async属性,这个属性会使脚本异步加载,不会阻塞页面的解析过程,但是当脚本加载完成后立即执行 js脚本,这个时候如果文档没有解析完成的话同样会阻塞。
动态创建 DOM 标签的方式,我们可以对文档的加载事件进行监听,当文档加载完成后再动态的创建 script 标签来引入 js 脚本。
1、 vue生命周期(11个)可以根据周期扩充很多题可以看完。
beforeCreate() 创建前,这个时候data中的数据,还未定义,所以不能使用
created()创建后 最早开始使用 data和methods中数据的钩子函数
beforeMount()挂载前 指令已经解析完毕内存中已经生成dom树,还没有渲染到本地
mounted()挂载后 dom已经渲染完毕,最早可以操作DOM元素钩子函数
beforeUpdate()更新前 当data的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新
updated()更新后 数据更新完成以后触发的方法,DOM节点已经更新
beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
destroyed()已经销毁完毕
其他三个:
activated 被 keep-alive 缓存的组件激活时调用。
deactivated 被 keep-alive 缓存的组件停用时调用。
errorCaptured 2.5.0+ 新增当捕获一个来自子孙组件的错误时被调用
Vue3.0对比vue2中的生命周期做了一些改动:
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
destroyed -> onUnmounted 组件卸载之前执行的函数。
深入扩展
- vue的实例加载完成是在哪个声明周期完成呢
beforeCreate
- vue的dom挂载完成是在哪个声命周期里呢
mounted
1、created mounted 的区别?
created 模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
2、怎么在created里面操作dom?
this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
可以根据打印的顺序看到,在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作并无作用,而在created()里使用this.$nextTick()可以等待dom生成以后再来获取dom对象,而通过this.$nextTick()获取到的值为dom更新之后的值
setTimeout(() => {
console.log(this.$refs.button);
});
3、那 setTimeout this.$nextTick 什么区别呢?
setTimeout 将同步转换为异步 this.$nextTick
this.$nextTick 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,
4、this.$nextTick()是宏任务还是微任务啊?
微任务
5、a页面跳转到b页面周期执行
页面a----beforeCreate undefined
页面a----created 1
页面a----beforeMount 1
页面a----mounted 1
页面b----beforeCreate undefined
页面b----created 1
页面b----beforeMount 1
页面a----beforeDestroy 1
页面a----destroyed 1
页面b----mounted 1
6、组件 和 页面周期 的执行顺序
- 页面beforeCreate undefined
- 页面created 1
- 页面beforeMount 1
- 组件beforeCreate undefined
- 组件created 5555
- 组件beforeMount 5555
- 组件mounted 5555
- 页面mounted 1
7、父子组件生命周期执行顺序
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
代码更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
代码销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
代码常用钩子简易版
父create->子created->子mounted->父mounted
8、补充单一组件钩子执行顺序
activated, deactivated 是组件keep-alive时独有的钩子
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
errorCaptured
watch
仅仅是数据发生改变的时候会侦听到;
只是会检测到你写在watch里的那些属性,没写的就不会触发。
updated
执行到它的时候时候是数据发生变化且界面更新完毕;
不能监听到路由数据(例如网址中的参数);
所有的数据发生变化都会调用(消耗性能);
每次触发的代码都是同一个
computed
1、监控自己定义的变量,不用再data里面声明,函数名就是变量名
2、适合多个变量或对象进行处理后返回一个值(结果)。若这多个变量发生只要有一个发生变化,结果都会变化。
3、计算的结果具有缓存,依赖响应式属性变化,响应式属性没有变化,直接从缓存中读取结果。
4、在内部函数调用的时候不用加()。
5、必须用return返回
6、不要在computed 中对data中的数据进行赋值操作,这会形成一个死循环。
methods
用 methods 方法编写的逻辑运算,在调用时 add() 一定要加“()”,methods 里面写的多位方法,调用方法一定要有()。methods方法页面刚加载时调用一次,以后只有被调用的时候才会被调用。
在重新渲染的时候每次都会被重新的调用;
使用场景?
watch:
1、watch 函数是不需要调用的。
2、重点在于监控,监控数据发生变化的时候,执行回调函数操作。
3、当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch
4、函数名就是你要监听的数据名字
updated
有事先设置好的data变量如下arrData改变并且要在页面重新渲染{undefined{ arrData }}完成之后,才会进updated方法,
光改变arrData但不渲染页面是不会进的.
使用场景:
computed:
1、一个需要的结果受多个数据影响的时候,比如购物车结算金额(受到很多处的价格结算)。
2、操作某个属性,执行一些复杂的逻辑,并在多处使用这个结果。
3、内部函数中多处要使用到这个结果的。
watch :
1、监控一些input框值的特殊处理,适合一个数据影响多个数据。
2、数据变化时,执行一些异步操作,或开销比较大的操作
2vuex是什么, state,getters,mutations,actions,modules的用途和用法
vuex 是一个状态管理工具,它采用集中式存储管理应用的所有组件的状态,当有多个组件共享数据时,如果需要构建是一个中大型单页应用,会考虑如何更好地在组件外部管理状态,就使用Vuex 。
好处:
①: 能够在 vuex 中集中管理共享的数据,易于开发和后期维护
②: 可以做状态管理、采用localstorage保存信息、数据一直存储在用户的客户端中
③: 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步,能够高效地实现组件之间的数据共享,提高开发效率
vuex核心:
state:vuex的基本数据,数据源存放地,用于定义共享的数据。
geeter:从基本数据派生的数据,相当于state的计算属性
mutation:提交更新数据的方法,唯一 一个可以操作state 中数据的方法,必须是同步的,第一个参数是state,第二个参数是cmmi传过来的数据
action:action是用来做异步操作的,一般用来发请求,在 action 中写入函数,然后在页面中用dispatch调用,然后在 action 中通过commit 去调用 mutation 通过 mutation 去操作state。
modules:模块化vuex,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理
详述Vuex运行机制
(1) Vuex的状态存储是响应式的单页面
(2) 当vue组件从store中读取时,若store中状态发生改变,响应的组件也会更新状态
(3) 不能直接改变state,必须通过显示的提交(commit)mutations来追踪每个状态的变化
高级用法辅助函数(语法糖)
mapState,mapActions,mapMutations,mapGetters
辅助函数可以把vuex中的数据和方法映射到vue组件中。达到简化操作的目的
如何使用:
Import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'
computed(){mapActions(['名字'])}
3、vue中key 的作用(都可以三种)
“key 值:用于管理可复用的元素。因为 Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做使 Vue 变得非常快,但是这样也不总是符合实际需求。 2.2.0+ 的版本里,当在组件中使用 v-for 时,key 是必须的。”
更高效的对比虚拟DOM中每个节点是否是相同节点,相同就复用,不相同就删除旧的创建新的
key是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,更准确, 更快的找到对应的vnode节点
什么是虚拟dom,和 diff 算法
虚拟dom 是根据模板生成一个js对象(使用createElement,方法),根据这个js对象再去生成真实的dom,对复杂的文档DOM结构,提供一种方便的工具,进行最小化的DOM操作 ,是可以快速的渲染和高效的更新元素,提高浏览器的性能,
例如,一个 ul 标签下很多个 li 标签,其中只有一个 li 有变化,这种情况下如果使用新的 ul 去替代旧的 ul,因为这些不必要的 DOM 操作而造成了性能上的浪费,但是如果直接使用虚拟节点覆盖旧节点的话,减少很多不必要的 DOM 操作。。
diff算法 当data发生改变 会根据新的数据生成一个新的虚拟dom ,新的虚拟dom和旧的虚拟dom进行对比,这个对比的过程就是diff算法,会找到不同地方,只去渲染不同的地方
总的来说就是减少DOM,重绘和回流。
vue中 methods,computed, watch 的区别
computed 是vue中的计算属性,具有缓存性,当他的依赖于值,发生改变的时候才会重新调用
methods 是没有缓存的,只要调用,就会执行,一般结合事件来使用
watch 没有缓存性 监听data中的属性 属性值只要发生变化就会执行 可以利用他的特性做一些异步的操作
、 vue 双向数据绑定原理
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图,实现数据和视图同步。
1、 observer 主要是负责对Vue数据进行递归便利,使其数据拥有get和set方法,当有数据给某个对象值赋值,就触发 setter 就监听到数据的变化了。( 如有变动可拿到最新值并通知订阅者 )
2、 compile (抗牌偶) 指令解析器负责绑定数据和指令解析。 将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数。一旦数据有变动,收到通知,更新视图
3、 watcher Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是 负责数据监听,当数据发生改变,能调用自身的update()方法,并触发Compile中绑定的回调
4、mvvm 入口函数,整合以上三者
在vue3 中
Vue3是通过Object.define.proxy 对对象进行代理,从而实现数据劫持。使用Proxy 的好处是它可以完美的监听到任何方式的数据改变,唯一的缺点是兼容性的问题,因为 Proxy 是 ES6 的语法
路由导航守卫有几种,如何实现,重定向用哪个属性?
•一:全局的守卫
无论访问哪一个路径,都会触发全局的钩子函数,位置是调用router的方法 router/index.js
router.beforeEach 全局前置守卫 进入路由之前
router.beforeResolve 全局解析守卫,在beforeRouteEnter调用之后调用,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用
router.afterEach 全局后置钩子 进入路由之后,你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:
二:组件级路由守卫 放在要守卫的组件里,跟data和methods同级
beforeRouteEnter 进入路由前,此时实例还没创建,无法获取到zhis
beforeRouteUpdate (2.2) 路由复用同一个组件时
beforeRouteLeave 离开当前路由,此时可以用来保存数据,或数据初始化,或关闭定时器等等
三:单个路由规则独享的守卫 写在路由配置中,只有访问到这个路径,才能触发钩子函数
beforeEnter(){}
什么是 mixin ?
Mixin 使我们能够为 Vue 组件编写可插拔和可重用的功能。
如果希望在多个组件之间重用一组组件选项,例如生命周期 hook、 方法等,则可以将其编写为 mixin,并在组件中简单的引用它。
然后将 mixin 的内容合并到组件中。如果你要在 mixin 中定义生命周期 hook,那么它在执行时将优化于组件自已的 hook。
Vue模版编译原理。
vue中的模板template无法被浏览器解析并渲染,因为这不属于浏览器的标准,不是正确的HTML语法,所有需要将template转化成一个JavaScript函数,这样浏览器就可以执行这一个函数并渲染出对应的HTML元素,就可以让视图跑起来了,这一个转化的过程,就成为模板编译。
模板编译又分三个阶段,解析parse,优化optimize,生成generate,最终生成可执行函数render。
vue 中数组中的某个对象的属性发生变化,视图不更新如何解决
问题原因:因为 vue 的检查机制在进行视图更新时无法监测 数组中的对象的某个属性值的变化。解决方案如下
方案一:利用 this.set(this.obj,key,val)
例:this.set(this.obj,‘k1’,‘v1’)
方案二:就利用 Object.assign({},this.obj)创建新对象 (额 晒恩)
如果是数组就 Object.assign([],this.obj)
如果是对象就 Object.assign({},this.obj)。
vue3.0 与 vue2.0 的区别
1.性能提升
更小巧,更快速;支持摇树优化。支持 Fragments 和跨组件渲染;支持自定义渲染器。
2.API 变动
vue2:optionsApi 使用传统api中,新增一个需求,要在data,methods,computed中修改
vue3:compositionApi 我们可以更加优雅的组织我们的代码,函数,让我们的代码更加有序的组合在一起
除渲染函数 API 和 scoped-slot 语法之外,其余均保持不变或者将通过另外构建一个兼容包 来兼容 2.x。
模板语法的 99% 将保持不变。除了 scoped slot 语法可能会有一些微调之外变动最大的部分将是渲染函数 (render) 中的虚拟 DOM 的格式。
3.重写虚拟 DOM (Virtual DOM Rewrite)
随着虚拟 DOM 重写,减少 运行时(runtime)开销。重写将包括更有效的代码来创建虚拟节点。
vue3 没有了过滤器
双向数据绑定 从 Object.defineProperty() 变成了 proxy,数据变化了试图数据没发生变化 this.$set() vue3不需
Vue-router共有几种模式?默认是那种?hash和history模式
有两种模式 hash和history模式 默认是hash
1、hash ——即地址栏 URL 中的#符号,它的特点在 于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影 响,因此改变 hash 不会重新加载页面。
2、history ——利用了 HTML5 History api 在浏览器中没有# 有浏览器兼容问题
history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 地址后加上/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。
axios的二次封装怎么做的?你怎么发请求?
首先要安装axios,一般我会在项目的src目录中,新建一个network文件夹,作为我们的网络请求模块,然后在里面新建一个http.js和一个api.js文件和一个reques.js。http.js文件用来封装我们的axios,api.js用来统一管理我们的接口url,在request.js中添加请求拦截和响应拦截。
在请求拦截中,会给请求头添加token字段,还有loading动画的开启。在响应拦截中,可以做一些loading动画的关闭,还有可以根据后端返回的状态码,做一些检验token是否有效或者过期的操作。
接着就是做一些axios进行的api接口的封装,这里我用到了async,await封装请求接口函数,这样可以代将异步操作同步化操作,码更加友好,避免回调地域的出现
面向过程,面向对象,面向过程和面向对象的优缺点
一、面向过程:面向过程就是分析出实现需求所需要的步骤,通过函数一步一步实现这些步骤,接着依次调用即可。
二、面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程面向过程:
优点:性能上它是优于面向对象的,因为类在调用的时候需要实例化,开销过大。
缺点:不易维护、复用、扩展
用途:单片机、嵌入式开发、Linux/Unix等对性能要求较高的地方
面向对象:
面向对象有三大特性:封装,继承,多态。
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护 。
缺点:性能比面向过程低
1、 Vue与Angular以及React的区别
▍Angular
框架比较成熟完整,过于庞大,上手难;
指令以ng-xxx开头; 由谷歌开发和维护;
版本1比较适合PC端开发,版本2在往移动端靠;
不支持低版本浏览器; 内置指令和自定义指令;
内置过滤器和自定义过滤器; 支持双向数据绑定;
▍Vue
它是一个轻量级框架,其核心库只关注视图层,简单小巧、易学易上手;
指令以v-xxx开头; 个人维护项目; 适合于移动端开发; 不支持低版本浏览器;
内置指令和自定义指令; 内置过滤器和自定义过滤器; 支持双向数据绑定;
使用DOM模板。中心思想:一切都是组件,组件实例之间可以嵌套; 核心库不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载; 基于依赖追踪的观察系统,并且异步队列更新。
▍React
依赖虚拟DOM; 采用特殊的JSX语法; 中心思想:一切都是组件,组件实例之间可以嵌套; 核心库不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载。
三次握手和四次挥手
三次握手:
第一次:建立连接时,客户端发送syn包到服务器,等待服务端确认
第二次:服务器收到syn包,必须确认客户的syn,同时也发送一个syn包,即syn+ACK包
第三次:客户端收到服务器的syn和ack包,向服务器发送确认包ack,发送完毕,客户端和服务端连接成功,完成三次握手
四次挥手:
第一次:浏览器发送完数据后,发送fin请求断开连接
第二次:服务器发送ack到客户端,确认客户端的断开请求
第三次:服务器请求断开fin的请求
第四次:客户端确认服务器的断开ack
Webpack
- 模块化分类有哪些
- 浏览器端的模块化
- AMD(Asynchronous Module Definition,异步模块定义) 代表产品为:Require.js
- CMD(Common Module Definition,通用模块定义) 代表产品为:Sea.js
- 服务器端的模块化,服务器端的模块化规范是使用CommonJS规范:
- 使用require引入其他模块或者包
- 使用exports或者module.exports导出模块成员
- 一个文件就是一个模块,都拥有独立的作用域
- ES6模块化,ES6模块化规范中定义:
1.每一个js文件都是独立的模块
2.导入模块成员使用import关键字
3.暴露模块成员使用export关键字
小结:推荐使用ES6模块化,因为AMD,CMD局限使用于浏览器端,
CommonJS在服务器端使用,
ES6模块化是浏览器端和服务器端通用的规范.
- export default 和 exports有什么区别
前者是默认导出,每个模块只能有一个,导入的时候需要用 import XX from‘XXX’这种方式
后者是导出,每个模块可以有多个,导入的时候需要用import {XX} from‘XX’的方式
如果在一个模块中没有向外暴露成员,其他模块引入该模块时将会得到一个空对象
- webpack的作用是什么
webpack是一个流行的前端项目构建工具,提供了模块化支持,代码压缩混淆,解决兼容问题,性能优化等特性,提高了开发效率和项目的可维护性。
- 对代码重新加载翻译。
- 合并静态资源,减少io
- webpack的安装命令是什么
npm install webpack webpack-cli -D
- webpack当中的development和pruduction有什么区别
前者为开发模式,代码不会进行压缩,打包速度也更快
后者是生产模式,代码会进行压缩,打包速度相对较慢
- 如何配置webpack的出口和入口
在webpack.config.js当中设置entry字段,该字段用来配置文件的入口,默认为src下的index.js
在webpack.config.js当中设置output字段,该字段用来配置文件的出口,默认为dist文件下的main.js
- 如何配置webpack自动打包的功能
A.安装自动打包功能的包:webpack-dev-server
npm install webpack-dev-server -D
B.修改package.json中的dev指令如下:
"scripts":{
"dev":"webpack-dev-server"
}
C.将引入的js文件路径更改为:<script src="/bundle.js"></script>(绝对路径)
D.运行npm run dev,进行打包
- webpack Loder和plugins区别
loader是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等
plugins 主要是拓展 webpack 功能
- webpack怎么打包非js文件
下载文件对应的加载器,然后再webpack.config.js当中配置module的语法规则
- webpack如何打包css文件
下载style-loader 和 css-loader,然后再webpack.config.js当中配置语法规则
- webpack如何打包less文件
下载less、less-loader、css-loader、style-loader,然后配置语法规则
- webpack如何打包图片文件
下载url-loader、file-loader ,配置语法规则
- webpack打包非vue
- npm init 初始项目
- 安装webpack及web -cli
- 配置打包入口(entry)/出口(output)
- 设置自动打包
- 下载模块加载器,在webpack.config.js配置语法规则
微信小程序
- 微信小程序当中如何获取用户信息
wx.getUserInfo 现在版本更新为wx.getUserProfile
- 微信小程序组件传值
父组件给子组件传值:
将页面中data中数据传递给组件供组件使用:
1. 给父组件中子组件组件绑定一个自定义属性 在小程序中给标签绑定自定义属性无需加:号,直接 写就可以了
例如 给一个自定义组件child绑定一个list自定义属性
<child list="{{绑定的data中数据}}"></child>
2. child组件中获取传递的参数:
在组件的js文件中 properties: {}中接收
properties: {} 组件的属性列表 用来接收父组件传递过来的数据
例如 properties: {
list:Array//绑定的自定义属性名称:数据类型
}
然后就直接可以使用传递过来的list了
子组件给父组件传值:
事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。
1. 在子组件中 使用this.triggerEvent("自定义事件名称",将要传递的参数)发送一个自定义事件
2. 在父组件中的子组件上绑定一个自定义事件 bind子组件传递的自定义事件名="自定义事件名" 如:child子组件传递的事件为getUser,则父组件上子组件绑定的自定义事件就要为bindgetUser="getUserName"
3. 在父组件的自定义事件中使用 e.detail 获取子组件传递过来的参数
如:getUserName(){
let childValue=e.detail
}
- 路由跳转传参
使用<navigator url="/路径"></navigator>组件进行路径跳转时可以在路径后面拼接参数进行传参 方式类似于get请求传参
例如:<navigator url="/路径?id=01"></navigator>
获取参数时在跳转后页面的js中onLoad: function (options) {}页面加载生命周期中使用自带的参数options.属性名进行获取
如 获取如上例子中传递的id :
onLoad: function (options) {
console.log(options.id)
}
- 微信小程序如何实现用户登录
wx.login
- 微信小程序当中如何获取当前手机设备信息,比如品牌、操作系统、蓝牙信息等
wx.getSystemInfo
- 微信小程序如何实现更新微信版本
wx.updateWeChatApp
- 微信小程序的页面跳转有哪些方式
wx.switchTab 只能跳转到tabbar包含的几个页面
wx.navigateTo 跳转到不在tabbar里包含的其它页面
wx.navigateBack 关闭当前页面,返回到上一级
wx.redirectTo 重定向,关闭当前面,不能跳转到tabbar里面包含的页面
wx.reLaunch 关闭所有页面,打开到应用内的某个页面
- 微信如果实现下拉刷新
1.在页面json或者app.json当中配置 enablePullDownRefresh:true
然后在需要监听刷新的页面的js当中,会自动触发函数onPullDownRefresh
2.可以通过微信API-- wx.startPullDownRefresh和wx.stopPullDownRefresh来实现
开启和关闭刷新
- 如何让页面滚动到指定位置
wx.pageScrollTop
- 微信怎么进行数据请求,下载和上传
数据请求:wx.request
上传:wx.uploadFile
下载:wx.downloadFile
- 微信小程序怎么在页面中共享数据
- 将数据存放在app.js当中的globalData中
- 使用wx.setStorage存储在本地
- 微信小程序如何获取自己的地理位置信息
wx.getLocation 可以获取当前的地理位置、速度等信息
- 微信小程序的生命周期函数有哪些
- onLoad() 页面加载的时候触发,只调用一次
- onShow() 页面显示/回到前台的时候调用 多次调用
- onReady() 页面初次渲染完毕的时候调用,只调用一次
- onHide() 页面隐藏/进入后台的时候调用
- onUnload() 页面卸载的时候触发
- 微信小程序怎么阻止事件冒泡
可以使用catchTap来替换bindTap
bind事件绑定不会阻止冒泡事件,catch事件绑定可以组件阻止冒泡事件
- 说说你对rpx的理解
不管屏幕实际像素是多少,将当前屏幕分成750rpx
- 微信小程序有哪些优势和劣势
优势:
- 容易上手,有丰富的组件和强大的API
- 用户基础广泛
- 无需下载
- 开发成本比app低
劣势:
- 限制较多,单个页面大小不能超过1M,不能打开超过5个层级的页面
- 组件样式单一,如果组件不能满足需求,需要自定义组件
- 依托于微信,无法打包单独的安装包
- 微信小程序和H5的区别是什么
- 运行环境不同,微信小程序在微信中运行,h5在浏览器
- 开发成本不同,h5需要进行各个浏览器的兼容
- 小程序获取手机系统权限非常简单,h5较为复杂,需要依赖于其它的东西,比如uniApp或者插件
- 事件绑定、传值、数据请求方式等都不一样
git
- 平时是怎么进行团队合作的
- 首先会确定好需求,UI设计师根据需求设计效果图,效果图客户通过后,UI设计师会给前端一份标注图和切图,同时前后端根据需求开发页面和进行服务器开发
- 服务器接口是后端给的,会给一份开发者文档,里面有各个需求请求接口地址、请求类型、参数和返回值等信息
- 前端组各个成员会使用git进行代码提交,每天上班时会将最新的代码pull一下,下班前会将代码push上去
- 如何解决代码冲突问题
- 首先将自己的代码提交到本地仓库
- 然后将最新的代码从云仓库拉下来
- 进行代码合并,如果合并过程当中冲突,手动解决冲突(删除多余的代码或者合并两份代码)
- 解决完冲突以后,重新提交到本地,最后上传到云仓库就行了
- 平时使用git版本工具有哪些
习惯使用命令行提交
工具使用过sourceTree , 以及git自带的提交工具
- git和SVN有什么区别
- 平时只用了git
- git是分布式的,svn是集中式的
- git仓库可以克隆在本地,svn只可以存储在云上
- git支持离线提交,svn只能在线提交
- git常用的命令有哪些
- git status 查看代码状态
- git add . 保存代码到暂存区
- git commit -m 保存代码到持久区
- git pull 将云仓库的代码拉下来
- git push 上传代码到云上
- git clone 将云仓库代码克隆到本地
- git merge XX 合并分支,合并分支的时候只允许在主枝合并
react
- React和Vue的区别是什么
(1)vue使用的是template模版编写。react使用的是jsx语法。
(2)状态管理:react中的状态全部存入state中,通常修改的时候需要用到setState方法来更新状态。 vue中的state对象不是必须,vue是通过data属性在vue对象中进行管理
(3)监听数据的变化,vue劫持一些函数,能精确的知道数据变化。react中默认是通过比较引用的方式去进行,如果不优化使用shouldComponentUpdate/PureComponent方法优化,那会导致大量的虚拟dom重新渲染
(4)数据流不同:vue可以进行组件与dom之间v-modle双向绑定。react从始至终都只有单向数据流
(5)vue中使用的是mixins。react使用的是Hoc高阶组件
- jsx语法有什么特点
单标签一定要闭合
定义标签时,最外层只允许有一个标签
Img标签必须添加alt属性
标签都是小写字母,组件都是首字母大写
Class需要写成className
For需要写成htmlfor
使用{}可以做条件判断,但是不能有复杂的逻辑,只能写表达式
- 函数式组件和类组件的区别
函数组件的性能比类组件的性能要高,
因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。
为了提高性能,尽量使用函数组件。
函数组件没有this,没有生命周期,没有状态state,
类组件有this,有生命周期,有状态state。
- 什么是虚拟DOM
一个能代表DOM树的对象,通常含有标签名、标签上的属性、事件监听和子元素们,以及其他属性
- 什么是diff算法
. 把树形结构按照层级分解,只比较同级元素。给列表结构的每个单元添加唯一的key属性,方便比较。
2. React 只会匹配相同类名的 component合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.
3. 在每一个事件循环结束时, React 检查所有标记 dirty 的 component 重新绘制.选择性子树渲染。
4. 开发人员可以重写shouldComponentUpdate提高diff的性能。
- 在调用setState以后程序内部发生了什么
1. React 会将传入的参数对象与组件当前的状态合并产生了新的state
2. 生成新的虚拟DOM树 ==> render()
3. 计算出新树与老树的节点差异,然后做真实DOM的差异更新
- react当中的声明周期生命怎样的
16.3以前的生命周期
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
16.3以后
去掉了包含will的生命周期(除了willUnmount)
新增了
static getDerivedStateFromProps
getSnapshotBeforeUpdate
- 说说你的Hooks的理解
- 说说你对Redux的理解
React当中的数据管理,用来统一管理React中的数据。包含以下几个概念
state:包含所有的数据
action:包含一个type属性,用来修改state里面的属性
action creator:用来创建不同的action,对数据进行不同的操作
- 什么是HOC
HOC(higher order component)高阶组件,接受一个组件作为参数,并且返回一个组件的组件,称之为高阶组件
- 什么是Context
Context上下文,本身提供了一个Provider对象和Consumer对象,可以使数据进行隔代传递,淡化了组件的父子关系
- 什么是Composition
复合组件,有点类似Vue组件当中的插槽,可以用来获取组件之间的内容
vue2与vue3的区别
1. vue2和vue3双向数据绑定原理发生了改变
vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。
vue3 中使用了 es6 的 ProxyAPI 对数据代理。
相比于vue2.x,使用proxy的优势如下
- defineProperty只能监听某个属性,不能对全对象监听
- 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
- 可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化
2. Vue3支持碎片(Fragments)
就是说在组件可以拥有多个根节点
3. Composition API
Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
旧的选项型API在代码里分割了不同的属性: data,computed属性,methods,等等。新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁。
- 生命周期钩子 — Lifecyle Hooks
- Vue2--------------vue3
- beforeCreate -> setup()
- created -> setup()
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeDestroy -> onBeforeUnmount
- destroyed -> onUnmounted
- activated -> onActivated
- deactivated -> onDeactivated
setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
- onBeforeMount() : 组件挂载到节点上之前执行的函数。
- onMounted() : 组件挂载完成后执行的函数。
- onBeforeUpdate(): 组件更新之前执行的函数。
- onUpdated(): 组件更新完成之后执行的函数。
- onBeforeUnmount(): 组件卸载之前执行的函数。
- onUnmounted(): 组件卸载完成后执行的函数
- 若组件被<keep-alive>包含,则多出下面两个钩子函数。
- onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
- onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。
本文详述了前端开发中的重要概念,包括JavaScript的let const var区别、地图和forEach的运用、Vue生命周期、Webpack配置、微信小程序开发、Git操作、CSS3新特性以及BFC等。还探讨了Vue2与Vue3的差异,如双向数据绑定原理的改变和对Fragments的支持。此外,文章介绍了H5新特性、JavaScript函数、事件流、Promise与异步编程、以及React和Vue的区别。文章总结了前端开发中的多种知识点,包括模块化、数据管理、组件通信以及版本控制策略。

554

被折叠的 条评论
为什么被折叠?



