vue数据双向绑定的原理

vue数据双向绑定的原理

一 复习闭包

1 闭包含义:

当函数嵌套时,内部函数使用了外部函数的变量,就会产生闭包

当函数可以记住并访问自己的作用域时,就会产生闭包

2 闭包注意点

① 队列里的代码执行完毕,同步的已经执行完了

② 作用域时js代码解析时创建,关浏览器时销毁

③ 作用域是来维护变量的查找规则的

④ 一个函数作用域一般对应一个执行上下文,除非函数被递归调用

⑤ 执行上下文是函数调用时创建,调用完销毁

⑥ 执行上下文是来存函数执行时需要的数据的

3 鸡肋闭包

// 5.在全局作用域对应的处于活动状态下的执行上下文中寻找 如果找到就使用  如果找不到 报错!
    function wrap(){
        // 3.在wrap作用域对应的处于活动状态下的执行上下文中寻找 如果找到就使用
        // 4.如果找不到查看闭包 如果闭包中也没有如果找不到上上一层作用域
        var test = "wrap_test";
        function inner(){
            //1. 首先在inner作用域对应的处于活动状态下的执行上下文中寻找  如果找到就使用
            //2. 如果找不到查看闭包 如果闭包中也没有上上一层作用域
            console.log(test)
        }
        inner()
    }
    wrap()

作用域:全局作用域,wrap函数作用域 , inner作用域

执行上下文:全局执行上下文 wrap执行上下文 inner执行上下文

4 经典闭包

  	function wrap(){
        var test = "wrap_test";
        return function(){
            console.log(test)
        }
    }
    var inner = wrap();
    inner()

5 异步代码闭包

当函数可以记住并访问自己的作用域链时,就会产生闭包

  function wrap(){
        var test = "wrap_test";
        setTimeout(function (){
            console.log(test)
        },0)
    }
    wrap()

6 异步面试题

闭包和内部函数是一一对应的 先同步执行,异步执行进了队列等待同步的执行完毕

		// 第一次定时器执行时 定时器的回调拿到了一个闭包 闭包的值为{i:0}
		// 第二次定时器执行时 定时器的回调拿到了一个闭包 闭包的值为{i:1}
		// 第三次定时器执行时 定时器的回调拿到了一个闭包 闭包的值为{i:2}
		// 第四次定时器执行时 定时器的回调拿到了一个闭包 闭包的值为{i:3}
		// 第五次定时器执行时 定时器的回调拿到了一个闭包 闭包的值为{i:4}

		for(var i=0;i<5;i++){
			(function(i){
				// i: 当前function自己的i
				setTimeout(function(){
					console.log(i);
				},1000)
			})(i)
			// i :全局的i
		}

		//一秒钟之后同时输出01234
for(var i=0;i<5;i++){
			(function(i){
				setTimeout(function(){
					console.log(i);
				},1000*i)
			})(i)
		}
/*如果同步代码执行的时间比较短,那么应该是每隔一秒钟 输入 0 1 2 3 4*/
如果同步代码执行的时间比较长,那么就会一起在在队列中等待,同步代码执行完毕,会同时输出

二 文档碎片

1 querySelector

querySelector拿到的是静态列表,而getElement拿到的则是动态列表

   window.onload=function (){
        //querySelector系列拿到是静态列表!!!!
        var liNodes = document.querySelectorAll("ul li");
        var listNode = document.querySelector("#list");

        //getxxx系列拿到的是动态列表
        // var liNodes = listNode.getElementsByTagName("li");

        //dom操作
        listNode.innerHTML+="<li>5</li>"
        liNodes = document.querySelectorAll("ul li");

        //点灯
        for(var i=0;i<liNodes.length;i++){
            liNodes[i].style.background="pink";
        }
    }

2 template

template.html

<body>
    <template>
        <img :src="url" >
    </template>
</body>
<script src="./js/text.js"></script>

text.js

   var temp = document.querySelector("template");
    //temp.content:文档碎片对象
    var fragment =  temp.content;
    console.dir(fragment);

    //start
    var imgNode = fragment.querySelector("img");
    imgNode.src = "./img/vuex.png"
    //在start和end之间进行大量的dom操作 且不会触发dom树更新 不会引起浏览器的重新渲染
    //end


    //给body元素加一个子节点
    //将文档碎片作为append的参数时 加入到dom树中的不是该文档碎片 而是文档碎片所有子节点
    document.body.append(fragment)
    temp.remove()
}

案例

window.onload=function () {
        var ulNode = document.querySelector("ul");
        //创建一个文档碎片
        var fragment = document.createDocumentFragment();
        var child = null;
        //firstChild 会考虑文本节点的
        while (ulNode.firstChild){
            //  appendChild的参数如果是存在于dom树内部的节点 那appendChild是剪切操作
            //  appendChild的参数如果是一个新创建的节点 那appendChild是添加操作
            fragment.appendChild(ulNode.firstChild)
        }

        //dom树中将不会再有节点  而文档碎片中会塞入所有的ul的子节点

        //进行大量的dom操作  且界面不会更新  提供了dom操作的性能
        Array.from(fragment.children).forEach((item)=>{
            item.innerHTML = "尚硅谷-" + item.innerHTML;
        })

        //appendChild 让 fragment作为参数  最终追加到文档中的是fragment的子节点列表 而不是fragment本身
        ulNode.appendChild(fragment)

三 数据双向绑定

1 js属性

	var obj = {a:"a"}
    obj.b="b"
    obj.c="c"
    Object.defineProperty(obj,"c",{
        // value:"c", //c的属性值
        // writable:true, //当前属性是否可以被修改
        enumerable:true,//当前属性是否可枚举(当前属性是否可以出现在对象的for in循环中)
        configurable:true,//当前属性是否可以重新配置(是否可以被delete关键字删除 是否可以通过defineProperty重新定义)
        //get set 和 writable value 只能出现一组
        get(){return "ccc"},
        set(newval){}
    })
    console.log(obj);

2 断点

resume播放按钮:跳到下一个断点处 给回调函数使用(异步代码)

step over:直接跳到下一行代码 如果当前行是个函数,则函数会被立马执行完

step into :跳到函数内部执行代码

step out:跳出该函数

3 mvvm原理

mvvm是 Model-View-ViewModel 的缩写,即 模型-视图-视图模型。

① Model:数据模型,后端传递的数据。(data,props,computed等部分)
② View:代表 UI 组件,它负责将数据模型转化成 UI 展现出来。(template部分)
③ ViewModel:是一个同步View 和 Model的对象。MVVM模式的核心,它连接Model和View的桥梁。
vue的核心,双向绑定、监听(watch)、操作(methods)等部分

数据代理:将data对象中直接属性一个个拿出来给vm实例对象新增同名的属性,此处的代理是浅代理

数据劫持:将data对象中所有属性一个个拿出来重新定义,让他们具备get set方法,此处劫持是深度的

模板解析

dep watcher

① dep(data中的每一个数据):

data中的每一个属性都分配了一个dep,在对data中的数据进行读取或修改时这个dep闭包都会被加载

② watcher(模板上的每一个指令):

在每一个指令被解析的最后一步,都会去构建一个watcher对象,这个对象拥有更新器闭包

模板写法:

<div id = "app">
	<div v-html="obj.wife.name"></div>
	<span>{{obj.wife.name}}</span>
</div>

一个watcher可能要对用多个dep

一个dep可能对应多个watcher

为了响应式更新,vue需要建立dep和watcher之间的多对多关系

vue数据双向绑定原理

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值