20220518面试题

问题一:js中如何判断是否是数组

方法一:isArray()数组自带的判断方法
let a =[1,2,3];
Array.isArray(a); //true
方法二:instanceof操作符
let a = [1,2,3];
a instanceof Array; //true
方法三:constructor.toString()方法
let a = [1,2,3]
//把constructor转换成字符串,然后通过indexOf去判断是否包含Array
a.constructor.toString().indexOf("Array") !== -1; //true

const a = [];
console.log(a.constructor);//function Array(){ [native code] }
const a = [];
console.log(a.constructor == Array);//true

方法四:Object.prototype.toString.call(a).indexOf(“Array”)
let a = [1,2,3];
//和上面一个意思,都是转换成字符串,然后判断是否包含Array,
//有就会返回下标位置
/*
  Object.prototype.toString会取对象的一个内部属性[[Class]],
  大概会返回一个类似于"[object Array]"这样的字符串,注意,
  这里这个是内部属性,外部是无法访问的,然后再配合call方法,
  改变toString的this指向,也就是指向a数组
*/

问题二:vue watch和computed和methods区别

1、watch(监听),重视过程,当监听的数据(data里面定义的数据比如num)发生改变才可以执行,watch接收两个参数一个时oldValue(旧值),newValue(新值),第一个参数为更新的数据,第二个参数为之前的旧数据,不用返回值。
监听单个变量或一个数组.
例子:watch属性可以用来做页面中的模糊查询使用.

num(newValue,oldValue){
	console.info(newValue);
}

在这里插入图片描述

2、computed (计算属性),重视结果,响应式依赖发生改变时执行并记录缓存,当响应式值不改变时后续读取数据都是用缓存的,
当响应时值改变时才会重新求值并返回,必须有return。
例子:计算可以使用computed

<script src="https://how2j.cn/study/vue.min.js"></script>
    
<style>
table tr td{
    border:1px solid gray;
    padding:10px;
     
}
table{
    border-collapse:collapse;
    width:800px;
    table-layout:fixed;
}
tr.firstLine{
    background-color: lightGray;
}
</style>
  
<div id="div1">
    
    <table align="center" >
        <tr class="firstLine">
            <td>人民币</td>
            <td>美元</td>
        </tr>       
        <tr>
        	<td align="center" colspan="2">
        	汇率: <input type="number" v-model.number="exchange" />
        	</td>
        </tr>
        
        <tr>
        
        	<td align="center">
        		¥: <input type="number" v-model.number = "rmb"  />
        	</td>
        	<td align="center">
        		$: {{ dollar }}
        	</td>
        </tr>
    </table>
  
</div>
     
<script>
   
new Vue({
      el: '#div1',
      data: {
    	  exchange:6.4,
          rmb:0
      },
      computed:{
          dollar() {
              return this.rmb / this.exchange; 
          }
      }
    })
     
</script>

监听复杂数据(深度监听 deep)

不使用 deep 时,当我们改变 obj.a 的值时,watch 不能监听到数据变化,默认情况下,handler 只监听属性引用的变化,也就是只监听了一层,但改对象内部的属性是监听不到的。

immerdiate 属性: 通过声明 immediate 选项为 true,可以立即执行一次 handler。

<template>
  <div>
    <el-input v-model="obj.text"></el-input>
  </div>
</template>

<script>
export default {
  data() {
    return {
      obj:{
        text:'hello'
      }
    };
  },
  watch:{
    // 监听对象obj的变化
    obj:{
      handler (newVal,oldval) {
        console.log(newVal,oldval)
      },
      deep: true,
      immediate: true
    }
  },
};
</script>

通过使用 deep: true 进行深入观察,我们监听 obj,会把 obj 下面的属性层层遍历,都加上监听事件,这样做性能开销也会变大,只要修改 obj 中任意属性值,都会触发 handler,那么如何优化性能呢?
可以直接对用对象 . 属性的方法拿到属性

<template>
  <div>
    <el-input v-model="obj.text"></el-input>
  </div>
</template>

