面试知识点突击

摘录各大语录,合集,非原创,链接较多后续添加。

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 对象。

  1. 通过 baseCompile 方法进行编译;
  2. 通过 createCompilerCreator 中的 compile 方法合并配置参数并返回 baseCompile 方法执行结果;
  3. createCompilerCreator 返回 compile 方法和 compileToFunctions 方法;
  4. compileToFunctions 方法用于将方法字符串生成真实方法。

baseCompile:

  1. parse 将HTML解析为 AST 元素。
  2. optimize该方法只是做了些标记静态节点的行为,目的是为了在重新渲染时不重复渲染静态节点,以达到性能优化的目的。
  3. 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));
}

复制代码

优化

  1. 减少http请求(雪碧)
  2. 将样式表放在头部
  3. 将脚本放在底部
  4. 针对第三方库文件使用cdn方式
  5. 慎用deep watch
  6. v-if v-show
  7. keep-alive

打包库忽略externals

一、加载渲染过程

父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

二、子组件更新过程

父beforeUpdate->子beforeUpdate->子updated->父updated

三、父组件更新过程

父beforeUpdate->父updated

四、销毁过程

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

转载于:https://juejin.im/post/5bd2fffce51d457aa25be5b9

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值