基础知识点(一)原始类型原始类型有哪些?null是一个对象吗?在JS中,原始值有6种,分别是:numberbooleanstringnullundefinedsymbol首先,原始类型存储值,没有可以调用的函数,比如undefined.toString()。虽然typeofnull会输出object,但这只是JS长期存在的bug。在最初的JS版本中,使用的是32位系统。出于性能考虑,使用了低位存储变量的类型消息。000开头代表一个对象,而null代表全为0,所以被误判为一个对象。虽然现在内部的类型判断代码已经改了,但是针对这个bug已经流传下来了。Vue框架MVVM什么是MVVM?与MVC相比有什么区别?首先申明,不管是React还是Vue,都不是MVVM框架,只能借鉴MVVM的思想。接下来说说View和Model:View很简单,就是用户看到的模型也很简单,一般就是本地数据和数据库中的数据。基本上我们写的产品都是通过接口从数据库中读取数据。然后数据被处理并显示在用户看到的视图上。当然,我们也可以从视图中读取用户的输入,然后通过接口将用户的输入写入数据库。但是,如何在视图上显示数据,然后如何将用户的输入写入数据,不同的视图有不同的视图,此后出现了很多架构设计。传统的MVC架构通常使用控制器更新模板,视图从模型中获取数据进行渲染。当用户有输入时,模板会通过控制器更新,并通知视图更新。但是MVC的一个巨大缺陷是控制器承担了太多的责任。随着项目越来越复杂,controller中的代码会越来越臃肿,造成不利于维护的情况。在MVVM架构中,引入了ViewModel的概念。ViewModel只关心数据的业务处理,不关心View如何处理数据。这样的话,View和model就可以独立了。任何一方发生变化,不一定需要改变另一方,将一些可复用的逻辑放在ViewModel中,让多个View复用这个ViewModel。以Vue框架为例,ViewModel是组件的一个实例。View是模板,引入Vuex后Model可以和组件完全分离。除了以上三部分,MVVM中其实还引入了一个隐式的Binder层来实现View和ViewModel的绑定。同样以Vue框架为例,这个隐含的Binder层是Vue通过解析模板中的插值和指令来绑定View和ViewModel。对于MVVM来说,最重要的不是通过双向绑定或者其他方式来绑定View和VieModel,而是通过ViewModel将视图中的状态和用户的行为分离成一个抽象,这就是MVVM的精髓所在。虚拟DOM什么是虚拟DOM?为什么虚拟DOM比原生DOM快?为什么操作DOM性能不佳?因为DOM是渲染引擎里面的东西,而JS是JS引擎里面的东西。当我们通过JS操作DOM时,实际上这个操作涉及到两个线程之间的通信,因此必然会带来一些性能损失。多操作DOM就相当于在线程之前进行通信,并且操作DOM还可能会引起重绘和回流,从而导致性能问题。首先,DOM是一个多叉树结构。如果需要完全比较两棵树之间的差异,所需时间复杂度为O(n^3)。这种复杂度肯定是无法接受的,所以React团队优化了算法,实现了O(n)的复杂度来比较差异。实现O(n)复杂度的关键是只比较同一层的节点,而不是跨层比较。这也是考虑到跨层移动DOM元素在实际业务中很少使用。因此,判断差异的算法分为两步:首先,从上到下,从左到右遍历对象,这就是树的深度遍历。在这一步中,为每个节点添加了一个索引,方便最终渲染差异。一旦节点有了子元素,就要判断子元素是否不同。在算法的第一步,我们需要判断新旧节点的tagNames是否相同。如果不是,则表示节点已被替换。如果tagName没有改变,则需要判断是否有子元素,如果有则进行算法的第二步。在算法的第二步,我们需要判断一个节点是否已经从原来的链表中移除,新的链表中是否加入了新的节点,节点是否移动了。当然,VirtualDOM的性能提升也是优势之一。其实最大的优势在于:1、使用VirtualDOM作为兼容层,可以让我们对接非Web端的系统,实现跨端开发。2、同样的,我们可以通过VirtualDOM渲染到其他平台,比如实现SSR,同构渲染等等。3、实现组件的高度抽象。路由原理前端路由原理?这两种实现有什么区别?前端路由实现起来其实很简单。本质就是监听URL的变化,然后匹配路由规则,在不刷新页面的情况下显示相应的页面。目前前端使用的路由只有两种实现方式。HashmodeHistorymodeHashmodewww.test.com/#/为HashURL。当#后面的hash值发生变化时,可以通过hashchangetime监听到url的变化,从而跳转到页面,无论hash值如何变化,服务器收到的url请求永远是www。测试网。window.addEventListener('hashchange',()=>{//...具体逻辑})Hash方式相对简单,兼容性更好。History模式History模式是HTML5引入的新特性,主要使用history.pushState和history.replaceState来改变URL。通过History模式更改URL也不会导致页面刷新,而只是更新浏览器的历史记录。//添加历史history.pushState(stateObject,title,URL)//替换当前历史history.replaceState(stateObject,title,URL)当用户做出浏览器动作,比如点击后退按钮时,popState事件会被triggeredwindow.addEventListener('popstate',e=>{//e.state是pushState(stateObject)中的stateObjectconsole.log(e.state)})与Hash模式相比,这两种模式只能改变后面的内容#、History模式可以通过API设置任意同源URLHistory模式可以通过API向历史记录中添加任意类型的数据,Hash模式只能改变hash值,即字符串Hash模式不无需后台配置,兼容性好。history模式会在用户手动输入地址或刷新页面时发起URL请求,后台需要配置index.html页面,以备无法匹配到静态资源时使用。beforeCreate钩子函数调用vue基础知识点生命周期钩子函数时,无法获取到props或data中的数据,因为这些数据的初始化都在initState中。然后执行创建的钩子函数。到这一步,之前访问不到的数据已经访问到了,但是此时组件还没有挂载,所以看不到。接下来会先执行beforeMount钩子函数,创建VDOM,最后执行mounted钩子,将VDOM渲染成真实的DOM,渲染数据。如果组件中有子组件,则递归挂载子组件。只有当所有子组件都挂载后,才会执行根组件的挂载钩子。接下来是挂钩函数beforeUpdate和updated,当数据更新时会调用。这两个钩子函数会分别在数据更新前后调用。另外还有一个独特的keep-alive生命周期,分别激活和去激活。用keep-alive包裹的组件在切换时不会被销毁,而是缓存在内存中并执行去激活的钩子函数,激活的钩子函数会在命中缓存渲染后执行。最后,还有销毁组件的beforeDestroy和destroyed钩子函数。前者适用于去除事件、定时器等,否则可能会造成内存泄漏。然后进行一系列的销毁操作。如果有子组件,则递归销毁子组件。根组件的destroyed钩子函数只有在所有子组件都销毁后才会执行。组件通信组件通信一般分为以下几种情况:父子组件通信兄弟组件通信跨级组件通信任意组件父子通信父组件通过props向子组件传递数据,子组件通过props向父组件传递数据发出事件。这两种方式是目前最常用的实现亲子通信的方式。这种父子通信方式也是典型的单项数据流。父组件通过props传递数据,子组件不能直接修改props,必须通过发送事件通知父组件修改数据。另外,这两个方法也可以直接使用语法糖v-model来实现,因为v-model默认会解析成一个名为value的prop和一个名为input的事件。这种语法糖方式是典型的双向绑定,经常用在UI控件上,归根结底是让父组件通过事件方式修改数据。当然,我们也可以通过访问$parent或$children对象来访问组件实例中的方法和数据。另外,如果你使用Vue2.3及以上版本,还可以使用$listeners和.sync这两个属性。$listeners属性会将父组件中的v-on事件监听器(不带.native修饰符)传递给子组件,子组件可以通过访问$listeners自定义监听器。.sync属性是一个语法糖,可以轻松实现子组件与父组件的通信。