<script>
export default {
  data() {
    return {
      obj:{
        text:'hello',
      }
    };
  },
  watch:{
    // 监听对象单个属性text
    'obj.text':{
      handler (newVal,oldval) {
        console.log(newVal,oldval)
      },
      immediate: true, // 该属性会先执行一次handler
    }
  },
};
</script>

3、methods.没有缓存每次都会求值,是事件绑定用的,逻辑运算,可以不用return
绑定事件专用
4、computed中的函数必须要用return返回,watch中的函数不是必须要用return
computed与watch的使用场景:
computed:是多对一,多个数据影响一个。当需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时都要重新计算。
watch:是一对多,一个数据发生变化,执行相应操作会影响多个数据。当需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许执行异步操作 ( 访问一个 API ),限制执行该操作的频率,并在得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

问题三:rpx、px、em、rem、%、vh、vw的区别是什么

rpx、px、em、rem、%、vh、vw的区别是什么?
rpx 相当于把屏幕宽度分为750份,1份就是1rpx px 绝对单位,页面按精确像素展示 em 相对单位,相对于它的父节点字体进行计算 rem 相对单位,相对根节点html的字体大小来计算 % 一般来说就是相对于父元素 vh 视窗高度,1vh等于视窗高度的1% vw 视窗宽度,1vw等于视窗宽度的1%

问题四:typeof和instanceof的区别是什么

比较typeof与instanceof

相同点:

JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空, 或者是什么类型的。

不同点:

typeof:

1、返回值是一个字符串, 用来说明变量的数据类型。

2、typeof 一般只能返回如下几个结果: number, boolean, string, function, object, undefined。

var a = [34,4,3,54],
        b = 34,
        c = 'adsfas',
        d = function(){console.log('我是函数')},
        e = true,
        f = null,
        g;
 
        console.log(typeof(a));//object
        console.log(typeof(b));//number
        console.log(typeof(c));//string
        console.log(typeof(d));//function
        console.log(typeof(e));//boolean
        console.log(typeof(f));//object

对于 Array, Null 等特殊对象使用 typeof 一律返回 object, 这正是 typeof 的局限性。

instanceof:

1、返回值为布尔值

2、instanceof 用于判断一个变量是否属于某个对象的实例。

// var a = new Array();
// alert(a instanceof Array); // true
// alert(a instanceof Object) // true
//如上, 会返回 true, 同时 alert(a instanceof Object) 也会返回 true;
// 这是因为 Array 是 object 的子类。
// alert(b instanceof Array) // b is not defined
// function Test() {};
// var a = new test();
// alert(a instanceof test) // true

问题五:vue实现移动端适配方案

回答一:页面初始化时判断当前环境是手机端还是pc端切换不同的项目版本
回答二:vue项目在index.html中加入<meta name="viewport" content="width=device-width,initial-scale=1.0">
回答三:html5中手机端适配使用document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + 'px';

问题六:js闭包

  1. 保护全局变量安全。函数a中的num只有函数b才能访问,而无法通过其他途径访问到,因此保护了全局变量的安全。
  2. 在内存中维持一个变量
  3. 所有的(闭包)自由变量的查找,是在函数定义的地方,向上级作用域查找不是在执行的地方!!!
var num = 6;
function a() {
	//上层作用域
	var num = 1;
	function b() {
		var n = 2;
		alert(n + num);
	}
	//执行的地方
	return b
}
const c= a();
c()//等于3 没有污染最外层的num
alert(num);//等于6 没有污染最外层的num

扩展:内存占用问题
因为f()被fn一直占用所以在内存中num改变后的值是被记录下来的也就导致每次调用都是+的问题

var f = function() {
    var num = 0;
    return function() {
      return num += 1;
    };
  }
  var fn = f();
fn()
// 1
fn()
// 2
fn()
// 3 最后等于3 num进行了累加
如何释放内存 fn=null 就可以了
内存回收机制
f函数已经执行完毕了,没有其他资源引用了,ta会被立即释放,也就是说,f()执行完后,fn=null,不在占用f()函数了,内存立即就释放了。
var f = function() {
    var num = 0;
    return function() {
      return num += 1;
    };
  }
  var fn = f();
console.info(fn())
// 1
fn =null
var fn = f();
console.info(fn())
// 1
fn =null
var fn = f();
console.info(fn())
// 1
fn =null

实际应用场景:

隐藏数据,做一个简单的cache工具

// 闭包隐藏数据,只提供 API
function createCache() {
    const data = {} // 闭包中的数据,被隐藏,不被外界访问
    return {
        set: function (key, val) {
            data[key] = val
        },
        get: function (key) {
            return data[key]
        }
    }
}

const c = createCache()
c.set('a', 100)
console.log( c.get('a') )

问题七:this、let和var

1、 this的指向是,由它所在函数调用的上下文决定的而不是,由它所在函数定义的上下文决定的
2、 var创建的变量会挂载在window对象上。 而let 、 const创建的变量不会挂载在window对象上

问题八:vue中 的传值问题 父传子和子传父和兄弟组件传值

1、父组件可以使用 props 把数据传给子组件。
2、子组件可以使用 e m i t 触发父组件的绑定的自定义事件。 3 、通过 b u s 需要先引入发送 b u s . emit 触发父组件的绑定的自定义事件。 3、通过bus需要先引入 发送bus. emit触发父组件的绑定的自定义事件。3、通过bus需要先引入发送bus.emit(‘a’,this.msg)
接收bus.on(‘a’,(data)=>{
console.info(data);
this.msg=data;
})

问题九:vue 响应式原理

Vue的数据双向绑定,响应式原理,其实就是通过Object.defineProperty()结合监听者订阅者模式来实现的
当data改变时set进行拦截通知watcher,在watcher中触发所有订阅者进行更新,在更新过程中会生成一颗新的虚拟dom tree在对比老的虚拟dom tree以最小的代价找出不同后更新到真实的dom中

问题十:vue v-model

v-model只不过是一个语法糖而已,真正的实现靠的还是
v-bind:绑定响应式数据
触发oninput 事件并传递数据

语法糖
<input v-model="searchText">
原理
<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value">

问题十一:小程序的双向绑定

在input中绑定value="{{username}}"再添加bindinput事件监听input发生的变化通过e.detail.value获取值用
this.setData({username:e.detail.value})实现双向绑定

wxml:

  <label>
 	 用户名:{{username}}
  </label>
            <input class="input" type="text" placeholder-class="search-placeholder" placeholder="请输入用户名" maxlength="20" value="{{username}}" bindinput="inputstr" />
   </view>
js:
inputstr(e){
    var name=e.detail.value
    this.setData({
      username:name
    })
}

问题十二:生命周期:

从Vue实例创建、运行、到销毁期间,伴随着的各种事件,这些事件统称为生命周期

生命周期函数分类:

创建期间的生命周期函数:
beforeCreate:实例刚在内存中被创建出来,此时还没有初始化好data和methods属性
created:实例已经在内存中创建出来,此时的data和methods以及创建完成,但是还没有开始编译模板
beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面上
mounted:已经将编译好的模板,挂载到了页面指定的容器中显示

运行期间的生命周期函数:
beforeUpdate:状态更新之前执行此函数,此时data中的状态值是最新的,但是界面上显示的数据还是旧的,因为此时还没有开始重新渲染DOM节点
updated:实例更新完毕之后调用此函数,此时data中的状态值和界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了

销毁期间的生命周期函数:
注意 !!!vue3,则是beforeunmount和unmount
beforeDestory:实例销毁之前调用,在这一步,实例仍然完全可用
destroyed:Vue实例销毁之后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁

问题十三:为什么现代前端框架要基于虚拟 DOM?

一、虚拟 dom 使用 diff 算法,模拟浏览器内核渲染算法,并在此基础上进行了优化;

二、虚拟 dom 只占用浏览器内存,不占用浏览器内核资源。

三、虚拟 dom 渲染时,首先与旧的 dom 结构进行比较,然后将需要渲染的节点渲染到页面,很少需要回流,大多数只进行了重绘。

四、虚拟 dom 将浏览器内核中的 dom 树结构,转化为 dom 对象结构,可以使用操作对象的方法进行同层的比较等。

五、虚拟 dom 可以解决不同浏览器内核渲染时的过程差异,减少开发成本,节省开发时间。

问题十三:Vue中key的作用

1.虚拟DOM中key的作用:

    key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,

   随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

2.对比规则:

    (1).就虚拟DOM中找到了与新虚拟DOM相同的key:

            ①.若虚拟DOM中内容没变,直接使用之前的真实DOM!

            ②.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

   (2).就虚拟DOM中未找到与新虚拟DOM相同的key创建新的真实DOM,随后渲染到页面。

3.用index作为key可能会引发的问题:

   1.若对数据进行:逆序添加、逆序删除等破坏顺序操作;

        会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低。

   2.如果结构中还包含输入类的DOM;

         会产生错误DOM更新 ==> 界面有问题。

4.开发中如何选择key?

   1.最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。

   2.如果不存在对数据的逆向添加、逆向删除等破坏顺序操作,仅用于渲染列表用于展示, 

      使用index作为key是没有问题的。

在这里插入图片描述

在这里插入图片描述

问题十四:html5中打包app调用相机的方法(还没有研究明白)

git地址
jsbridge实现前端js和java之间架起一座桥梁,服务操作完app后将内容返回给前端
JitPack.io

git内容

我强烈推荐https://jitpack.io

repositories {
    // ...
    maven { url "https://jitpack.io" }
}

dependencies {
    compile 'com.github.lzyzsd:jsbridge:1.0.4'
}

在 Java 中使用它
将 com.github.lzyzsd.jsbridge.BridgeWebView 添加到您的布局中,它是从 WebView 继承的。

注册一个Java处理函数,让js可以调用

webView.registerHandler("submitFromWeb", new BridgeHandler() {
    @Override
    public void handler(String data, CallBackFunction function) {
        Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
        function.onCallBack("submitFromWeb exe, response data from Java");
    }
});

Node.js 可以通过以下方式调用这个 Java 处理程序方法“submitFromWeb”:

WebViewJavascriptBridge.callHandler(
    'submitFromWeb'
    , {'param': str1}
    , function(responseData) {
        document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData
    }
);

你可以在Java中设置一个默认的handler,这样js就可以在不分配handlerName的情况下向Java发送消息

webView.setDefaultHandler(new DefaultHandler());
window.WebViewJavascriptBridge.send(
    data
    , function(responseData) {
        document.getElementById("show").innerHTML = "repsonseData from java, data = " + responseData
    }
);

注册一个 JavaScript 处理函数,以便 Java 可以调用
WebViewJavascriptBridge.registerHandler(“functionInJs”, function(data, responseCallback) {
document.getElementById(“show”).innerHTML = ("data from Java: = " + data);
var responseData = “Javascript Says Right back aka!”;
responseCallback(responseData);
});
Java可以通过以下方式调用这个js处理函数“functionInJs”:

webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
    @Override
    public void onCallBack(String data) {

    }
});

你也可以定义一个默认的handler使用init方法,这样Java就可以在不分配handlerName的情况下向js发送消息

例如:

bridge.init(function(message, responseCallback) {
    console.log('JS got a message', message);
    var data = {
        'Javascript Responds': 'Wee!'
    };
    console.log('JS responding with', data);
    responseCallback(data);
});
webView.send("hello");

将在 webview 问题中打印 ‘JS got message hello’ ‘JS respond with’。

注意
这个库将向多个打击对象注入一个 WebViewJavascriptBridge。您可以收听WebViewJavascriptBridgeReady事件以确保window.WebViewJavascriptBridge存在,如代码所示:

if (window.WebViewJavascriptBridge) {
    //do your work here
} else {
    document.addEventListener(
        'WebViewJavascriptBridgeReady'
        , function() {
            //do your work here
        },
        false
    );
}

或者定义,如果JBridge函数将所有通话时间window.WVJBCallbacks中,当事件触发window.WebViewJavascriptBridge时,此任务将被发掘。WebViewJavascriptBridgeReady

将 setupViewJavascriptBridge 复制并粘贴到您的 JS 中:

function setupWebViewJavascriptBridge(callback) {
	if (window.WebViewJavascriptBridge) {
        return callback(WebViewJavascriptBridge);
    }
	if (window.WVJBCallbacks) {
        return window.WVJBCallbacks.push(callback);
    }
	window.WVJBCallbacks = [callback];
}

调用setupWebViewJavascriptBridge然后使用桥来注册处理程序或调用Java处理程序:

setupWebViewJavascriptBridge(function(bridge) {
	bridge.registerHandler('JS Echo', function(data, responseCallback) {
		console.log("JS Echo called with:", data);
		responseCallback(data);
    });
	bridge.callHandler('ObjC Echo', {'key':'value'}, function(responseData) {
		console.log("JS received response:", responseData);
	});
});

它与https://github.com/marcuswestin/WebViewJavascriptBridge相同,您可以轻松地在 Android 和 iOS 之间的不同平台上定义相同的行为。同时,编写自己的代码。

问题十五:Vue中的$nextTick有什么作用?

定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()

理解:nextTick()是将回调函数延迟在下一次dom更新数据后调用,即当数据更新了在DOM中渲染后自动执行该函数。
Vue实现响应式并非数据发生变化后DOM立即变化,而是按照一定的策略进行DOM的更新

原理:

Vue是异步执行DOM更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环(event loop)中观察到的数据变化的watcher推送进这个队列。如果这个watcher被触发多次,只会被推送到队列一次。这种缓冲行为可以有效去掉重复数据造成不必要的计算和DOM操作。而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新。

当你设置vm.somedata = 'new value’时,DOM并不会立马更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。若此时你想要根据更新的DOM状态去做某些事情,就会出现问题。为了在数据变化后等待Vue完成更新DOM,可在数据变化后立即使用Vue.nextTick(callback),这样回调函数在DOM更新完成后就会调用。

例子:

const vm = new Vue({
  el: '#app',
  data: {
    message: '原始的值'
  }
})
vm.message = '修改后的值'
// DOM 还没有更新
console.log(vm.$el.textContent) // 原始的值
Vue.nextTick(function () {
  // DOM 更新了
  console.log(vm.$el.textContent) // 修改后的值
})

组件内使用 vm. n e x t T i c k ( ) 实例方法只需要通过 t h i s . nextTick() 实例方法只需要通过this. nextTick()实例方法只需要通过this.nextTick(),并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
this.$nextTick(function () {
    console.log(this.$el.textContent) // => '修改后的值'
})

$nextTick() 会返回一个 Promise 对象,可以是用async/await完成相同作用的事情

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
await this.$nextTick()
console.log(this.$el.textContent) // => '修改后的值'

问题十四:懒加载的实现

一、什么是懒加载?

懒加载突出一个“懒”字,懒就是拖延迟的意思,所以“懒加载”说白了就是延迟加载,比如我们加载一个页面,这个页面很长很长,长到我们的浏览器可视区域装不下,那么懒加载就是优先加载可视区域的内容,其他部分等进入了可视区域在加载

二.为什么要懒加载?

减少无用资源的加载
提升用户体验
防止加载过多图片而影响其它资源文件的加载

三.懒加载的实现原理?

图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会请求图片资源。根据这个原理,我们使用 HTML5 的 data-xxx 属性来储存图片的路径,在需要加载图片的时候,将 data-xxx 中图片的路径赋值给 src,这样就实现了图片的按需加载,即懒加载
四.实现步骤
知识点

window.innerHeight 是浏览器可视区的高度
document.body.scrollTop || document.documentElement.scrollTop 是浏览器滚动的过的距离
imgs.offsetTop 是元素顶部距离文档顶部的高度(包括滚动条的距离)
图片加载条件:img.offsetTop < window.innerHeight + document.body.scrollTop;

在这里插入图片描述
代码实现

<!DOCTYPE html>
<html lang="en">
<div class="container">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
</div>
<script>
var imgs = document.querySelectorAll('img');
function lozyLoad(){
		var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
		var winHeight= window.innerHeight;
		for(var i=0;i < imgs.length;i++){
			if(imgs[i].offsetTop < scrollTop + winHeight ){
				imgs[i].src = imgs[i].getAttribute('data-src');
			}
		}
	}
  window.onscroll = lozyLoad();
四. 微信小程序实现图片懒加载

十六. js执行顺序问题

setTimeout是宏任务【macrotask】,Promise整体是微任务【microtask】,
Promise 是放入 microtask 队列的, 而 setTimeout 放入 macrotask 队列.

主线程执行完了之后,先处理微任务【microtask】队列, 【微任务】队列每次处理直到队列为空, 接下来处理【宏任务】队列,【宏任务】 每次只处理的队列里的第一个任务, 当任务处理完后, 又会进入到【微任务】队列的处理. 如此反复。

setTimeout(function(){
    console.log('D')
 },0)

var promise = new Promise(function(resolve, reject){
    console.log('A')
    resolve()
 }).then(function(){
    console.log('C')
})
console.log('B');
//  A
//  B
//  C
//  D

十七.虚拟dom是什么?

从本质上来说,Virtual Dom是一个JavaScript对象,通过对象的方式来表示DOM结构。将页面的状态抽象为JS对象的形式,配合不同的渲染工具,使跨平台渲染成为可能。通过事务处理机制,将多次DOM修改的结果一次性的更新到页面上,从而有效的减少页面渲染的次数,减少修改DOM的重绘重排次数,提高渲染性能。

虚拟DOM是对DOM的抽象,这个对象是更加轻量级的对 DOM的描述。它设计的最初目的,就是更好的跨平台,比如Node.js就没有DOM,如果想实现SSR,那么一个方式就是借助虚拟DOM,因为虚拟DOM本身是js对象。 在代码渲染到页面之前,vue会把代码转换成一个对象(虚拟 DOM)。以对象的形式来描述真实DOM结构,最终渲染到页面。在每次数据发生变化前,虚拟DOM都会缓存一份,变化之时,现在的虚拟DOM会与缓存的虚拟DOM进行比较。在vue内部封装了diff算法,通过这个算法来进行比较,渲染时修改改变的变化,原先没有发生改变的通过原先的数据进行渲染。

另外现代前端框架的一个基本要求就是无须手动操作DOM,一方面是因为手动操作DOM无法保证程序性能,多人协作的项目中如果review不严格,可能会有开发者写出性能较低的代码,另一方面更重要的是省略手动DOM操作可以大大提高开发效率。

个人理解
虚拟DOM就是用JS对象模拟了真实渲染好的DOM,所以模拟出来的DOM称为虚拟DOM,浏览器内核中有两个引擎,JS引擎和渲染引擎,他们是彼此分开的,且每一次使用JS去操作DOM时,两个引擎之间会发生“跨界交流”,这个交互的过程是有性能开销的,访问的越多会造成明显的性能卡顿问题,所以我们选择用JS去操作JS模拟出来的虚拟DOM这样JS和JS之间不存在跨界问题就会很快,新生成的虚拟DOM(每次操作节点会创建新的虚拟DOM)会和之前旧的虚拟DOM(初始化时就会创建虚拟DOM)进行diff比较,比较完成后把变化的地方一次性更新到真实的 DOM 树上(新的虚拟DOM会缓存下来和下次生成的虚拟DOM进行比较)。

vue里面

虚拟DOM(Virtual Dom)即虚拟节点。

    虚拟DOM在Vue.js里做了两件事:
    创建JS对象(虚拟节点),用来模拟真实DOM节点。
    该对象包含了真实DOM的结构及其属性
    将虚拟节点与旧虚拟节点进行对比,然后更新视图(渲染)

vue的VNode
在vue中存在一个VNode类,使用它可以实例化不同类型的vnode实例,而不同类型的vnode实例各自代表不同类型的DOM元素,vnode的作用主要是描述了怎样去创建DOM节点

vnode的几种类型

1.注释节点

2.文本节点

3.元素节点

4.组件节点

5.函数式组件

6.克隆节点

事实上,只有前三类节点会被创建并插入到DOM中

vnode有tag属性就是元素节点

没有tag属性就可以看isCommet属性,true代表注释节点,false就是文本节点了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值