openks / learn-vue

自定义组件文档
https://openks.github.io/learn-vue
0 stars 0 forks source link

20180704_前端基础知识 #113

Open openks opened 6 years ago

openks commented 6 years ago

vue.nextTick如何实现的

2.4后版本实现方案 使用优雅降级方案处理, 分macrotask和microtask, 对于macrotask来说 技术上将最好的是使用setImmediate但只有IE支持 然后是使用messsageChannel,在同一循环中使用的所有dom事件触发后的回调是使用messsageChannel 最后是使用setTimeout 对于microtask来说是使用promise,如果原生promise不支持则改用macrotask处理

vue virtual dom diff 算法

虚拟DOm核心思想:对复杂的文档DOM结构,提供一种方便的工具,进行最小化的DOM操作

为甚么要用虚拟dom因为真实dom复杂属性方法较多而虚拟dom会把dom树抽象成数据对象 virtual dom 它可以使我们操作这块的数据对象,用数据对象来呈现dom树 var element = document.createElement('h1'); var len=0 for (var property1 in element) { len++ console.log(property1) } console.log(len) //共206个属性与方法 你的知道浏览器的虚拟DOM与真实DOM的区别(注意:需不需要虚拟DOM,其实与框架的DOM操作机制有关):

  1. 虚拟DOM不会进行排版与重绘操作
  2. 虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分(注意!), 最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
  3. 真实DOM频繁排版与重绘的效率是相当低的
  4. 虚拟DOM有效降低大面积(真实DOM节点)的重绘与排版,因为最终与真实DOM比较差异,可以只渲染局部(同2) 使用虚拟DOM的损耗计算: 总损耗 = 虚拟DOM增删改 + (与Diff算法效率有关)真实DOM差异增删改 + (较少的节点)排版与重绘 直接使用真实DOM的损耗计算: 总损耗 = 真实DOM完全增删改 + (可能较多的节点)排版与重绘 总之,一切为了减弱频繁的大面积重绘引发的性能问题,不同框架不一定需要虚拟DOM,关键看框架是否频繁会引发大面积的DOM操作

    vue与react区别

    如何对一个div实现3个边框

    border ouline box-shadow

    vue的双向绑定是如何实现的

    object.keysfor in 区别

    object.keys返回对象自己的可枚举属性

    The object of which the enumerable own properties are to be returned.

for in返回对象自己及原型链上的可枚举属性

A for...in loop only iterates over enumerable properties. The loop will iterate over all enumerable properties of the object itself and those the object inherits from its constructor's prototype

闭包及其实现和优缺点,是否会造成内存泄露,如果是如何解决内存泄露问题

浏览器的事件循环和node的事件循环区别

浏览器的事件循环有两种一种是browsing contexts另外一种是workers这里只说browsing contexts

  1. 一个浏览器事件循环会有一个或多个事件队列
  2. 每一个 event loop 都有一个 microtask queue
  3. task(也叫macrotask),task queue
  4. microtask,microtask queue 判断相关代码是task还是micrtask,根据结果来判断是加入task queue还是加入microtask queue
    每一个task执行完后都会执行该task相关的micotask,执行完后继续执行task queue里的下一个task
    每个task和micotask调用时都会被压入js调用栈,等调用栈里代码全部执行完毕后执行下一个micotask 所有micotask执行完后执行下一个task
    包裹在一个 script 标签中的js代码也是一个 task

关于事件循环,我们需要记住以下几点: 事件队列严格按照时间先后顺序将任务压入执行栈执行; 当执行栈为空时,浏览器会一直不停的检查事件队列,如果不为空,则取出第一个任务; 在每一个任务结束之后,浏览器会对页面进行渲染;

最简单的理解就是一个宏任务,所有微任务,一个宏任务,所有微任务......

task:script中代码、setTimeout、setInterval、I/O、UI render。 microtask: promise、Object.observe、MutationObserver。

参考一:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ 参考二:https://segmentfault.com/a/1190000013660033?utm_source=channel-hottest

箭头函数与function函数区别

  1. this指向
  2. 变量提升
  3. 构造函数

    箭头函数能当构造函数使用么?为什么

    不能

    那些函数不能当构造函数

    css如何画三角形及箭头

    三角形:用边框画 箭头:两个div的半个边框旋转即可

react生命周期

见图: https://blog.csdn.net/njafei/article/details/76216337

纯组件与非纯组件区别

无状态函数组件

  1. 组件不会被实例化,整体渲染性能得到提升
  2. 组件不能访问this对象
  3. 组件无法访问生命周期的方法
  4. 只能访问输入的props,同样的props会得到同样的渲染结果,不会有副作用

React.pureComponent和React.component的区别

  1. React.PureComponent 的 shouldComponentUpdate() 只会对prop和state对象进行浅对比。 如果对象包含复杂的数据结构,它可能会因深层的数据不一致而产生错误的否定判断
  2. React.PureComponent 的 shouldComponentUpate() 会忽略整个组件的子级

react定义组件的方式及他们之间的区别

  1. 函数式定义的无状态组件
  2. es5原生方式React.createClass定义的组件
  3. es6形式的extends React.Component定义的组件

React.createClass是react刚开始推荐的创建组件的方式,这是ES5的原生的JavaScript来实现的React组件

  1. 函数this自绑定,导致不必要的性能开销 React.createClass会自绑定函数方法,导致不必要的性能开销,增加代码过时的可能性。 React.createClass的mixins不够自然、直观;
  2. 在创建组件时,有关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是使用getDefaultProps的方法来获取默认组件属性的
  3. 其状态state是通过getInitialState方法来配置组件相关的状态
  4. 在创建组件时可以使用mixins属性,以数组的形式来混合类的集合

React.Component是以ES6的形式来创建react的组件的,是React目前极为推荐的创建有状态组件的方式,最终会取代React.createClass形式;相对于 React.createClass可以更好实现代码复用 React.Component形式非常适合高阶组件(Higher Order Components--HOC),它以更直观的形式展示了比mixins更强大的功能,并且HOC是纯净的JavaScript,不用担心他们会被废弃

  1. this需要手动绑定,否则this不能获取当前组件实例对象

    React.Component有三种手动绑定方法: 可以在构造函数中完成绑定, 也可以在调用时使用method.bind(this)来完成绑定, 还可以使用arrow function来绑定。

constructor(props) {
   super(props);
   this.handleClick = this.handleClick.bind(this); //构造函数中绑定 无法解决传递参数问题
}
<div onClick={this.handleClick.bind(this,id)}></div> //使用bind来绑定 并传递参数id
<div onClick={(e)=>this.handleClick(id,e)}></div> //使用arrow function来绑定 并传递参数id
  1. 组件props的属性类型及组件默认的属性是作为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。
  2. 状态state是在constructor中像初始化组件属性一样声明的
  3. 不支持mixin但是提供HOC来替代mixin

详见https://www.cnblogs.com/wonyun/p/5930333.html

HOC与mixin区别

不同用户写的mixin可能会造成命名冲突 命名冲突的mixin可能已经被组件或者其他mixin引用,如果修改则要修改所有被调用的地方 自定义mixin名称可能与第三方包的mixin名称冲突,自定义mixin就需要改变成不那么准确的名字来避免冲突 新增方法名也存在破坏性的风险,新增的方法名可能已经在组件中被直接使用或者在其他mixin中被间接引用 mixin一旦确定就不容易被删除或者修改(由于引用的数量不确定性,修改或删除存在风险) 即便某个mixin写的不是很合适一般也不会有人会去重构,因为重构面临的风险较大

mixin导致滚雪球式的复杂性 mixin用起来简单,但随着时间的推移它们会趋于复杂

react为什么要手动绑定this

因为在class中声明函数,并不会自动绑定this对象 1.如果你不绑定this.handleClick方法,那么在事件发生并且调用这个方法时,方法内部的this会丢失指向undefined。 2.这不是React的原因,这是JavaScript中本来就有的。如果你传递一个函数名给一个变量,然后通过在变量后加括号()来调用这个方法,此时方法内部的this的指向就会丢失 在React(或者说JSX)中,传递的事件参数不是一个字符串,而是一个实实在在的函数,如果你传递一个函数名给一个变量,然后通过在变量后加括号()来调用这个方法,此时方法内部的this的指向就会丢失

let obj = {
    tmp:'Yes!',
    testLog:function(){
        console.log(this.tmp);
    }
};
obj.testLog();
let tmpLog = obj.testLog;//函数名传递给变量
tmpLog();//变量后加括号

react触发渲染方式和区别

如何监听数据源的变化

使用es5的Object.defineProperty

var m={}
var zhihu=0
Object.defineProperty(m,'zhiho',{
    get(){
        console.log("get",zhihu)
        return zhihu
    },
    set(value){
        zhihu = value
        console.log('set',zhihu)
    }
})
m.zhiho // get 0 0 其中第二个0为返回值
m.zhiho = 9 //set 9 9
zhihu //9
// 可以看出这里借助了中间参数zhihu 

如何同时进行多个异步请求

基于fetch如何做超时处理

实现fetch的timeout功能,其思想就是新创建一个可以手动控制promise状态的实例,根据不同情况来对新promise实例进行resolve或者reject,从而达到实现timeout的功能;

var oldFetchfn = fetch; //拦截原始的fetch方法
window.fetch = function(input, opts){//定义新的fetch方法,封装原有的fetch方法
    return new Promise(function(resolve, reject){
        var timeoutId = setTimeout(function(){
            reject(new Error("fetch timeout"))
        }, opts.timeout);
        oldFetchfn(input, opts).then(
            res=>{
                clearTimeout(timeoutId);
                resolve(res)
            },
            err=>{
                clearTimeout(timeoutId);
                reject(err)
            }
        )
    })
  }

利用Promise.race方法

var oldFetchfn = fetch; //拦截原始的fetch方法
window.fetch = function(input, opts){//定义新的fetch方法,封装原有的fetch方法
    var fetchPromise = oldFetchfn(input, opts);
    var timeoutPromise = new Promise(function(resolve, reject){
        setTimeout(()=>{
             reject(new Error("fetch timeout"))
        }, opts.timeout)
    });
    retrun Promise.race([fetchPromise, timeoutPromise])
}

fetch兼容性 fetch默认不携带cookie fetch请求对某些错误http状态不会reject 这主要是由fetch返回promise导致的,因为fetch返回的promise在某些错误的http状态下如400、500等不会reject,相反它会被resolve;只有网络错误会导致请求不能完成时,fetch 才会被 reject;所以一般会对fetch请求做一层封装

fetch 不支持JSONP 可以使用fetch-jsonp来解决

JSONP原理

本地定义函数并把函数名作为callback一并作为scrip标签的src属性传递到后端, 后端根据src其他查询参数及其他域上数据(这里是重点,如果不需要其他域数据本域js即可处理不需JSONP)调用callback函数 这种方式就叫JSONP

如何进行性能优化

如何加快首屏渲染速度