摘录各大语录,合集,非原创,链接较多后续添加。
js 题库
原型链
原理
-
原型prototype:对象,函数都有。
-
原型指针_proto_:属性,对象都有。
-
对象的_proto_指向构造函数的原型
obj._proto_ = Object.prototype
复制代码
- A.prototype.constructer = A
new过程
var a = new B()
等同于
var a ={}
a._prototype_= B.prototype
B.call(a)
复制代码
类型
- number,boolean,null,undefined,string,object(es6 symbol)
- typeof =>输出类型:object,string,number,boolean,function,undefined
- instanceof =>输出true or false 。
- a instanceof b // a对象的原型链上是否存在b.prototype.constructor,一个对象在其原型链中是否存在一个构造函数的 prototype 属性
var arr = []
arr instanceof Array //true
typeof arr //object
null instanceof Object //false
typeof null //object
undefined instanceof Object //false
typeof undefined //undefined
function a (){}
a instanceof Object // true
typeof a //function
typeof NaN //number
复制代码
继承
原型
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
复制代码
原型链继承
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
复制代码
特点:
非常纯粹的继承关系,实例是子类的实例,也是父类的实例 父类新增原型方法/原型属性,子类都能访问到 简单,易于实现
缺点:
如果要新增原型属性和方法,则必须放在new Animal()这样的语句之后执行;
无法实现多继承,来自原型对象的所有属性被所有实例共享;
创建子类实例时,无法向父类构造函数传参
构造继承
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
复制代码
特点:
子类实例共享父类引用属性的问题 创建子类实例时,可以向父类传递参数 可以实现多继承(call多个父类对象)
缺点:
实例并不是父类的实例,只是子类的实例 只能继承父类的实例属性和方法,不能继承原型属性/方法 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
组合继承
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
复制代码
特点:
可以继承实例属性/方法,也可以继承原型属性/方法 既是子类的实例,也是父类的实例 不存在引用属性共享问题 可传参 函数可复用
缺点:
调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
寄生组合继承
function Cat(name){
Animal.call(this);
this.name = name||'Tom';
}
(function(){
// 创建一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();
})();
Cat.prototype.constructor = Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
复制代码
方法
- push():向数组尾部添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
- pop(): 删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组。
- unshift():在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
- shift():删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组。
- valueOf():返回数组的本身。
- indexOf():返回指定元素在数组中出现的位置,如果没有出现则返回-1。接受第二个参数,表示搜索的开始位置
- str.indexOf(searchString,startIndex); 返回子字符串第一次出现的位置,从startIndex开始查找,找不到时返回-1
- toString():返回数组的字符串形式
- join():以参数作为分隔符,将所有数组成员组成一个字符串返回。如果不提供参数,默认用逗号分隔。
- concat():用于多个数组的合并。它将新数组的成员,添加到原数组的尾部,然后返回一个新数组,原数组不变。
- reverse():用于颠倒数组中元素的顺序,返回改变后的数组。注意, 该方法将改变原数组。
- slice():用于截取原数组的一部分,返回一个新数组,原数组不变。 slice(start,end)它的第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。
- str.slice(start,end); 返回值:[start,end)
- splice():删除原数组的一部分成员,并可以在被删除的位置添加入新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组。 splice(start,delNum,addElement1,addElement2,...)第一个参数是删除的起始位置,第二个参数是被删除的元素个数。如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。
- sort():对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变
- map():对数组的所有成员依次调用一个函数,根据函数结果返回一个新数组。
- filter():参数是一个函数,所有数组成员依次执行该函数,返回结果为true的成员组成一个新数组返回。该方法不会改变原数组。
- str.charAt(index); 返回子字符串,index为字符串下标,index取值范围[0,str.length-1]
- str.split(separator,limit); 参数1指定字符串或正则,参照2指定数组的最大长度
promise原理
Promise 对象用于延迟(deferred) 计算和异步(asynchronous )计算.一个Promise对象代表着一个还未完成,但预期将来会完成的操作。Promise 对象是一个返回值的代理,这个返回值在promise对象创建时未必已知。它允许你为异步操作的成功或失败指定处理方法。 这使得异步方法可以像同步方法那样返回值:异步方法会返回一个包含了原返回值的 promise 对象来替代原返回值。
axios
- 从浏览器生成XMLHttpRequests
- 从node.js发出http请求
- 支持Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防范XSRF
安全
谈谈对前端安全的理解,有什么,怎么防范前端安全问题主要有XSS、CSRF攻击 XSS:跨站脚本攻击 它允许用户将恶意代码植入到提供给其他用户使用的页面中,可以简单的理解为一种javascript代码注入。
XSS的防御措施: 过滤转义输入输出 避免使用eval、new Function等执行字符串的方法,除非确定字符串和用户输入无关 使用cookie的httpOnly属性,加上了这个属性的cookie字段,js是无法进行读写的 使用innerHTML、document.write的时候,如果数据是用户输入的,那么需要对象关键字符进行过滤与转义
CSRF:跨站请求伪造 其实就是网站中的一些提交行为,被黑客利用,在你访问黑客的网站的时候进行操作,会被操作到其他网站上
CSRF防御措施: 检测http referer是否是同域名 避免登录的session长时间存储在客户端中 关键请求使用验证码或者token机制 其他的一些攻击方法还有HTTP劫持、界面操作劫持
webscoket
垃圾回收
vue
vuex
在main.js引入store,注入,新建一个目录store,….. export 等,常用的场景有:单页应用中,组件之间的状态,音乐播放、登录状态、加入购物车等等。
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态。这里的关键在于集中式存储管理
-
学院派:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式;集中存储和管理应用的所有组件状态。
-
理解:以上这4个词是我们理解的关键。状态:什么是状态,我们可以通俗的理解为数据。Vue只关心视图层,那么视图的状态如何来确定?我们知道是通过数据驱动,这里的状态管理可以简单理解为管理数据。集中存储:Vue只关心视图,那么我们需要一个仓库(Store)来存储数据,而且是所有的数据集中存储,视图和数据就可以分析。管理:除了存储,还可以管理数据,也就是计算、处理数据。所有组件状态:所用的组件共用一个仓库(Store),也就是一个项目只有一个数据源(区分模块modules)。
-
总结:Vuex就是在一个项目中,提供唯一的管理数据源的仓库。
-
场景一:处理多组件依赖于同一个数据,例如有柱状图和条形图两个组件都是展示的同一数据;
-
场景二: 一个组件的行为——改变数据——影响另一个组件的视图,其实也就是公用依赖的数据;
-
Vuex将组件公用数据抽离,在一个公共仓库管理,使得各个组件容易获取(getter)数据,也容易设置数据(setter)
生命周期
vue生命周期总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreated阶段,vue实例的挂载元素el还没有。
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。
双向数据绑定原理
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。 具体步骤:
第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter。这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
template编译
简而言之,就是先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点) 详情步骤:
首先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创建编译器的。另外compile还负责合并option。
然后,AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等)
1.获取el元素。
2.判断el是否为body或者html。
3.为$options编译render函数。
4.执行之前的mount函数。
关键在于第三步,编译 render 函数上。先获取 template,即获取HTML内容,然后执行 compileToFunctions 来编译,最后将 render 和 staticRenderFns 传给 vm.$options 对象。
- 通过 baseCompile 方法进行编译;
- 通过 createCompilerCreator 中的 compile 方法合并配置参数并返回 baseCompile 方法执行结果;
- createCompilerCreator 返回 compile 方法和 compileToFunctions 方法;
- compileToFunctions 方法用于将方法字符串生成真实方法。
baseCompile:
- parse 将HTML解析为 AST 元素。
- optimize该方法只是做了些标记静态节点的行为,目的是为了在重新渲染时不重复渲染静态节点,以达到性能优化的目的。
- generate 解析成基本的 render 函数
vue-router
单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面。
1、Hash模式: hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中也不会不包括#;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;
2、History模式: HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;
- Vue-Router的两种模式主要依赖什么实现的
hash主要依赖location.hash来改动 URL,达到不刷新跳转的效果.每次 hash 改变都会触发hashchange事件(来响应路由的变化,比如页面的更换) history主要利用了 HTML5的 historyAPI 来实现,用pushState和replaceState来操作浏览历史记录栈
-
钩子函数
-
全局的钩子
beforeEach(to,from,next)
afterEach(to,from,next)
-
单个路由里面的钩子
beforeEnter(to,from,next)
beforeLeave (to, from, next)
-
组件内的钩子
beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
vue和react
-
-
相同点:都支持 ssr,都有 vdom,组件化开发,实现 webComponents 规范,数据驱动等
-
不同点:vue 是双向数据流(当然为了实现单数据流方便管理组件状态,vuex 便出现了),react 是单向数据流。vue 的 vdom 是追踪每个组件的依赖关系,不会渲染整个组件树,react 每当应该状态被改变时,全部子组件都会 re-render。
VDOM 的必要性?
- 创建真实DOM的代价高:真实的 DOM 节点 node 实现的属性很多,而 vnode 仅仅实现一些必要的属性,相比起来,创建一个 vnode 的成本比较低。 触发多次浏览器重绘及回流:使用 vnode ,相当于加了一个缓冲,让一次数据变动所带来的所有 node 变化,先在 vnode 中进行修改,然后 diff 之后对所有产生差异的节点集中一次对 DOM tree 进行修改,以减少浏览器的重绘及回流。
vue 为什么采用 vdom?
-
性能受场景的影响是非常大的,不同的场景可能造成不同实现方案之间成倍的性能差距,所以依赖细粒度绑定及 Virtual DOM 哪个的性能更好还真不是一个容易下定论的问题。 Vue 之所以引入了 Virtual DOM,更重要的原因是为了解耦 HTML 依赖,这带来两个非常重要的好处是:
-
不再依赖 HTML 解析器进行模版解析,可以进行更多的 AOT 工作提高运行时效率:通过模版 AOT 编译,Vue 的运行时体积可以进一步压缩,运行时效率可以进一步提升; 可以渲染到 DOM 以外的平台,实现 SSR、同构渲染这些高级特性,Weex 等框架应用的就是这一特性。
-
综上,Virtual DOM 在性能上的收益并不是最主要的,更重要的是它使得 Vue 具备了现代框架应有的高级特性。
vue SSR ...
axios
css
未知宽高的元素实现水平垂直居中
.parent{
width:100%;
height:400px;
position:relative;
}
.children{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}
复制代码
.parent{
width:100%;
height:400px;
display:flex;
align-items:center;
justify-content:center;
}
.children{
background:red;
}
复制代码
.parent{
display:table;
width:100%;
height:400px;
}
.children{
display:table-cell;
vertical-align:middle;
text-align:center;
}
复制代码
深复制
var json1 = {
name: 'aaa',
age: 25,
data: {
a: 1,
b: 2
}
};
function deepCopy(parent, child) {
var child = child || {};// 并不是直接声明一个新child为空{},传过来的就用传过来的
for(var i in parent) {
if(typeof parent[i] === 'object') {
child[i] = (parent[i].constructor === Array) ? [] : {};// child.data = {};
deepCopy(parent[i], child[i]);// {a: 1,b: 2},传过去的是child.data的空json
}
else {
child[i] = parent[i];// child.data.a ...
}
}
return child;
}
var json2 = deepCopy(json1);
json2.data.a = 3;
console.log(json1.data.a);// json1.data.a不受影响,仍旧是1
console.log(json2.data.a);
复制代码
算法
都是从小到大
//冒泡
function a (arr){
for(var i;arr<length;i++){
for(var j;arr<=length-1;i++){
if(arr[j]>arr[j+1]){
var b ;
b = arr[j];
arr[j] = arr[j+1];
arr[j+1] = b;
}
}
}
return arr;
}
复制代码
function b (arr){
if(arr.length<=1){return arr;}
var left =[];
var right = [];
var a = Math.floor(arr.length/2);
var indexs = arr.splice(a,1)[0];
for(var i=0;i<length;i++){
if(indexs > arr[i]){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return b(left).concat([indexs],b(right));
}
复制代码
优化
- 减少http请求(雪碧)
- 将样式表放在头部
- 将脚本放在底部
- 针对第三方库文件使用cdn方式
- 慎用deep watch
- v-if v-show
- keep-alive
打包库忽略externals
一、加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
二、子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
三、父组件更新过程
父beforeUpdate->父updated
四、销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed