Full Code of qq281113270/vue-ddf- for AI

master 770f5592dda4 cached
176 files
850.1 KB
234.4k tokens
351 symbols
1 requests
Download .txt
Showing preview only (1,047K chars total). Download the full file or copy to clipboard to get everything.
Repository: qq281113270/vue-ddf-
Branch: master
Commit: 770f5592dda4
Files: 176
Total size: 850.1 KB

Directory structure:
gitextract_aaudxq4u/

├── 0.html
├── 05自定义指令.html
├── 06provide组件通信.html
├── 07.html
├── 08delimiters.html
├── 09v-model.html
├── 1.html
├── 10tag标签.html
├── 10标签匹配.html
├── 11tag标签.html
├── 11标签匹配.html
├── 12tag标签.html
├── 12高阶组件.html
├── 13组件.html
├── 14高阶组件.html
├── 15 vonde.html
├── 16transition动画1.html
├── 16transition动画2.html
├── 16transition动画3.html
├── 17transition动画中的appear.html
├── 2.html
├── 3.html
├── 4.html
├── 5.html
├── 6.html
├── 6属性.html
├── 7for属性.html
├── 8event属性.html
├── HTMLUnknownElement.html
├── IS_REGEX_CAPTURING_BROKEN.html
├── JS里charCodeAt()和fromCharCode().html
├── JS里charCodeAt()和fromCharCode()方法拓展应用:加密与解密.html
├── MessageChannel.html
├── MessageChannel_0.html
├── MessageChannel_1.html
├── Proxy_1.html
├── Proxy_2.html
├── Proxy_3.html
├── Proxy_4.html
├── Proxy_5.html
├── Proxy_6.html
├── README.md
├── README_EN.md
├── Reflect.ownKeys.html
├── Set.html
├── StrictChecking.html
├── String方法之fromCharCode()和charCodeAt().html
├── Symbol.html
├── Symbol1.html
├── Symbol2.html
├── Symbol3.html
├── _Set.html
├── __proto__.html
├── _c.html
├── add.txt
├── add1.txt
├── advance.html
├── appear.html
├── argMatch.html
├── arrObj.html
├── array.html
├── attribute.html
├── bailRE.html
├── buildRegex.html
├── callbacks.slice(0).html
├── camelize.html
├── charCodeAt.html
├── classify.html
├── classifyRE.html
├── classifyRE1.html
├── comments.html
├── contextmenu.html
├── createElementNS.html
├── ddf.html
├── def.html
├── defineProperty.html
├── exec.html
├── exex.html
├── forIteratorRE.html
├── formatComponentName.html
├── genCheckboxModel.js
├── genStaticKeys.html
├── getComputedStyle.html
├── getHookArgumentsLength.html
├── getOwnPropertyNames.html
├── getShouldDecode.html
├── getTransitionInfo.html
├── getTransitionInfo获取css3 Transition 信息.html
├── getTransitionInfo获取css3 Transition 信息2.html
├── getType.html
├── getTypeIndex.html
├── hookRE.html
├── hyphenate.html
├── hyphenateRE.html
├── ieNSBug.html
├── index.html
├── indexOf.html
├── inline-template.html
├── is.html
├── isReserved.html
├── isUnknownElement.html
├── javascript 匿名函数自执行调用.html
├── js Worker 线程.docx
├── js 字符串截取方法.html
├── js 数组截取.html
├── js_watch.html
├── js_watch1.html
├── js中with、this的用法.html
├── js命令者.html
├── js如何判断数组含有某值,in,includes,inArray,indexOf方案对比.html
├── js观察者.xmind
├── js观察者_1.xmind
├── lastIndexOf.html
├── length.html
├── length0.html
├── modifierRE.html
├── mount.html
├── new Array(val).html
├── new Proxy.html
├── newFunction.html
├── nodeType.html
├── normalizeArrayChildren.html
├── object.html
├── object.keys.html
├── once.html
├── parseFilters.html
├── parseModel.html
├── parseModifiers.html
├── parsePath.html
├── parseStyleText.html
├── parseText.html
├── performance.html
├── performance对象.docx
├── prohibitedKeywordRE.html
├── promise.html
├── proxy.html
├── repeat.html
├── requestAnimationFrame.html
├── requestAnimationFrame2.html
├── setget.html
├── simpleCheckRE.html
├── slice splice.html
├── split.html
├── startTagClose.html
├── stopImmediatePropagation.html
├── stripStringRE.html
├── toUnicodeFun.html
├── transformModel.html
├── transition.html
├── unaryOperatorsRE.html
├── unaryOperatorsRE匹配字符串前一个字符串是什么.html
├── unaryOperatorsRE匹配字符串前一个字符串是什么2.html
├── vm._watcher === watcher.html
├── vue.js
├── vue.js中HOOK函数.docx
├── vue实现单页返回缓存,下一页刷新.doc
├── vue数据监听.docx
├── vue源码分析.docx
├── vue源码帖子分析.docx
├── vue零散代码分析.html
├── window_performance.html
├── window_performance1.html
├── with.html
├── wrapFilter.html
├── 三木分析.html
├── 三木分析1.html
├── 匿名函数执行.html
├── 发布-订阅模式.html
├── 数组api.html
├── 数组的扩展-array.some()和array.every()区别?.docx
├── 正则$.html
├── 理解vue实现原理,实现一个简单的Vue框架.docx
├── 虚拟dom.docx
├── 观察者模式.html
├── 静态方法与原型.html
└── 高阶组件.html

================================================
FILE CONTENTS
================================================

================================================
FILE: 0.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>



</head>
<body>

<div id="app">
    <!--this is comment-->  {{ message }}
</div>
<div id="app1">
    <div  >

        <!--count={{count}}-->
        <!--reversedCount={{reversedCount}}-->
    </div>


</div>


<script>
    console.log( Object.keys('abcd'))
    debugger;
    console.log('=====return 1=======')
    console.log(   new Function('return 1'))

    console.log('return='+ new Function(("return " + function () {
                
            })));



    var app = new Vue({

        el: '#app',
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点
           setTimeout(()=>{
//                this.count+=1;
//                console.log('this.count='+this.count)
           },1000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

       },
        data:function () {
             return  {
                 count:0,

                 message: 'Hello Vue!1111111'
             }
        },
//        data: {
//            count:0,
//            message: 'Hello Vue!'
//        }
    })
    var app1 = new Vue({
        comments:true,
        el: '#app1',
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        methods:{
          click:function () {
               console.log('点击事件')
          }
        },
        mounted: function (){ //挂载元素,获取到DOM节点
            setTimeout(()=>{
                console.log(this.count)
                this.count++;
                console.log('this.count=')
                console.log(this.count)
            },1000)
        },
        computed: {
            // 计算属性的 getter
            reversedCount: function () {
                // `this` 指向 vm 实例
                return this.count++;
            }
        },

        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
        data: {
            count:0,

            message: 'Hello Vue!2222'
        }
    })
</script>

</body>
</html>

================================================
FILE: 05自定义指令.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <my-comp v-if="msg" :msg="msg"></my-comp>
    <button @click="update">更新</button>
    <button @click="uninstall">卸载</button>
    <button @click="install">安装</button>
</div>
<script type="text/javascript">
    Vue.component('button-counter', {


        data: function () {
            return {
                count: 0
            }
        },
        mounted: ()=> { //挂载元素,获取到DOM节点

        },
        template: '<button  v-hello="123">You clicked me   times.</button>'
    })
    Vue.directive('hello', {
        bind: function (el){
            console.log('bind:');
        },
        inserted: function (el){
            console.log('inserted:');
        },
        update: function (el){
            console.log('update:');
        },
        componentUpdated: function (el){
            console.log('componentUpdated:');
        },
        unbind: function (el){
            console.log('unbind:');
        }
    });

    var myComp = {
        template: '<button-counter >{{msg}}</button-counter>',
        props: {
            msg: String
        }
    }

    new Vue({
        el: '#app',
        data: {
            msg: 'Hello'
        },
        components: {
            myComp: myComp
        },
        methods: {
            update: function (){
                this.msg = 'Hi';
            },
            uninstall: function (){
                this.msg = '';
            },
            install: function (){
                this.msg = 'Hello';
            }
        }
    })
</script>
</body>
</html>

================================================
FILE: 06provide组件通信.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="components-demo">
    <button-counter id="123"></button-counter>
</div>
<div id="app">
    {{ message }}
</div>

<script>
    //   function  person (){
    //     this.options='aaa'
    //   }
    //
    //   person.constructor={aa:'c'}
    //   person.prototype.options='span'
    //
    //   console.log(person.constructor.options)
    //  console.log(Object.create(person.constructor.options));
    //    new Vue({})
    var obj = {
        name: 'name',
        age: 29
    }
    var arr = []
    var res = new Array(obj.length);

    console.log(obj.length)
    console.log(res)
    console.log(arr.length)


    Vue.component('button-counter', {
        props:['id'],
        functional:true,
        inject: ['foo'],
        data: function () {
            return {
                count: 0
            }
        },
        mounted: ()=> { //挂载元素,获取到DOM节点
            console.log('==this.foo==')
            console.log(this.foo)

        },
        template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
    })

    new Vue({el: '#components-demo'})

    var app = new Vue({
        el: '#app',
        provide: {
            foo: 'bar'
        },
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点

           setTimeout(()=>{
                this.count=11;
                console.log('this.count='+this.count)
           },5000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

       },
        data: {
            count:0,
            message: 'Hello Vue!'
        }
    })
</script>

</body>
</html>

================================================
FILE: 07.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="example">
    <my-component  :msg="count" >

    </my-component>
</div>
<script >

    // 注册
    Vue.component('my-component', {
      //  _isComponent:true,
        props: ['msg'],
        template: '<div>{{msg}} A custom component!</div>'
    })

    // 创建根实例

    var app = new Vue({
        el: '#example',
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: function () {


        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
        data: {
            count:0,
            message: 'Hello Vue!'
        }
    })
</script>

</body>
</html>

================================================
FILE: 08delimiters.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>




</head>
<body>
<div id="app">
    {{ message }}
</div>

<div id="app1">
    ${ message }
</div>

<script>


    new Vue(
            {
                el:'#app',
                data: {
                    message: 'Hello'
                },

            })
    new Vue(
            {
                el:'#app1',
                data: {
                    message: 'Hello'
                },
                delimiters:['${', '}']
            })

</script>

</body>
</html>

================================================
FILE: 09v-model.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="demo">

    <ul>

        <li   :class="[isClass?'class-a':'class-b']" v-if="index"   v-for="(item,index) in list"    v-userdefined >
            <!--<img v-bind:src="item.url"/>-->
            <input type="text" v-model="item.url">
            <input type="checkbox" :value="index"  v-model="checkbox">
        </li>
    </ul>
    <select v-model="select">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5</option>
    </select>

    <base-input v-model="lovingVue"></base-input>
    <!-- 我是注释节点,你好啊! -->
</div>
<style>
    .class-a {
        background: red;
    }

    .class-b {
        background: red;
    }
</style>
<script>
    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('userdefined', { //用户自定义指令
        // 当被绑定的元素插入到 DOM 中时……
        inserted: function (el) {
            // 聚焦元素
            el.addEventListener("click", function(){
                alert(1)
            });
        }
    })


    //关键是在$emit('change', $event.target.checked)  change或者input 事件就是更新model事件
    Vue.component('base-input', {
        model: {
            prop: 'text',
            event: 'input' //或者 event: 'change' 都可以
        },
        props: {
            text: String
        },
        template: `
    <input
      type="text"
      v-bind:value="text"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
    })


    //创建一个vue的实例
    new Vue({
        el: "#demo",
        comments:true,
        data: {
            isClass:true,
            lovingVue:'123',
            checkbox:['3'],
//            checkbox:false,
            select:3,
            userDefined:'userDefined',
            classA: true,
            list: [
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:true,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
            ],

        },
        methods: {
            clickEvent(){
                console.log('clickEvent')
            },
            clickEvent1(){
                console.log('clickEvent1')
            }

        },

        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: function(){ //挂载元素,获取到DOM节点
            console.log(this.lovingVue)
            console.log(this.select)

            setInterval(()=>{
                console.log(this.lovingVue)
            },1000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: 1.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="components-demo">
    <button-counter></button-counter>
</div>
<div id="app">
    {{ message }}
</div>

<script>
    //   function  person (){
    //     this.options='aaa'
    //   }
    //
    //   person.constructor={aa:'c'}
    //   person.prototype.options='span'
    //
    //   console.log(person.constructor.options)
    //  console.log(Object.create(person.constructor.options));
    //    new Vue({})
    var obj = {
        name: 'name',
        age: 29
    }
    var arr = []
    var res = new Array(obj.length);

    console.log(obj.length)
    console.log(res)
    console.log(arr.length)


    Vue.component('button-counter', {
        data: function () {
            return {
                count: 0
            }
        },
        template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
    })

    new Vue({el: '#components-demo'})

    var app = new Vue({
        el: '#app',
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点
           setTimeout(()=>{
                this.count=11;
                console.log('this.count='+this.count)
           },5000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

       },
        data: {
            count:0,
            message: 'Hello Vue!'
        }
    })
</script>

</body>
</html>

================================================
FILE: 10tag标签.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>

<div id="demo">
        <span style="width: 100px;">
            <i>i 标签
                  在纯文本中,要宽容,把它当作文本来对待
            </i>
            {{lovingVue}}
        </span>
       <div>
            {{select}}
       </div>
</div>
<style>
    .class-a {
        background: red;
    }

    .class-b {
        background: red;
    }
</style>
<script>


    //创建一个vue的实例
    new Vue({
        el: "#demo",
        comments:true,
        data: {
            classD:'classD',
            classC:'classC',
            isClass:true,
            lovingVue:'123',
            checkbox:['3'],
//            checkbox:false,
            select:3,
            userDefined:'userDefined',
            classA: true,
            list: [
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:true,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
            ],

        },
        methods: {
            clickEvent(){
                console.log('clickEvent')
            },
            clickEvent1(){
                console.log('clickEvent1')
            }

        },

        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: function(){ //挂载元素,获取到DOM节点
            console.log(this.lovingVue)
            console.log(this.select)

            setInterval(()=>{
                console.log(this.lovingVue)
            },1000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: 10标签匹配.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <input type="text" v-info v-data/>
   <div>
       <span>
           <i>213</i>
       </span>
   </div>
    <div>
        {{message}}
    </div>

</div>
<script>
    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('info', {
        // 当被绑定的元素插入到 DOM 中时……
        inserted: function (el) {

            el.addEventListener('change',function () {
                console.log(this.value)
            },false)
//            // 聚焦元素
//            el.focus()
        }
    })
    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('data', {
        // 当被绑定的元素插入到 DOM 中时……
        inserted: function (el) {

            el.addEventListener('change',function () {
                console.log(this.value)
            },false)
//            // 聚焦元素
//            el.focus()
        }
    })

    new Vue(
            {
                el:'#app',
//                comments:true,
                data: {
                    message: 'Hello'
                },
                directives: {
                    focus: {
                        // 指令的定义
                        inserted: function (el) {
                            el.focus()
                        }
                    }
                }

            })

</script>
</body>
</html>

================================================
FILE: 11tag标签.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<p><h1>标签h1</h1></p>
<div  class="classB" class='classA' html='abc' class='[a?aa:bb,cc]'  style='width:100px'>我是div</div>
<div id="demo">
    <div  class="classB" class='classA' html='abc' :class='classC' :class='classD' style='width:100px'>我是div</div>
    <span>我是span</span>
    <!--我是注释标签-->
    <p><h1>标签h1</h1></p>
</div>
<style>
    .class-a {
        background: red;
    }

    .class-b {
        background: red;
    }
</style>
<script>


</script>

</body>
</html>

================================================
FILE: 11标签匹配.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">

    <div :class="{'a':message}">
        {{message}}
    </div>

</div>
<script>
    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('info', {
        // 当被绑定的元素插入到 DOM 中时……
        inserted: function (el) {

            el.addEventListener('change',function () {
                console.log(this.value)
            },false)
//            // 聚焦元素
//            el.focus()
        }
    })
    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('data', {
        // 当被绑定的元素插入到 DOM 中时……
        inserted: function (el) {

            el.addEventListener('change',function () {
                console.log(this.value)
            },false)
//            // 聚焦元素
//            el.focus()
        }
    })

    new Vue(
            {
                el:'#app',
//                comments:true,
                data: {
                    message: 'Hello'
                },
                directives: {
                    focus: {
                        // 指令的定义
                        inserted: function (el) {
                            el.focus()
                        }
                    }
                }

            })

</script>
</body>
</html>

================================================
FILE: 12tag标签.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>

<div id="demo">
       <i></i>
        <span style="width: 100px;">

              span 节点
               {{isClass}}
              {{number}}
        </span>

</div>
<style>
    .class-a {
        background: red;
    }

    .class-b {
        background: red;
    }
</style>
<script>


    //创建一个vue的实例
    new Vue({
        el: "#demo",
        comments:true,
        data: {
            number:1,
            classD:'classD',
            classC:'classC',
            isClass:true,
            lovingVue:'123',
            checkbox:['3'],
//            checkbox:false,
            select:3,
            userDefined:'userDefined',
            classA: true,
            list: [
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:true,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
            ],

        },
        methods: {
            clickEvent(){
                console.log('clickEvent')
            },
            clickEvent1(){
                console.log('clickEvent1')
            }

        },

        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: function(){ //挂载元素,获取到DOM节点
            console.log(this.lovingVue)
            console.log(this.select)

            setInterval(()=>{
                this.number++
                console.log(this.lovingVue)
            },3000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: 12高阶组件.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app5">
    <input v-model="query">
    <my-transition :query="query" :list="list">
        <li v-for="(item, index) in computedList"
            :key="item.msg"
            :data-index="index">
            {{item.msg}}
        </li>
    </my-transition>
    <script>
        Vue.component('my-transition', {
            functional:true,
            render:function (h, ctx) {
                var data = {
                    props:{
                        tag:'ul',
                        css:false
                    },
                    on:{
                        beforeEnter:function (el) {
                            el.style.opacity = 0
                            el.style.height = 0
                        },
                        enter:function (el, done) {
                            var delay = el.dataset.index * 150
                            setTimeout(function () {
                                Velocity(el, {opacity:1, height:'1.6em'},{complete:done})
                            }, delay)
                        },
                        leave:function (el, done) {
                            var delay = el.dataset.index * 150
                            setTimeout(function () {
                                Velocity(el, {opacity:0, height:0}, {complete:done})
                            }, delay)
                        }
                    }
                }
                return h('transition-group', data, ctx.children)
            },
            props:['query', 'list']
        })

        var app5 = new Vue({
            el:'#app5',
            data:{
                query:'',
                list:[
                    {msg:'Bruce Lee'},
                    {msg:'Jackie Chan'},
                    {msg:'Chuck Norris'},
                    {msg:'Jet Li'},
                    {msg:'Kung Furry'},
                    {msg:'Chain Zhang'},
                    {msg:'Iris Zhao'},
                ]
            },
            computed:{
                computedList:function () {
                    var vm = this
                    return this.list.filter(function (item) {
                        return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
                    })
                }
            },
        })
    </script>
</div>
</body>
</html>

================================================
FILE: 13组件.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>

<div id="demo">
    <i></i>
    <span style="width: 100px;">

              span 节点
               {{isClass}}
        </span>
    <button-counter mgs="你好"></button-counter>

</div>
<style>
    .class-a {
        background: red;
    }

    .class-b {
        background: red;
    }
</style>
<script>
    // 定义一个名为 button-counter 的新组件
    Vue.component('button-counter', {
        props:['mgs'],
        data: function () {
            return {
                count: 0
            }
        },
        template: '<button v-on:click="count++">You clicked me {{ count }} times.{{mgs}}</button>'
    })


    //创建一个vue的实例
    new Vue({
        el: "#demo",
        comments:true,
        data: {
            classD:'classD',
            classC:'classC',
            isClass:true,
            lovingVue:'123',
            checkbox:['3'],
//            checkbox:false,
            select:3,
            userDefined:'userDefined',
            classA: true,
            list: [
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:true,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    selected:false,
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
            ],

        },
        methods: {
            clickEvent(){
                console.log('clickEvent')
            },
            clickEvent1(){
                console.log('clickEvent1')
            }

        },

        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: function(){ //挂载元素,获取到DOM节点
            console.log(this.lovingVue)
            console.log(this.select)

            setInterval(()=>{
                console.log(this.lovingVue)
            },1000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: 14高阶组件.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app5">
    <input v-model="query">
    <my-transition :query="query" :list="list">
        <li v-for="(item, index) in computedList"
            :key="item.msg"
            :data-index="index">
            {{item.msg}}
        </li>
    </my-transition>
</div>

<script>
    Vue.component('my-transition', {
        functional:true,
        render:function (h, ctx) {
            var data = {
                props:{
                    tag:'ul',
                    css:false
                },
                on:{
                    beforeEnter:function (el) {
                        el.style.opacity = 0
                        el.style.height = 0
                    },
                    enter:function (el, done) {
                        var delay = el.dataset.index * 150
                        setTimeout(function () {
                            Velocity(el, {opacity:1, height:'1.6em'},{complete:done})
                        }, delay)
                    },
                    leave:function (el, done) {
                        var delay = el.dataset.index * 150
                        setTimeout(function () {
                            Velocity(el, {opacity:0, height:0}, {complete:done})
                        }, delay)
                    }
                }
            }
            var vonde = h('transition-group', data, ctx.children)
            console.log(vonde)
            debugger;
            return vonde;
        },
        props:['query', 'list']
    })

    var app5 = new Vue({
        el:'#app5',
        data:{
            query:'',
            list:[
                {msg:'Bruce Lee'},
                {msg:'Jackie Chan'},
                {msg:'Chuck Norris'},
                {msg:'Jet Li'},
                {msg:'Kung Furry'},
                {msg:'Chain Zhang'},
                {msg:'Iris Zhao'},
            ]
        },
        computed:{
            computedList:function () {
                var vm = this
                return this.list;
                return this.list.filter(function (item) {
                    console.log('=item.msg.toLowerCase()=')
                    console.log(item.msg.toLowerCase())
                    return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
                })
            }
        },
    })
</script>

</body>
</html>

================================================
FILE: 15 vonde.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
        <div id="demo">
                   <i></i>
                   <span style="width: 100px;">

                span 节点
        {{isClass}}
         </span>

         </div>

<script>
    var app = new Vue({

        el: '#demo',
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点
            setTimeout(()=>{
//                this.count+=1;
//                console.log('this.count='+this.count)
            },1000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
        data:function () {
            return  {
                count:0,
                isClass:true,

                message: 'Hello Vue!1111111'
            }
        },
//        data: {
//            count:0,
//            message: 'Hello Vue!'
//        }
    })
</script>

</body>
</html>

================================================
FILE: 16transition动画1.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<style>
    .fade-enter-active,
    .fade-leave-active {
        transition: opacity .5s;
    }
    .fade-enter,
    .fade-leave-to  {
        opacity: 0;
    }
</style>
<body>
<div id="demo">
    <button v-on:click="show = !show">
        Toggle
    </button>
    <transition
            name="fade"
            :duration="10000"
    >
        <p v-if="show">hello</p>
    </transition>
</div>

    <script>
        new Vue({
            el: '#demo',
            data: {
                show: true
            }
        })
    </script>
</div>
</body>
</html>

================================================
FILE: 16transition动画2.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<style>
    /* 可以设置不同的进入和离开动画 */
    /* 设置持续时间和动画函数 */
    .slide-fade-enter-active {
        transition: all .3s ease;
    }
    .slide-fade-leave-active {
        transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
    }
    .slide-fade-enter, .slide-fade-leave-to
        /* .slide-fade-leave-active for below version 2.1.8 */ {
        transform: translateX(10px);
        opacity: 0;
    }
</style>
<body>
<div id="demo">
    <div id="example-1">
        <button @click="show = !show">
            Toggle render
        </button>
        <transition name="slide-fade">
            <p v-if="show">hello</p>
        </transition>
    </div>

    <script>
        new Vue({
            el: '#example-1',
            data: {
                show: true
            }
        })
    </script>
</div>
</body>
</html>

================================================
FILE: 16transition动画3.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<style>
    .v-enter-active,
    .v-leave-active {
        transition: opacity .5s;
    }
    .v-enter,
    .v-leave-to  {
        opacity: 0;
    }
</style>
<body>
<div id="demo">
    <button v-on:click="show = !show">
        Toggle
    </button>
    <transition >
        <p v-if="show">hello</p>
    </transition>
</div>

    <script>
        new Vue({
            el: '#demo',
            data: {
                show: true
            }
        })
    </script>
</div>
</body>
</html>

================================================
FILE: 17transition动画中的appear.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<style>
    .custom-appear-active{
        /*color: red;*/
        background: red;
        transition: all 2s ease;
    }
    .custom-appear{
        font-size: 40px;
        /*color: #e069e2;*/
        background: blue;
    }
    .custom-appear-to{
        /*color: #e29138;*/
        background: burlywood;
    }
</style>
<body>
<!--
         关于appear的用法和enter的用法相似,它只是在第一次渲染的时候才会起作用。看完整的代码:
    但是这里有一些问题:关于appear-class、 appear-to-class、 appear-active-class的相同属性那个起作用的问题。
    四种情况:(与他们在style中的排列顺序有关系)
    1、appear-class、 appear-to-class、 appear-active-class或者 appear-to-class、appear-class、 appear-active-class的排列顺序,此时只有appear-active-class的属性起作用。
    2、appear-active-class、appear-class、 appear-to-class
    此时appear-active-class的不起作用,由appear-class过渡到appear-to-class属性。
    3、appear-class、appear-active-class、 appear-to-class
    此时appear-class属性不起作用,由appear-active-class过渡到 appear-to-class属性。
    4、 appear-to-class、 appear-active-class、appear-class
    此时appear-to-class不起作用,由appear-class过渡到 appear-active-class属性。
    enter也有相似的问题
 -->
<div id="app">
    <transition
            appear
            appear-class="custom-appear"
            appear-to-class="custom-appear-to"
            appear-active-class="custom-appear-active"
    >
        <p>appear</p>
    </transition>
</div>
<script>

    new Vue({
        el: "#app"
    })
</script>
</body>
</html>

================================================
FILE: 2.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="example">
    <my-component  msg="hello world" ></my-component>
</div>
<script >

    // 注册
    Vue.component('my-component', {
        _isComponent:true,
        props: ['msg'],
        template: '<div>{{msg}} A custom component!</div>'
    })

    // 创建根实例
    new Vue({
        el: '#example'
    })
</script>

</body>
</html>

================================================
FILE: 3.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="demo">
    {{message}}
    <template></template>
</div>
<script >
    //创建一个子组件
    var Child=Vue.component("child-component",{
       //_isComponent:true,
        template:"<div>我是子组件 {{message}}</div>",
        props: ['message'],
    });
    //创建一个父组件
    Vue.component("parent-component",{
         _isComponent:true,
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
        mounted:function () {
           setTimeout(()=>{
                this.message.push(1);
           },1000)
        },
        template:"<div>{{message}}<child-component  :message='message'></child-component></div>", //注意元素模板只能有一个最上层元素,也就是用一个div包裹整个模板。
        components:{"child-component":Child},//进行子组件关联,注意child-component需要引号。
        data:function(){//组件中的data是一个函数
            return {
                message:[]
            }
        }
    })
    //创建一个vue的实例
    new Vue({
        el:"#demo",
        data: {
            message: 'Hello Vue!'
        },
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
//        mounted: ()=> { //挂载元素,获取到DOM节点
//
//        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: 4.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>

    


</head>
<body>

<div id="app">
    {{ message }}
</div>



<script>


    var app = new Vue({
        el: '#app',
  
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点
//           setTimeout(()=>{
//                this.count+=1;
//                console.log('this.count='+this.count)
//           },5000)
        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

       },
        data: {
            count:0,
            message: 'Hello Vue!'
        }
    })

</script>

</body>
</html>

================================================
FILE: 5.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="demo">
    {{message}}
    <parent-component></parent-component>
    <ul>
        <li v-for="(item,index,key) in  list">
             {{item}}
        </li>
    </ul>
</div>
<script >
    //创建一个子组件
    var Child=Vue.component("child-component",{
       //_isComponent:true,
        template:"<div>我是子组件 {{message}}</div>",
        props: ['message'],
    });
    //创建一个父组件
    Vue.component("parent-component",{
         _isComponent:true,
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
        mounted:function () {
           setTimeout(()=>{
                this.message.push(1);
           },1000)
        },
        template:"<div>{{message}}<child-component  :message='message'></child-component></div>", //注意元素模板只能有一个最上层元素,也就是用一个div包裹整个模板。
        components:{"child-component":Child},//进行子组件关联,注意child-component需要引号。
        data:function(){//组件中的data是一个函数
            return {
                message:[]
            }
        }
    })
    //创建一个vue的实例
    new Vue({
        el:"#demo",
        data: {
            list:[1,2,3,4,5,6,7,8],
            message: 'Hello Vue!'
        },
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点

        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: 6.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>


    


</head>
<body>


<script>
var string = 'abcde';
    var keys = Object.keys(string);
console.log(keys)


</script>

</body>
</html>

================================================
FILE: 6属性.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="demo"  :class="classA ? 'class-a' : 'class-b' ">
    {{message}}

</div>
<style>
    .class-a{
        background: red;
    }
    .class-b{
        background: red;
    }
</style>
<script >

    //创建一个vue的实例
    new Vue({
        el:"#demo",
        data: {
            classA:true,
            list:[1,2,3,4,5,6,7,8],
            message: 'Hello Vue!'
        },
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点

        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: 7for属性.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="demo"   >
  <ul>
      <li v-for="(item,index) in list">{{item}}</li>
  </ul>

</div>
<style>
    .class-a{
        background: red;
    }
    .class-b{
        background: red;
    }
</style>
<script >

    //创建一个vue的实例
    new Vue({
        el:"#demo",
        data: {
            classA:true,
            list:[1,2,3,4,5,6,7,8],

        },
        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点

        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: 8event属性.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="demo">
    <ul>
        <li v-for="(item,index) in list"    v-userdefined >
            <!--<img v-bind:src="item.url"/>-->
            <div></div>
        </li>
    </ul>

</div>
<style>
    .class-a {
        background: red;
    }

    .class-b {
        background: red;
    }
</style>
<script>
    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('userdefined', { //用户自定义指令
        // 当被绑定的元素插入到 DOM 中时……
        inserted: function (el) {
            // 聚焦元素
            el.addEventListener("click", function(){
                alert(1)
            });
        }
    })

    //创建一个vue的实例
    new Vue({
        el: "#demo",
        data: {
            userDefined:'userDefined',
            classA: true,
            list: [
                {
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
                {
                    url: 'http://i4.265g.com/images/201902/201902280644122663.jpg'
                },
            ],

        },
        methods: {
            clickEvent(){
                console.log('clickEvent')
            },
            clickEvent1(){
                console.log('clickEvent1')
            }

        },

        beforeCreate(){

        },
        created(){

        },
        beforeMount(){

        },
        mounted: ()=> { //挂载元素,获取到DOM节点

        },
        beforeUpdate(){

        },
        updated(){ //挂载元素,获取到DOM节点
        },
        beforeDestroy(){

        },
        destroyed(){

        },
    })
</script>

</body>
</html>

================================================
FILE: HTMLUnknownElement.html
================================================
<html>
    <head>
        <meta>
    </head>
    <body>
        <script>
            var el = document.createElement('add-options');
            console.log(el);
            console.log(window.HTMLUnknownElement);
            console.log( window.HTMLElement);

            console.log(el.constructor === window.HTMLUnknownElement ||
                el.constructor === window.HTMLElement)
               console.log(   /HTMLUnknownElement/.test('HTMLUnknownElement')  ); 

        </script>
    </body>
</html>

================================================
FILE: IS_REGEX_CAPTURING_BROKEN.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>


</head>


<script>
    var IS_REGEX_CAPTURING_BROKEN = false;
    'x'.replace(/x(.)?/g, function (m, g) {
        console.log(g)
        IS_REGEX_CAPTURING_BROKEN = g === '';
    });
    console.log(IS_REGEX_CAPTURING_BROKEN)
</script>
</body>
</html>

================================================
FILE: JS里charCodeAt()和fromCharCode().html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script>
    console.log('abc'.charCodeAt(1))
    console.log(String.fromCharCode(0x5D));



</script>

</body>
</html>

================================================
FILE: JS里charCodeAt()和fromCharCode()方法拓展应用:加密与解密.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p><textarea id="text1" name="textfield" cols="50" rows="5">钱庄王员外这个人怎么样?</textarea></p>
<input type="button" name="Button1" value="加密" onClick="text1.value = MySign.Encrypt(text1.value);">
<input type="button" name="Button2" value="解密" onClick="text1.value = MySign.UnEncrypt(text1.value);">

<script>
    //    JS实现客户端的网页加密解密技术,可用作选择性隐蔽展示。当然客户端的加密安全度是不能与服务器相提并论,肯定不能用于密码这类内容的加密,但对于一般级别的内容用作展示已经够了。
    //    JS加密与解密的解决方案有很多,本文则利用String对象的charCodeAt()方法和fromCharCode()方法对字符的ASCII编码进行获取和修改。
    //    加密,解密代码:
    var MySign = {
        //加密/解密次数
        num: 0,
        //加密
        Encrypt: function (Text) {
            this.num = this.num + 1;
            output = new String;
            alterText = new Array();
            varCost = new Array();
            TextSize = Text.length;
            for (i = 0; i < TextSize; i++) {
                idea = Math.round(Math.random() * 111) + 77;
                alterText[i] = Text.charCodeAt(i) + idea;
                varCost[i] = idea;
            }
            for (i = 0; i < TextSize; i++) {
                output += String.v(alterText[i], varCost[i]);
            }
            //text1.value = output;
            return output;
        },

        //解密
        UnEncrypt: function (Text) {
            if (this.num > 0) {
                this.num = this.num - 1;
                output = new String;
                alterText1 = new Array();
                varCost1 = new Array();
                TextSize = Text.length;
                for (i = 0; i < TextSize; i++) {
                    alterText[i] = Text.charCodeAt(i);
                    varCost[i] = Text.charCodeAt(i + 1);
                }
                for (i = 0; i < TextSize; i = i + 2) {
                    output += String.fromCharCode(alterText[i] - varCost[i]);
                }
                //text1.value = output;
                return output;
            }
        }
    };


    //测试代码
    var testString = "光头强,还不去砍树?";
    console.log(testString);

    var sign = MySign.Encrypt(testString); //凑ˆ妣o忕›ァ[還¬什³呯´硠S桲aチb
    var sign2 = MySign.UnEncrypt(sign); //光头强,还不去砍树?

    console.log(sign);
    console.log(sign2);

</script>

</body>
</html>

================================================
FILE: MessageChannel.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<iframe src="https://www.baidu.com/"></iframe>
  <script>
      var channel = new MessageChannel();
      var para = document.querySelector('p');

      var ifr = document.querySelector('iframe');
      var otherWindow = ifr.contentWindow;

      ifr.addEventListener("load", iframeLoaded, false);

      function iframeLoaded() {
          otherWindow.postMessage('Hello from the main page!', '*', [channel.port2]);
      }

      channel.port1.onmessage = handleMessage;
      function handleMessage(e) {
          para.innerHTML = e.data;
      }
  </script>
</body>
</html>

================================================
FILE: MessageChannel_0.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var channel = new MessageChannel();
    var port1 = channel.port1;
    var port2 = channel.port2;
    port1.onmessage = function(event) {
        console.log("port1收到来自port2的数据:" + event.data);
    }
    port2.onmessage = function(event) {
        console.log("port2收到来自port1的数据:" + event.data);
    }

    port1.postMessage("发送给port2");
    port2.postMessage("发送给port1");


</script>
</body>
</html>

================================================
FILE: MessageChannel_1.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    function random(min, max) {
        return min + Math.floor((max - min + 1) * Math.random());
    }

     //实例化对象
    var CalculatorChannel = new MessageChannel();

    var newsOne = CalculatorChannel.port1; //端口1
    var newsTow = CalculatorChannel.port2; //端口2


    newsOne.onmessage = function(event) {
        //console.log("port1收到来自port2的数据:" + event.data);
        var d = event.data;
        console.log('num1: ' + d.num1, 'num2: ' + d.num2);
        var sum = d.num1 + d.num2;
        //推送信息 更新  newsTow 推送信息 像消息体2推送信息
         newsOne.postMessage(sum)
    }



    newsTow.onmessage = function(event) {
        //console.log("port2收到来自port1的数据:" + event.data);
        console.log('结果为:' + event.data);
    }

    // 生成数字
    setInterval(() => {
        //像 消息体 1 推送信息
        newsTow.postMessage({
            num1: random(1, 10),
            num2: random(1, 10)
        });
    }, 1000);

</script>
</body>
</html>

================================================
FILE: Proxy_1.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      //Proxy 有两个参数,第一个是目标对象,第二个参数是设置Proxy的代理拦截方法
      var obj = new Proxy({}, {
          get: function (target, key, receiver) {
              console.log(`getting ${key}!`);
              return Reflect.get(target, key, receiver);
          },
          set: function (target, key, value, receiver) {
              console.log(`setting ${key}!`);
              return Reflect.set(target, key, value, receiver);
          }
      });
      obj.count = 1;
      obj.count
      //  setting count!
//      ++obj.count
  </script>
</body>
</html>

================================================
FILE: Proxy_2.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      //下面是另一个拦截读取属性行为的例子。
      var proxy = new Proxy({}, {
          get: function(target, property) {
              return 35;
          }
      });

      console.log(proxy.time) // 35
      console.log(proxy.name) // 35
      console.log(proxy.title) // 35
  </script>
</body>
</html>

================================================
FILE: Proxy_3.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      //如果handler没有设置任何拦截,那就等同于直接通向原对象。
      var target = {};
      var handler = {};
      var proxy = new Proxy(target, handler);
      proxy.a = 'b';
      console.log(target.a)
        // "b"
  </script>
</body>
</html>

================================================
FILE: Proxy_4.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      //get方法的用法,上文已经有一个例子,下面是另一个拦截读取操作的例子。
      var person = {
          name: "张三"
      };

      var proxy = new Proxy(person, {
          get: function(target, property) {
              if (property in target) {
                  return target[property];
              } else {
                  throw new ReferenceError("Property \"" + property + "\" does not exist.");
              }
          }
      });

      proxy.name // "张三"
      proxy.age // 抛出一个错误
  </script>
</body>
</html>

================================================
FILE: Proxy_5.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      //下面的例子使用get拦截,实现数组读取负数的索引。
      function createArray(...elements) {
          let handler = {
              get(target, propKey, receiver) {
                  let index = Number(propKey);
                  if (index < 0) {
                      propKey = String(target.length + index);
                  }
                  return Reflect.get(target, propKey, receiver);
              }
          };

          let target = [];
          target.push(...elements);
          return new Proxy(target, handler);
      }

      let arr = createArray('a', 'b', 'c');
      arr[-1] // c
  </script>
</body>
</html>

================================================
FILE: Proxy_6.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      var doc = new Proxy({}, {
          "get": function (oTarget, sKey) {

              console.log('get')
              return oTarget[sKey]
              return Reflect.get(oTarget, sKey);
          },
          "set": function (oTarget, sKey, vValue) {
              console.log('set')
               return Reflect.set(oTarget, sKey, vValue);
          },
          "deleteProperty": function (oTarget, sKey) {

              console.log('deleteProperty')

          },
          "enumerate": function (oTarget, sKey) {
              console.log('enumerate')

          },
          "ownKeys": function (oTarget, sKey) {
              console.log('ownKeys')

          },
          "has": function (oTarget, sKey) {
              console.log('has')
              console.log(oTarget)
              console.log(sKey)
              return oTarget[sKey]
          },
          "defineProperty": function (oTarget, sKey, oDesc) {
              console.log('defineProperty')
          },
          "getOwnPropertyDescriptor": function (oTarget, sKey) {
              console.log('getOwnPropertyDescriptor')
          },
      });
      doc.a=10;
      console.log(doc.a)
      console.log('a' in doc)

  </script>
</body>
</html>

================================================
FILE: README.md
================================================
 ***English document***: https://github.com/ygs-code/vue/blob/master/README_EN.md
#   开始

 vue源码业余时间差不多看了一年,以前在网上找帖子,发现很多帖子很零散,都是一部分一部分说,断章的很多,所以自己下定决定一行行看,经过自己坚持与努力,现在基本看完了   。这个vue源码逐行分析,我基本每一行都打上注释,加上整个框架的流程思维导图,基本上是小白也能看懂的vue源码了。

   说的非常的详细,里面的源码注释,有些是自己多年开发vue经验而获得的,有些是自己跑上下文程序知道的, 如果有不足的地方可以联系我QQ群 :302817612  修改,或者发邮件给我281113270@qq.com  谢谢。 如果大家觉得不错请动动小手指,帮我点一个satr,你们的支持就是我的动力。

vue 如何去看vue源码呢?其实mvvm源码并没有想象中那么神秘,从12年开始到至今mvvm发展已经有了十几年历史了,从以前直接操作dom的jq发展有十几年历史,但是这十几年历史发展,并没有多大的改变,思想还是那些,模块还是分为几大块:

## 1.模板转换:

 就是我们写的 vue 模板 或者是 react jsx 我们都可以理解是模板,然后他会经过 模板编译转换,像vue的话是进过一个方法paseHTML方法转换成ast树,里面的paseHTML用while 循环模板,然后经过正则 匹配到vue指令,还有vue的属性,事件方法等,收集到一个ast树中。

## 2.数据相应:

 vue是一个双数据相应的框架,底层用的是Object.defineProperty 监听和挟持数据改变,然后调用回调方法更新视图更新。双数据绑定原理是:obersve()方法判断value没有没有__ob___属性并且是不是Obersve实例化的,  value是不是Vonde实例化的,如果不是则调用Obersve 去把数据添加到观察者中,为数据添加__ob__属性, Obersve 则调用defineReactive方法,该方法是连接Dep和wacther方法的一个通道,利用Object.definpropty() 中的get和set方法 监听数据。get方法中是new Dep调用depend()。为dep添加一个wacther类,watcher中有个方法是更新视图的是run调用update去更新vonde 然后更新视图。 然后set方法就是调用dep中的notify 方法调用wacther中的run 更新视图

## 3.虚拟dom:

 vnode,在vue用vnode是通过 ast对象,在转义成vonde 需要渲染的函数,比如_c('div'  s(''))  等这类的函数,编译成vonde 虚拟dom。然后到updata更新数据 调用__patch__ 把vonde 通过diff算法变成正真正的dom元素。

##   4.diif算法:

​     vue2 的diff 算法是深度优先算法遍历,然后对比算法是通过 新旧的vnode对比先对比他们的基本属性,比如key 标签等,如果是相同则通过diff算法对比然后diff算法是新旧的vnode对比,然后有四个指针索引,两个新的vnode开始指针和新的 vnode 结束指针,两个旧的vnode开始指针和旧的 vnode 结束指针。然后先判断vnode是否为空,如果为空就往中间靠拢  开始的指针++  结束的指针 --。然后两头对比之后,在交叉对比,直到找不到相同的vnode之后如果多出的就删除,如果少的话就新增,然后对比完之后在更新到真实dom。





源码入口流程 vue源码解读流程 1.new Vue 调用的是 Vue.prototype._init  从该函数开始 经过 $options 参数合并之后 initLifecycle 初始化生命周期标志 初始化事件,初始化渲染函数。初始化状态就是数据。把数据添加到观察者中实现双数据绑定。

# new Vue实例化程序入口

```
 Vue.prototype._init = function (options) { //初始化函数
  //... 省略code
  
    initLifecycle(vm); //初始化生命周期 标志
            initEvents(vm); //初始化事件
            initRender(vm); // 初始化渲染
            callHook(vm, 'beforeCreate'); //触发beforeCreate钩子函数
            initInjections(vm); // resolve injections before data/props 在数据/道具之前解决注入问题 //初始化 inject
            initState(vm);  //    //初始化状态
            initProvide(vm); // resolve provide after data/props  解决后提供数据/道具  provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性,用于组件之间通信。
            callHook(vm, 'created'); //触发created钩子函数
  
  
  //... 省略code
    // 然后挂载模板,这里大概就是把模板转换成ast的入口
    vm.$mount(vm.$options.el);
  
 }
```



# 查找和挂载模板

​    vm.$mount 进入这个挂载模板方法,判断是否有 render 函数 或者是template,如果没有则使用el.outerHTML , 实际上这里就是要拿到模板的html内容

```
 Vue.prototype.$mount = function (el, hydrating) { 
   //... 省略code
       el = el && query(el); //获取dom
         if (!options.render) {
              if (template) {
              
              }else if (template.nodeType) { 
                  template = template.innerHTML;
              } else if (el) {
                template = getOuterHTML(el);
              }
         }
          
         
              // render 函数 也是 ast 转换 方法
                var ref = compileToFunctions(
                    template, //模板字符串
                    {
                        shouldDecodeNewlines: shouldDecodeNewlines, //flase //IE在属性值中编码换行,而其他浏览器则不会
                        shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref, //true chrome在a[href]中编码内容
                        delimiters: options.delimiters, //改变纯文本插入分隔符。修改指令的书写风格,比如默认是{{mgs}}  delimiters: ['${', '}']之后变成这样 ${mgs}
                        comments: options.comments //当设为 true 时,将会保留且渲染模板中的 HTML 注释。默认行为是舍弃它们。
                    },
                    this
                );
         
         
       
   
     //... 省略code
      //执行$mount方法     用$mount的方法把扩展挂载到dom上
        return mount.call(
            this,
            el, //真实的dom
            hydrating //undefined
        )
 
 }
```



# 编译AST和render函数

调用  Vue.prototype.$mount 方法之后 拿到模板之后 就会进入以下这几个方法,这几个方法用了很多函数式编程

```
compileToFunctions

createCompiler

createCompilerCreator

baseCompile

parse

parseHTML

```

这里比较重点的是parseHTML 他是  while (html) { //循环html 然后 然后经过正则 匹配到vue指令,还有vue的属性,事件方法等,收集到一个ast树中。

```
  function parseHTML(
        html, //字符串模板
        options //参数
    ) {
        var stack = []; // parseHTML 节点标签堆栈
        var expectHTML = options.expectHTML; //true
        var isUnaryTag$$1 = options.isUnaryTag || no; //函数匹配标签是否是 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen, link,meta,param,source,track,wbr'
        var canBeLeftOpenTag$$1 = options.canBeLeftOpenTag || no; //函数 //判断标签是否是 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
        var index = 0;
        var last, //
            lastTag; //
        console.log(html)



        while (html) { //循环html
            last = html; //
            // Make sure we're not in a plaintext content element like script/style 确保我们不在像脚本/样式这样的纯文本内容元素中
            if (
                !lastTag || //lastTag 不存在
                !isPlainTextElement(lastTag)  // 如果标签不是script,style,textarea
            ) {

                var textEnd = html.indexOf('<'); //匹配开始标签或者结束标签的位置
                if (textEnd === 0) { //标识是开始标签
                    // Comment:
                    if (comment.test(html)) { //匹配 开始字符串为<!--任何字符串,注释标签  如果匹配上
                        var commentEnd = html.indexOf('-->'); //获取注释标签的结束位置

                        if (commentEnd >= 0) { //如果注释标签结束标签位置大于0,则有注释内容
                            console.log(html.substring(4, commentEnd))
                            if (options.shouldKeepComment) { //shouldKeepComment为真时候。获取注释标签内容

                                //截取注释标签的内容
                                options.comment(html.substring(4, commentEnd));
                            }
                            //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                            advance(commentEnd + 3);
                            continue
                        }
                    }

                    //这里思路是先匹配到注释节点,在匹配到这里的ie浏览器加载样式节点
                    // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
                    if (conditionalComment.test(html)) {  //匹配开始为 <![ 字符串  <![endif]-->   匹配这样动态加ie浏览器的 字符串  <!--[if IE 8]><link href="ie8only.css" rel="stylesheet"><![endif]-->
                        //匹配ie浏览器动态加样式结束符号
                        var conditionalEnd = html.indexOf(']>');

                        if (conditionalEnd >= 0) {
                            //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                            advance(conditionalEnd + 2);
                            continue
                        }
                    }

                    // Doctype:
                    //匹配html的头文件 <!DOCTYPE html>
                    var doctypeMatch = html.match(doctype);
                    if (doctypeMatch) {
                        //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                        advance(doctypeMatch[0].length);
                        continue
                    }

                    // End tag:
                    //匹配开头必需是</ 后面可以忽略是任何字符串  ^<\\/((?:[a-zA-Z_][\\w\\-\\.]*\\:)?[a-zA-Z_][\\w\\-\\.]*)[^>]*>
                    var endTagMatch = html.match(endTag);
                    if (endTagMatch) {

                        var curIndex = index;
                        //标签分隔函数 while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                        advance(endTagMatch[0].length);
                        console.log(endTagMatch)
                        console.log(curIndex, index)
                        //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
                        //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                        //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                        parseEndTag(
                            endTagMatch[1],
                            curIndex,
                            index
                        );
                        continue
                    }

                    // Start tag:
                    //解析开始标记 标记开始标签
                    //  获取开始标签的名称,属性集合,开始位置和结束位置,并且返回该对象
                    var startTagMatch = parseStartTag();

                    if (startTagMatch) {
                        //把数组对象属性值循环变成对象,这样可以过滤相同的属性
                        //为parseHTML 节点标签堆栈 插入一个桟数据
                        //调用options.start  为parse函数 stack标签堆栈 添加一个标签
                        handleStartTag(startTagMatch);
                        //匹配tag标签是pre,textarea,并且第二个参数的第一个字符是回车键
                        if (shouldIgnoreFirstNewline(lastTag, html)) {
                            //去除回车键空格
                            advance(1);
                        }
                        continue
                    }
                }

                var text = (void 0),
                    rest = (void 0),
                    next = (void 0);
                if (textEnd >= 0) {

                    rest = html.slice(textEnd); //截取字符串  var textEnd = html.indexOf('<'); //匹配开始标签或者结束标签的位置
                    console.log(rest)

                    while (
                        !endTag.test(rest) && //匹配开头必需是</ 后面可以忽略是任何字符串
                        !startTagOpen.test(rest) && // 匹配开头必需是< 后面可以忽略是任何字符串
                        !comment.test(rest) && // 匹配 开始字符串为<!--任何字符串
                        !conditionalComment.test(rest) //匹配开始为 <![ 字符串
                    ) {
                        console.log(rest);


                        // < in plain text, be forgiving and treat it as text
                        // <在纯文本中,要宽容,把它当作文本来对待
                        next = rest.indexOf('<', 1); //匹配是否有多个<
                        if (next < 0) {
                            break
                        }
                        textEnd += next; //截取 索引位置
                        rest = html.slice(textEnd); //获取 < 字符串 <    获取他们两符号< 之间的字符串
                    }
                    text = html.substring(0, textEnd); //截取字符串 前面字符串到 <

                    //while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                    advance(textEnd);
                }

                if (textEnd < 0) { //都没有匹配到 < 符号 则表示纯文本
                    text = html; //出来text
                    html = ''; //把html至空 跳槽 while循环
                }

                if (options.chars && text) {
                    options.chars(text);
                }
            } else {
                //  处理是script,style,textarea
                var endTagLength = 0;
                var stackedTag = lastTag.toLowerCase();
                var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i'));
                var rest$1 = html.replace(reStackedTag, function (all, text, endTag) {
                    endTagLength = endTag.length;
                    if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') {
                        text = text
                            .replace(/<!\--([\s\S]*?)-->/g, '$1') // #7298
                            .replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1');
                    }
                    //匹配tag标签是pre,textarea,并且第二个参数的第一个字符是回车键
                    if (shouldIgnoreFirstNewline(stackedTag, text)) {
                        text = text.slice(1);
                    }
                    if (options.chars) {
                        options.chars(text);
                    }
                    return ''
                });
                index += html.length - rest$1.length;
                html = rest$1;
                parseEndTag(stackedTag, index - endTagLength, index);
            }

            if (html === last) {
                options.chars && options.chars(html);
                if ("development" !== 'production' && !stack.length && options.warn) {
                    options.warn(("Mal-formatted tag at end of template: \"" + html + "\""));
                }
                break
            }
        }






        // Clean up any remaining tags
        //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
        //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
        //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
        parseEndTag();
        //while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
        function advance(n) {
            index += n; //让索引叠加
            html = html.substring(n); //截取当前索引 和 后面的字符串。
        }

        //获取开始标签的名称,收集属性集合,开始位置和结束位置,并且返回该对象
        function parseStartTag() {
            var start = html.match(startTagOpen); //匹配开始标签 匹配开头必需是< 后面可以忽略是任何字符串  ^<((?:[a-zA-Z_][\\w\\-\\.]*\\:)?[a-zA-Z_][\\w\\-\\.]*)
            console.log(start)
            console.log(start[0].length)

            if (start) {
                var match = {
                    tagName: start[1], //标签名称
                    attrs: [], //标签属性集合
                    start: index //标签的开始索引
                };
                //标记开始标签的位置,截取了开始标签
                advance(start[0].length);
                var end, attr;

                while (
                    !(end = html.match(startTagClose)) //没有到 关闭标签 > 标签
                    && (attr = html.match(attribute)) //收集属性
                ) {
                    console.log(html)
                    //截取属性标签
                    advance(attr[0].length);
                    match.attrs.push(attr); //把属性收集到一个集合
                }
                if (end) {
                    match.unarySlash = end[1]; //如果是/>标签 则unarySlash 是/。 如果是>标签 则unarySlash 是空
                    console.log(end)

                    //截取掉开始标签,并且更新索引
                    advance(end[0].length);
                    match.end = index; //开始标签的结束位置
                    return match
                }
            }
        }

        //把数组对象属性值循环变成对象,这样可以过滤相同的属性
        //为parseHTML 节点标签堆栈 插入一个桟数据
        //调用options.start  为parse函数 stack标签堆栈 添加一个标签
        function handleStartTag(match) {
            /*
            * match = {
                     tagName: start[1], //标签名称
                     attrs: [], //标签属性集合
                     start: index, //开始标签的开始索引
                     match:index ,   //开始标签的 结束位置
                    unarySlash:'' //如果是/>标签 则unarySlash 是/。 如果是>标签 则unarySlash 是空
             };
            * */

            var tagName = match.tagName; //开始标签名称
            var unarySlash = match.unarySlash; //如果是/>标签 则unarySlash 是/。 如果是>标签 则unarySlash 是空
            console.log(expectHTML)
            console.log('lastTag==')
            console.log(lastTag)
            console.log(tagName)

            if (expectHTML) {   //true

                if (
                    lastTag === 'p' //上一个标签是p
                    /*
                      判断标签是否是
                     'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +
                     'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +
                     'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +
                     'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +
                     'title,tr,track'
                     */
                    && isNonPhrasingTag(tagName)
                ) {
                    //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
                    //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                    //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                    parseEndTag(lastTag);
                }
                if (
                    canBeLeftOpenTag$$1(tagName) &&   //判断标签是否是 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
                    lastTag === tagName //上一个标签和现在标签相同  <li><li> 编译成 <li></li>  但是这种情况是不会出现的 因为浏览器解析的时候会自动补全如果是<li>我是li标签<li> 浏览器自动解析成  <li>我是li标签</li><li> </li>
                ) {
                    //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
                    //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                    //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                    parseEndTag(tagName);
                }
            }

            var unary = isUnaryTag$$1(tagName) || //函数匹配标签是否是 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen, link,meta,param,source,track,wbr'
                !!unarySlash; //如果是/> 则为真

            var l = match.attrs.length;
            var attrs = new Array(l); //数组属性对象转换正真正的数组对象
            for (var i = 0; i < l; i++) {
                var args = match.attrs[i]; //获取属性对象
                // hackish work around FF bug https://bugzilla.mozilla.org/show_bug.cgi?id=369778
                //对FF bug进行黑客攻击:https://bugzilla.mozilla.org/show_bug.cgi?id=369778
                if (
                    IS_REGEX_CAPTURING_BROKEN &&  //这个应该是 火狐浏览器私有 标志
                    args[0].indexOf('""') === -1
                ) {
                    if (args[3] === '') {
                        delete args[3];
                    }
                    if (args[4] === '') {
                        delete args[4];
                    }
                    if (args[5] === '') {
                        delete args[5];
                    }
                }
                var value = args[3] || args[4] || args[5] || '';
                var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href'
                    ? options.shouldDecodeNewlinesForHref  // true chrome在a[href]中编码内容
                    : options.shouldDecodeNewlines;  //flase //IE在属性值中编码换行,而其他浏览器则不会

                attrs[i] = {  //把数组对象属性值循环变成对象,这样可以过滤相同的属性
                    name: args[1], //属性名称
                    //属性值
                    value: decodeAttr(value, shouldDecodeNewlines) //替换html 中的特殊符号,转义成js解析的字符串,替换 把   &lt;替换 <  , &gt; 替换 > , &quot;替换  ", &amp;替换 & , &#10;替换\n  ,&#9;替换\t

                };

            }

            console.log('==!unary==')
            console.log(!unary)

            if (!unary) { //如果不是单标签

                // 为parseHTML 节点标签堆栈 插入一个桟数据
                stack.push({ //标签堆栈
                    tag: tagName, //开始标签名称
                    lowerCasedTag: tagName.toLowerCase(), //变成小写记录标签
                    attrs: attrs //获取属性
                });
                //设置结束标签
                lastTag = tagName;
                console.log('== parseHTML handleStartTag stack==')
                console.log(stack)

            }


            //
            if (options.start) {

                //标签开始函数, 创建一个ast标签dom,  判断获取v-for属性是否存在如果有则转义 v-for指令 把for,alias,iterator1,iterator2属性添加到虚拟dom中
                //获取v-if属性,为el虚拟dom添加 v-if,v-eles,v-else-if 属性
                //获取v-once 指令属性,如果有有该属性 为虚拟dom标签 标记事件 只触发一次则销毁
                //校验属性的值,为el添加muted, events,nativeEvents,directives,  key, ref,slotName或者slotScope或者slot,component或者inlineTemplate 标志 属性
                // 标志当前的currentParent当前的 element
                //为parse函数 stack标签堆栈 添加一个标签
                options.start(
                    tagName,  //标签名称
                    attrs,  //标签属性
                    unary,  // 如果不是单标签则为真
                    match.start,  //开始标签的开始位置
                    match.end //开始标签的结束的位置
                );
            }


        }



        //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
        //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
        //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
        function parseEndTag(
            tagName,   //标签名称
            start,  //结束标签开始位置
            end    //结束标签结束位置
        ) {
            var pos,
                lowerCasedTagName;
            if (start == null) { //如果没有传开始位置
                start = index;    //就那当前索引
            }
            if (end == null) {  //如果没有传结束位置
                end = index;    //就那当前索引
            }

            if (tagName) { //结束标签名称
                lowerCasedTagName = tagName.toLowerCase(); //将字符串转化成小写
            }

            // Find the closest opened tag of the same type 查找最近打开的相同类型的标记
            if (tagName) {
                // 获取stack堆栈最近的匹配标签
                for (pos = stack.length - 1; pos >= 0; pos--) {
                    //找到最近的标签相等
                    if (stack[pos].lowerCasedTag === lowerCasedTagName) {
                        break
                    }
                }
            } else {
                // If no tag name is provided, clean shop
                //如果没有提供标签名称,请清理商店
                pos = 0;
            }


            if (pos >= 0) { //这里就获取到了stack堆栈的pos索引
                // Close all the open elements, up the stack 关闭所有打开的元素,向上堆栈
                console.log(pos)

                for (var i = stack.length - 1; i >= pos; i--) {

                    if ("development" !== 'production' && //如果stack中找不到tagName 标签的时候就输出警告日志,找不到标签
                        (i > pos || !tagName) &&
                        options.warn
                    ) {
                        options.warn(
                            ("tag <" + (stack[i].tag) + "> has no matching end tag.")
                        );
                    }
                    if (options.end) {
                        console.log(options.end)
                        //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                        //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                        options.end(
                            stack[i].tag,//结束标签名称
                            start, //结束标签开始位置
                            end //结束标签结束位置
                        );
                    }
                }
                // Remove the open elements from the stack
                //从堆栈中删除打开的元素
                // console.log(stack[pos].tag)
                // 为parseHTML 节点标签堆栈 出桟当前匹配到的标签
                stack.length = pos;
                //获取到上一个标签,就是当前节点的父节点
                lastTag = pos && stack[pos - 1].tag;
                console.log(stack)
                console.log(lastTag)




            } else if (lowerCasedTagName === 'br') {
                if (options.start) {
                    //标签开始函数, 创建一个ast标签dom,  判断获取v-for属性是否存在如果有则转义 v-for指令 把for,alias,iterator1,iterator2属性添加到虚拟dom中
                    //获取v-if属性,为el虚拟dom添加 v-if,v-eles,v-else-if 属性
                    //获取v-once 指令属性,如果有有该属性 为虚拟dom标签 标记事件 只触发一次则销毁
                    //校验属性的值,为el添加muted, events,nativeEvents,directives,  key, ref,slotName或者slotScope或者slot,component或者inlineTemplate 标志 属性
                    // 标志当前的currentParent当前的 element
                    //为parse函数 stack标签堆栈 添加一个标签
                    options.start(
                        tagName,
                        [], true,
                        start,
                        end
                    );
                }
            } else if (lowerCasedTagName === 'p') {
                if (options.start) {
                    //标签开始函数, 创建一个ast标签dom,  判断获取v-for属性是否存在如果有则转义 v-for指令 把for,alias,iterator1,iterator2属性添加到虚拟dom中
                    //获取v-if属性,为el虚拟dom添加 v-if,v-eles,v-else-if 属性
                    //获取v-once 指令属性,如果有有该属性 为虚拟dom标签 标记事件 只触发一次则销毁
                    //校验属性的值,为el添加muted, events,nativeEvents,directives,  key, ref,slotName或者slotScope或者slot,component或者inlineTemplate 标志 属性
                    // 标志当前的currentParent当前的 element
                    //为parse函数 stack标签堆栈 添加一个标签
                    options.start(
                        tagName,
                        [], false,
                        start,
                        end);
                }
                if (options.end) {
                    //删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                    //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                    options.end(
                        tagName,
                        start,
                        end
                    );
                }
            }
            console.log(lastTag)

        }
    }
```



一些匹配模板正则

```
  var onRE = /^@|^v-on:/;//判断是否是 @或者v-on:属性开头的
    var dirRE = /^v-|^@|^:/; //判断是否是 v-或者@或者:  属性开头的
    var forAliasRE = /([^]*?)\s+(?:in|of)\s+([^]*)/; //匹配 含有   字符串 in  字符串   或者  字符串 of  字符串
    var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/; //匹配上,  但是属于两边是 [{ , 点 , }]  所以匹配上   ,+字符串
    var stripParensRE = /^\(|\)$/g; //匹配括号 ()

    var argRE = /:(.*)$/; //匹配字符串是否含有:
    var bindRE = /^:|^v-bind:/; //开始匹配是 :或者是v-bind
    var modifierRE = /\.[^.]+/g; // 匹配以点开头的分组 不属于点 data.object.info.age  匹配到 ['.object','.info' , '.age']

    var decodeHTMLCached = cached(he.decode);    //获取 真是dom的textContent文本
```



## 双数据响应

 双数据绑定 入口 方法在defineReactive函数中 ,不管是 prop 还是 state 还是 属性监听方法 set 方法,还是initInjections 入口都是这里。

首先他会实例化         var dep = new Dep(); 依赖收集 Dep,get方法会添加一个   

​       //添加一个dep
​                    dep.depend();

​    if (childOb) {  //如果子节点存在也添加一个dep
​                        childOb.dep.depend();
​                        if (Array.isArray(value)) {  //判断是否是数组 如果是数组
​                            dependArray(value);   //则数组也添加dep
​                        }
​                    }



set 方法是触发更新视图的

//observe 添加 观察者

 // 然后在添加依赖

   childOb = !shallow && observe(newVal);
    //更新数据
    dep.notify();



```
    /**
     * Define a reactive property on an Object.
     * 在对象上定义一个无功属性。
     * 更新数据
     * 通过defineProperty的set方法去通知notify()订阅者subscribers有新的值修改
     * 添加观察者 get set方法
     */
    function defineReactive(obj, //对象
        key,//对象的key
        val, //监听的数据 返回的数据
        customSetter, //  日志函数
        shallow //是否要添加__ob__ 属性
    ) {
        //实例化一个主题对象,对象中有空的观察者列表
        var dep = new Dep();
        //获取描述属性
        var property = Object.getOwnPropertyDescriptor(obj, key);
        var _property = Object.getOwnPropertyNames(obj); //获取实力对象属性或者方法,包括定义的描述属性
        console.log(property);
        console.log(_property);

        if (property && property.configurable === false) {
            return
        }

        // cater for pre-defined getter/setters

        var getter = property && property.get;
        console.log('arguments.length=' + arguments.length)

        if (!getter && arguments.length === 2) {
            val = obj[key];
        }
        var setter = property && property.set;
        console.log(val)
        //判断value 是否有__ob__    实例化 dep对象,获取dep对象  为 value添加__ob__ 属性递归把val添加到观察者中  返回 new Observer 实例化的对象
        var childOb = !shallow && observe(val);
        //定义描述
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get: function reactiveGetter() {

                var value = getter ? getter.call(obj) : val;
                if (Dep.target) {  //Dep.target 静态标志 标志了Dep添加了Watcher 实例化的对象
                    //添加一个dep
                    dep.depend();
                    if (childOb) {  //如果子节点存在也添加一个dep
                        childOb.dep.depend();
                        if (Array.isArray(value)) {  //判断是否是数组 如果是数组
                            dependArray(value);   //则数组也添加dep
                        }
                    }
                }
                return value
            },
            set: function reactiveSetter(newVal) {
                var value = getter ? getter.call(obj) : val;
                /* eslint-disable no-self-compare  新旧值比较 如果是一样则不执行了*/
                if (newVal === value || (newVal !== newVal && value !== value)) {
                    return
                }
                /* eslint-enable no-self-compare
                 *   不是生产环境的情况下
                 * */
                if ("development" !== 'production' && customSetter) {
                    customSetter();
                }
                if (setter) {
                    //set 方法 设置新的值
                    setter.call(obj, newVal);
                } else {
                    //新的值直接给他
                    val = newVal;
                }
                console.log(newVal)

                //observe 添加 观察者
                childOb = !shallow && observe(newVal);
                //更新数据
                dep.notify();
            }
        });
    }

```







## 依赖收集 Dep

 在vue数据get获取中,谁读取了该数据,就把它收集起来,所以dep是一个集合,在数据set时,通过遍历dep去触发每个dep的notify方法通过视图更新
dep的主要功能是只作为收集,那在收集了依赖后,如何使视图更新呢
所以需要定义一个新的Watcher类,改类是会实现对视图的更新
 dep每收集的一个依赖实际就是一个Watcher

```
    //主题对象Dep构造函数  主要用于添加发布事件后,用户更新数据的 响应式原理之一函数
    var Dep = function Dep() {
        //uid  初始化为0
        this.id = uid++;
        /* 用来存放Watcher对象的数组 */
        this.subs = [];
    };

    Dep.prototype.addSub = function addSub(sub) {
        /* 在subs中添加一个Watcher对象 */
        this.subs.push(sub);
    };

    Dep.prototype.removeSub = function removeSub(sub) {
        /*删除 在subs中添加一个Watcher对象 */
        remove(this.subs, sub);
    };
    //this$1.deps[i].depend();
    //为Watcher 添加 为Watcher.newDeps.push(dep); 一个dep对象
    Dep.prototype.depend = function depend() {
        //添加一个dep    target 是Watcher dep就是dep对象
        if (Dep.target) {
            //像指令添加依赖项
            Dep.target.addDep(this);
        }
    };
    /* 通知所有Watcher对象更新视图 */
    Dep.prototype.notify = function notify() {
        // stabilize the subscriber list first
        var subs = this.subs.slice();
        for (var i = 0, l = subs.length; i < l; i++) {
            //更新数据
            subs[i].update();
        }
    };

    // the current target watcher being evaluated.
    // this is globally unique because there could be only one
    // watcher being evaluated at any time.
    //当前正在评估的目标监视程序。
    //这在全球是独一无二的,因为只有一个
    //观察者在任何时候都被评估。
    Dep.target = null;
    var targetStack = [];

    function pushTarget(_target) {
        //target 是Watcher dep就是dep对象
        if (Dep.target) { //静态标志 Dep当前是否有添加了target
            //添加一个pushTarget
            targetStack.push(Dep.target);
        }
        Dep.target = _target;
    }

    //
    function popTarget() {
        // 出盏一个pushTarget
        Dep.target = targetStack.pop();
    }
```

## 数据检测 Watcher

 Watcher的功能主要是接口到Dep的通知,然后调用update方法更新视图
在update方法中会触发回调,回调函数实际就是已生成render函数

在调用render函数是,函数里的值就会获取到已经更改后值,所以就会生成新的vnode
新的vnode生成后,就是patch的过程,用新的vnode与旧的vnode进行比对,最终将比对后的vnode转换为实际的dom添加到模板挂载节点上
新的模板挂载后,将旧的模板删除,这样视图就更新完成

```
     * *观察者分析表达式,收集依赖项,
     *并在表达式值更改时触发回调。
     *这用于$watch() api和指令。
     * 当前vue实例、updateComponent函数、空函数。
     */
    var Watcher = function Watcher(
        vm, //vm dom
        expOrFn,  //获取值的函数,或者是更新viwe试图函数
        cb, //回调函数,回调值给回调函数
        options, //参数
        isRenderWatcher//是否渲染过得观察者
    ) {
        console.log('====Watcher====')
        this.vm = vm;
        //是否是已经渲染过得观察者
        if (isRenderWatcher) { //把当前 Watcher 对象赋值给 vm._watcher上
            vm._watcher = this;
        }
        //把观察者添加到队列里面 当前Watcher添加到vue实例上
        vm._watchers.push(this);
        // options
        if (options) { //如果有参数
            this.deep = !!options.deep; //实际
            this.user = !!options.user; //用户
            this.lazy = !!options.lazy; //懒惰 ssr 渲染
            this.sync = !!options.sync; //如果是同步
        } else {

            this.deep = this.user = this.lazy = this.sync = false;
        }
        this.cb = cb; //回调函数
        this.id = ++uid$1; // uid for batching uid为批处理  监听者id
        this.active = true; //激活
        this.dirty = this.lazy; // for lazy watchers 对于懒惰的观察者
        this.deps = [];    // 观察者队列
        this.newDeps = []; // 新的观察者队列
        // 内容不可重复的数组对象
        this.depIds = new _Set();
        this.newDepIds = new _Set();
        // 把函数变成字符串形式
        this.expression = expOrFn.toString();
        // parse expression for getter
        //getter的解析表达式
        if (typeof expOrFn === 'function') {
            //获取值的函数
            this.getter = expOrFn;
        } else {
            //如果是keepAlive 组件则会走这里
            //path 因该是路由地址
            if (bailRE.test(path)) {  //  匹配上 返回 true     var bailRE = /[^\w.$]/;  //匹配不是 数字字母下划线 $符号   开头的为true
                return
            }

            // //匹配不上  path在已点分割
            // var segments = path.split('.');
            // return function (obj) {
            //
            //     for (var i = 0; i < segments.length; i++) {
            //         //如果有参数则返回真
            //         if (!obj) {
            //             return
            //         }
            //         //将对象中的一个key值 赋值给该对象 相当于 segments 以点拆分的数组做obj 的key
            //         obj = obj[segments[i]];
            //     }
            //     //否则返回一个对象
            //     return obj
            // }

            //匹配不是 数字字母下划线 $符号   开头的为true

            this.getter = parsePath(expOrFn);
            if (!this.getter) { //如果不存在 则给一个空的数组
                this.getter = function () {
                };
                "development" !== 'production' && warn(
                    "Failed watching path: \"" + expOrFn + "\" " +
                    'Watcher only accepts simple dot-delimited paths. ' +
                    'For full control, use a function instead.',
                    vm
                );
            }
        }
        this.value = this.lazy ?  //   lazy为真的的时候才能获取值  这个有是组件才为真
            undefined :
            this.get(); //计算getter,并重新收集依赖项。 获取值
    };

```

在Watcher实例构造函数执行时,会触发get
触发了get后就会该Watcher实例进行收集
update为接到Dep通知时触发的方法
update内会调用run方法
在run方法内会调用cb回调方法
cb回到方法实际就是模板编译时render方法





# 虚拟DOM

vue中的虚拟DOM,实际就是通过定义一个Vnode类,在该类上添加了dom的一些属性来标识一个dom

主要的作用是降低对实际dom的操作,来减轻对浏览器性能的耗费

```
 /*
     * 创建标准的vue vnode
     *
     * */

    var VNode = function VNode(
        tag, /*当前节点的标签名*/
        data, /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
        children, //子节点
        text, //文本
        elm, /*当前节点的dom */
        context, /*编译作用域*/
        componentOptions, /*组件的option选项*/
        asyncFactory/*异步工厂*/) {
        /*当前节点的标签名*/
        this.tag = tag;

        /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
        this.data = data;

        /*当前节点的子节点,是一个数组*/
        this.children = children;

        /*当前节点的文本*/
        this.text = text;

        /*当前虚拟节点对应的真实dom节点*/
        this.elm = elm;

        /*当前节点的名字空间*/
        this.ns = undefined;

        /*编译作用域 vm*/
        this.context = context;

        this.fnContext = undefined;
        this.fnOptions = undefined;
        this.fnScopeId = undefined;

        /*节点的key属性,被当作节点的标志,用以优化*/
        this.key = data && data.key;

        /*组件的option选项*/
        this.componentOptions = componentOptions;

        /*当前节点对应的组件的实例*/
        this.componentInstance = undefined;

        /*当前节点的父节点*/
        this.parent = undefined;

        /*简而言之就是是否为原生HTML或只是普通文本,innerHTML的时候为true,textContent的时候为false*/
        this.raw = false;

        /*静态节点标志*/
        this.isStatic = false;

        /*是否作为跟节点插入*/
        this.isRootInsert = true;

        /*是否为注释节点*/
        this.isComment = false;

        /*是否为克隆节点*/
        this.isCloned = false;

        /*是否有v-once指令*/
        this.isOnce = false;

        /*异步工厂*/
        this.asyncFactory = asyncFactory;

        this.asyncMeta = undefined;
        this.isAsyncPlaceholder = false;
    };
```

# diff算法

patch ,sameVnode, patchVnode ,updateChildren 这几个方法

入口是patch 然后调用sameVnode

```
    //sameVnode(oldVnode, vnode)2个节点的基本属性相同,那么就进入了2个节点的diff过程。
    function sameVnode(a, b) {
        return (

            a.key === b.key && (   //如果a的key 等于b的key
                (

                    a.tag === b.tag && // 如果a的tag 等于b的tag
                    a.isComment === b.isComment && // 如果a和b 都是注释节点
                    isDef(a.data) === isDef(b.data) && //如果a.data 和 b.data 都定义后,是组件,或者是都含有tag属性
                    sameInputType(a, b)   //相同的输入类型。判断a和b的属性是否相同
                ) || (
                    isTrue(a.isAsyncPlaceholder) && //判断是否是异步的
                    a.asyncFactory === b.asyncFactory &&
                    isUndef(b.asyncFactory.error)
                )
            )
        )
    }
```

如果调用sameVnode 条件成立 则进入patchVnode 方法,

patchVnode 方法主要是对vnode 进行增加和删除,主要还有key更新等。然后 判断 两个虚拟dom都不为空,并且他们不相等的时候oldCh !== ch 就进入updateChildren diff更新算法。

```
  // 对比 虚拟dom
        function patchVnode(
            oldVnode, // 旧的虚拟dom
            vnode,  // 新的虚拟dom
            insertedVnodeQueue,  // 删除虚拟dom队列
            removeOnly
        ) {
            if (oldVnode === vnode) { //如果他们相等
                return
            }

            var elm = vnode.elm = oldVnode.elm; //获取真实的dom

            // 判断是否有isAsyncPlaceholder 属性
            if (isTrue(oldVnode.isAsyncPlaceholder)) {
                //判断数据 是否不等于 undefined或者null
                if (isDef(vnode.asyncFactory.resolved)) {
                    // ssr 渲染
                    hydrate(oldVnode.elm, vnode, insertedVnodeQueue);
                } else {
                    vnode.isAsyncPlaceholder = true;
                }
                return
            }

            // reuse element for static trees.
            // note we only do this if the vnode is cloned -
            // if the new node is not cloned it means the render functions have been
            // reset by the hot-reload-api and we need to do a proper re-render.
            //为静态树重用元素。
            //注意,只有当vnode被克隆时,我们才这样做
            //如果新节点没有克隆,则表示渲染函数已经克隆
            //由hot-reload api重置,我们需要做一个适当的重新渲染。
            if (isTrue(vnode.isStatic) &&
                isTrue(oldVnode.isStatic) &&
                vnode.key === oldVnode.key &&
                (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
            ) {
                vnode.componentInstance = oldVnode.componentInstance;
                return
            }

            var i;
            var data = vnode.data;
            // 钩子函数
            if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
                i(oldVnode, vnode);
            }

            var oldCh = oldVnode.children;
            var ch = vnode.children;
            //循环组件实例 是否定义有 tag标签
            if (isDef(data) && isPatchable(vnode)) {
                // 触发钩子函数 更新钩子函数
                for (i = 0; i < cbs.update.length; ++i) {
                    cbs.update[i](oldVnode, vnode);
                }
                // 触发钩子函数
                if (isDef(i = data.hook) && isDef(i = i.update)) {
                    i(oldVnode, vnode);
                }
            }

            //如果是文本虚拟dom
            if (isUndef(vnode.text)) {
                // 两个虚拟dom都存在
                if (isDef(oldCh) && isDef(ch)) {
                    // 如果他们不相等
                    if (oldCh !== ch) {
                        // diff算法更新
                        updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly);
                    }
                } else if (isDef(ch)) {  // 如果是有新的虚拟dom
                    // 如果是文本虚拟dom 则 设置 空
                    if (isDef(oldVnode.text)) {
                        nodeOps.setTextContent(elm, '');
                    }
                    // 添加 vnode
                    addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
                } else if (isDef(oldCh)) { // 如果旧的有 新的虚拟dom没有则删除 虚拟dom
                    removeVnodes(elm, oldCh, 0, oldCh.length - 1);
                } else if (isDef(oldVnode.text)) { // 如果是文本虚拟dom则设置文本
                    nodeOps.setTextContent(elm, '');
                }


            } else if (oldVnode.text !== vnode.text) {
                // 如果新旧的文本不相同则设置文本
                nodeOps.setTextContent(elm, vnode.text);
            }
            if (isDef(data)) {
                // 触发钩子
                if (isDef(i = data.hook) && isDef(i = i.postpatch)) {
                    i(oldVnode, vnode);
                }
            }
        }

```



# ddif 算法updateChildren

diif算法,vue2 的diff 算法是深度优先算法遍历,然后对比算法是通过 新旧的vnode对比先对比他们的基本属性,比如key 标签等,如果是相同则通过diff算法对比然后diff算法是新旧的vnode对比,然后有四个指针索引,两个新的vnode开始指针和新的 vnode 结束指针,两个旧的vnode开始指针和旧的 vnode 结束指针。然后先判断vnode是否为空,如果为空就往中间靠拢  开始的指针++  结束的指针 --。然后两头对比之后,在交叉对比,直到找不到相同的vnode之后如果多出的就删除,如果少的话就新增,然后对比完之后 在调用patchVnode去增删虚拟dom。然后如果有vnode不相同在调用updateChildren,这样就做到深层递归,也叫深度优先搜索,然后子vnode没有了在更新到真实dom。 

```

        // ddif 算法
        function updateChildren(
            parentElm,  // 父亲dom
            oldCh,  // 旧的虚拟dom
            newCh,  // 新的虚拟dom
            insertedVnodeQueue,
            removeOnly
        ) {
            var oldStartIdx = 0;  // 旧的虚拟dom开始指针 
            var newStartIdx = 0; // 新的虚拟dom开始指针 
            var oldEndIdx = oldCh.length - 1; // 旧的虚拟dom结束指针 
            var newEndIdx = newCh.length - 1;// 新的虚拟dom结束指针 

            var oldStartVnode = oldCh[0];  // 旧的虚拟dom开始节点
            var newStartVnode = newCh[0]; // 新的虚拟dom开始节点

            var oldEndVnode = oldCh[oldEndIdx]; // 旧的虚拟dom结束节点
            var newEndVnode = newCh[newEndIdx];// 新的虚拟dom结束节点

            var oldKeyToIdx, idxInOld, vnodeToMove, refElm;

            // removeOnly is a special flag used only by <transition-group>
            // to ensure removed elements stay in correct relative positions
            // during leaving transitions
            var canMove = !removeOnly;

            {
                // 检查同一个兄弟节点是否有重复的key,如果有则发出警告日志
                checkDuplicateKeys(newCh);
            }

            /*
            diff 算法开始
              这里diff算法其实就是

            */
            while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {

                if (isUndef(oldStartVnode)) {
                    // 如果旧的开始节点不存在或者为空
                    // 如果旧的开始节点指针往中间偏移
                    oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
                } else if (isUndef(oldEndVnode)) {
                    // 如果旧的结束节点不存在或者为空
                    // 如果旧的结束节点指针往中间偏移
                    oldEndVnode = oldCh[--oldEndIdx];

                } else if (sameVnode(oldStartVnode, newStartVnode)) {   //sameVnode(oldVnode, vnode)2个节点的基本属性相同,那么就进入了2个节点的diff过程。



                    // 在对比下虚拟dom 
                    patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue);

                    //开始指针 两个都往中间偏移
                    oldStartVnode = oldCh[++oldStartIdx];
                    newStartVnode = newCh[++newStartIdx];

                } else if (sameVnode(oldEndVnode, newEndVnode)) {  //sameVnode(oldVnode, vnode)2个节点的基本属性相同,那么就进入了2个节点的diff过程。
                    // 在对比下虚拟dom 
                    patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue);
                    // 结束指针 两个都往中间偏移
                    oldEndVnode = oldCh[--oldEndIdx];
                    newEndVnode = newCh[--newEndIdx];
                } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right  //sameVnode(oldVnode, vnode)2个节点的基本属性相同,那么就进入了2个节点的diff过程。

                    // 交叉对比 深度优先算法入口
                    patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue);
                    // 交叉对比
                    canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));

                    oldStartVnode = oldCh[++oldStartIdx];
                    newEndVnode = newCh[--newEndIdx];
                } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
                    // 交叉对比
                    patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue);
                    // 交叉对比
                    canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
                    oldEndVnode = oldCh[--oldEndIdx];
                    newStartVnode = newCh[++newStartIdx];
                } else {
                    // 如果没有key 则给塔新的key
                    if (isUndef(oldKeyToIdx)) {

                        // 创建key 如果没有key 则用索引作为key
                        oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
                    }
                    
                    // 获取 旧的vnode key
                    idxInOld = isDef(newStartVnode.key)
                        ? oldKeyToIdx[newStartVnode.key]
                          // 查找旧的vnode key
                        : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx);
                        // 如果旧的 vnode key 未定义则创建新的真实dom
                    if (isUndef(idxInOld)) { // New element
                         //创建真实 dom 节点
                        createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
                    } else {

                        vnodeToMove = oldCh[idxInOld];
                        if (sameVnode(vnodeToMove, newStartVnode)) {
                            // 对比虚拟dom
                            patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue);
                            
                            oldCh[idxInOld] = undefined;
                            // 真实节点交换
                            canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm);
                        } else {
                            // same key but different element. treat as new element
                            // 创建真实dom
                            createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
                        }
                    }
                    newStartVnode = newCh[++newStartIdx];
                }
            }
            if (oldStartIdx > oldEndIdx) {
                refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
                // 添加虚拟dom
                addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
            } else if (newStartIdx > newEndIdx) {
                // 删除虚拟dom
                removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
            }
        }

```

具体看我源码和流程图,这里文字就不描述这么多了,流程图是下面这中的网盘,源码是vue.js,基本每一行都有注释

链接:https://pan.baidu.com/s/10IxV6mQ2TIwkRACKu2T0ng 
提取码:1fnu 


上面的vue.js 就是我基于vue源码中每行加有注释的vue.js, 其他文件就是我看vue.js源码的时候抽出来的vue.js 源码小demo。如果大家觉得不错请动动小手指,帮我点一个satr,你们的支持就是我的动力

 

 作者:姚观寿



最近失业了,想找一份前端开发工作,希望有朋友公司招聘的可以联系下我,谢谢你们,地点 深圳,或者远程都可以,前端构架,前端高级开发,组长职位都行。 我微信:18529531779  ,  helloTalk 号@18529531779,邮箱:281113270@qq.com 谢谢了。


================================================
FILE: README_EN.md
================================================
#   begin

 vue source code spare time to see almost a year, before looking for posts on the Internet, found that many posts are very scattered, are part of a part said, a lot of chapters, so they decided to see line by line, after their own persistence and efforts, now basically read. This vue source line by line analysis, I basically every line on the annotation, plus the whole framework of the process mind map, is basically a small white can also understand the vue source code.

Said very detailed, inside the source code notes, some are their own years of experience in developing vue, some are their own context program to know, if there are shortcomings can contact me QQ group: 302817612 modification, or send an email to me 281113270@qq.com thank you. If you feel good, please move your little finger to help me click a satr, your support is my motivation.

vue How to see vue source code? In fact, mvvm source code is not as mysterious as imagined, from the beginning of 12 years to the present mvvm development has more than a decade of history, from the previous direct operation of the dom jq development has more than a decade of history, but this decade of historical development, and there is not much change, the idea is still those, the module is still divided into several chunks:

## 1. Template conversion:

Is we write a vue template or react jsx we can understand is a template, and then it will go through the template compilation conversion, like vue is into a method paseHTML method converted into the ast tree, paseHTML inside the while loop template, Then through the RE match to the vue instructions, as well as vue properties, event methods, etc., collected into an ast tree.

## 2. Corresponding data:

vue is a dual data corresponding framework, the underlying use is Object.defineProperty to listen for and hijack data changes, and then call callback methods to update the view update. The principle of dual data binding is as follows: The obersve() method determines whether value has no __ob___ attribute and is not Obersve instantiated, and whether value is Vonde instantiated. If not, it calls Obersve to add the data to the observer and add the __ob__ attribute to the data. Obersve calls the defineReactive method, which is a channel connecting the Dep and wacther methods, and listens for data using the get and set methods in Object.definpropty(). In the get method, new Dep calls depend(). To add a wacther class to dep, watcher has a method to update the view. run calls update to update the vonde and then updates the view. Then the set method is to call the notify method in dep to call the run update view in wacther

## 3. Virtual dom:





vnode, used in vue, is via ast objects, escaped into vonde needs to render functions, such as _c('div' s('')) and such functions, compiled into vonde virtual dom. Then update the data to updata and call __patch__ to turn vonde into a true dom element through diff algorithm.

##   4.diif algorithm:

​    The diff algorithm of vue2 is depth-first traversal, and then the comparison algorithm compares the old vnode with the new vnode, first compares their basic attributes, such as key labels, etc. If they are the same, the diff algorithm compares the old Vnode with the new Vnode, and then there are four pointer indexes. Two new vnode start Pointers and two new vnode end Pointers, two old vnode start Pointers and old vnode end Pointers. Then first determine whether the vnode is empty, if it is empty, move to the center of the start pointer ++ end pointer --. Then after comparing the two sides, cross-compare until you can't find the same vnode, if there are more, delete it, if there are fewer, add it, and then update it to the real dom after comparing.



new Vue calls vue.prototype. _init. From this function, after merging with the $options parameter, initLifecycle initializes the life cycle, marking the initialization event, and initializing the rendering function. The initialization state is the data. Add data to the observer for double data binding.

# new Vue instantiates the program entry

```
 Vue.prototype._init = function (options) { //初始化函数
  //... 省略code
  
    initLifecycle(vm); //初始化生命周期 标志
            initEvents(vm); //初始化事件
            initRender(vm); // 初始化渲染
            callHook(vm, 'beforeCreate'); //触发beforeCreate钩子函数
            initInjections(vm); // resolve injections before data/props 在数据/道具之前解决注入问题 //初始化 inject
            initState(vm);  //    //初始化状态
            initProvide(vm); // resolve provide after data/props  解决后提供数据/道具  provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性,用于组件之间通信。
            callHook(vm, 'created'); //触发created钩子函数
  
  
  //... 省略code
    // 然后挂载模板,这里大概就是把模板转换成ast的入口
    vm.$mount(vm.$options.el);
  
 }
```



# Find and mount templates

 vm.$mount goes to the mount template method and determines whether it has a render function or a template, and if not, uses el.outerHTML, which is essentially getting the html content of the template

```
 Vue.prototype.$mount = function (el, hydrating) { 
   //... 省略code
       el = el && query(el); //获取dom
         if (!options.render) {
              if (template) {
              
              }else if (template.nodeType) { 
                  template = template.innerHTML;
              } else if (el) {
                template = getOuterHTML(el);
              }
         }
          
         
              // render 函数 也是 ast 转换 方法
                var ref = compileToFunctions(
                    template, //模板字符串
                    {
                        shouldDecodeNewlines: shouldDecodeNewlines, //flase //IE在属性值中编码换行,而其他浏览器则不会
                        shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref, //true chrome在a[href]中编码内容
                        delimiters: options.delimiters, //改变纯文本插入分隔符。修改指令的书写风格,比如默认是{{mgs}}  delimiters: ['${', '}']之后变成这样 ${mgs}
                        comments: options.comments //当设为 true 时,将会保留且渲染模板中的 HTML 注释。默认行为是舍弃它们。
                    },
                    this
                );
         
         
       
   
     //... 省略code
      //执行$mount方法     用$mount的方法把扩展挂载到dom上
        return mount.call(
            this,
            el, //真实的dom
            hydrating //undefined
        )
 
 }
```



# Compile the AST and render functions

After you call the Vue.prototype.$mount method and get the template, you enter the following methods, which use a lot of functional programming

```
compileToFunctions

createCompiler

createCompilerCreator

baseCompile

parse

parseHTML

```

The important thing here is that parseHTML is a while (html) {// loop through the html and then through the re match to the vue directive, as well as vue properties, event methods, etc., collected into an ast tree.

```
  function parseHTML(
        html, //字符串模板
        options //参数
    ) {
        var stack = []; // parseHTML 节点标签堆栈
        var expectHTML = options.expectHTML; //true
        var isUnaryTag$$1 = options.isUnaryTag || no; //函数匹配标签是否是 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen, link,meta,param,source,track,wbr'
        var canBeLeftOpenTag$$1 = options.canBeLeftOpenTag || no; //函数 //判断标签是否是 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
        var index = 0;
        var last, //
            lastTag; //
        console.log(html)



        while (html) { //循环html
            last = html; //
            // Make sure we're not in a plaintext content element like script/style 确保我们不在像脚本/样式这样的纯文本内容元素中
            if (
                !lastTag || //lastTag 不存在
                !isPlainTextElement(lastTag)  // 如果标签不是script,style,textarea
            ) {

                var textEnd = html.indexOf('<'); //匹配开始标签或者结束标签的位置
                if (textEnd === 0) { //标识是开始标签
                    // Comment:
                    if (comment.test(html)) { //匹配 开始字符串为<!--任何字符串,注释标签  如果匹配上
                        var commentEnd = html.indexOf('-->'); //获取注释标签的结束位置

                        if (commentEnd >= 0) { //如果注释标签结束标签位置大于0,则有注释内容
                            console.log(html.substring(4, commentEnd))
                            if (options.shouldKeepComment) { //shouldKeepComment为真时候。获取注释标签内容

                                //截取注释标签的内容
                                options.comment(html.substring(4, commentEnd));
                            }
                            //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                            advance(commentEnd + 3);
                            continue
                        }
                    }

                    //这里思路是先匹配到注释节点,在匹配到这里的ie浏览器加载样式节点
                    // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
                    if (conditionalComment.test(html)) {  //匹配开始为 <![ 字符串  <![endif]-->   匹配这样动态加ie浏览器的 字符串  <!--[if IE 8]><link href="ie8only.css" rel="stylesheet"><![endif]-->
                        //匹配ie浏览器动态加样式结束符号
                        var conditionalEnd = html.indexOf(']>');

                        if (conditionalEnd >= 0) {
                            //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                            advance(conditionalEnd + 2);
                            continue
                        }
                    }

                    // Doctype:
                    //匹配html的头文件 <!DOCTYPE html>
                    var doctypeMatch = html.match(doctype);
                    if (doctypeMatch) {
                        //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                        advance(doctypeMatch[0].length);
                        continue
                    }

                    // End tag:
                    //匹配开头必需是</ 后面可以忽略是任何字符串  ^<\\/((?:[a-zA-Z_][\\w\\-\\.]*\\:)?[a-zA-Z_][\\w\\-\\.]*)[^>]*>
                    var endTagMatch = html.match(endTag);
                    if (endTagMatch) {

                        var curIndex = index;
                        //标签分隔函数 while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                        advance(endTagMatch[0].length);
                        console.log(endTagMatch)
                        console.log(curIndex, index)
                        //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
                        //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                        //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                        parseEndTag(
                            endTagMatch[1],
                            curIndex,
                            index
                        );
                        continue
                    }

                    // Start tag:
                    //解析开始标记 标记开始标签
                    //  获取开始标签的名称,属性集合,开始位置和结束位置,并且返回该对象
                    var startTagMatch = parseStartTag();

                    if (startTagMatch) {
                        //把数组对象属性值循环变成对象,这样可以过滤相同的属性
                        //为parseHTML 节点标签堆栈 插入一个桟数据
                        //调用options.start  为parse函数 stack标签堆栈 添加一个标签
                        handleStartTag(startTagMatch);
                        //匹配tag标签是pre,textarea,并且第二个参数的第一个字符是回车键
                        if (shouldIgnoreFirstNewline(lastTag, html)) {
                            //去除回车键空格
                            advance(1);
                        }
                        continue
                    }
                }

                var text = (void 0),
                    rest = (void 0),
                    next = (void 0);
                if (textEnd >= 0) {

                    rest = html.slice(textEnd); //截取字符串  var textEnd = html.indexOf('<'); //匹配开始标签或者结束标签的位置
                    console.log(rest)

                    while (
                        !endTag.test(rest) && //匹配开头必需是</ 后面可以忽略是任何字符串
                        !startTagOpen.test(rest) && // 匹配开头必需是< 后面可以忽略是任何字符串
                        !comment.test(rest) && // 匹配 开始字符串为<!--任何字符串
                        !conditionalComment.test(rest) //匹配开始为 <![ 字符串
                    ) {
                        console.log(rest);


                        // < in plain text, be forgiving and treat it as text
                        // <在纯文本中,要宽容,把它当作文本来对待
                        next = rest.indexOf('<', 1); //匹配是否有多个<
                        if (next < 0) {
                            break
                        }
                        textEnd += next; //截取 索引位置
                        rest = html.slice(textEnd); //获取 < 字符串 <    获取他们两符号< 之间的字符串
                    }
                    text = html.substring(0, textEnd); //截取字符串 前面字符串到 <

                    //while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                    advance(textEnd);
                }

                if (textEnd < 0) { //都没有匹配到 < 符号 则表示纯文本
                    text = html; //出来text
                    html = ''; //把html至空 跳槽 while循环
                }

                if (options.chars && text) {
                    options.chars(text);
                }
            } else {
                //  处理是script,style,textarea
                var endTagLength = 0;
                var stackedTag = lastTag.toLowerCase();
                var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i'));
                var rest$1 = html.replace(reStackedTag, function (all, text, endTag) {
                    endTagLength = endTag.length;
                    if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') {
                        text = text
                            .replace(/<!\--([\s\S]*?)-->/g, '$1') // #7298
                            .replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1');
                    }
                    //匹配tag标签是pre,textarea,并且第二个参数的第一个字符是回车键
                    if (shouldIgnoreFirstNewline(stackedTag, text)) {
                        text = text.slice(1);
                    }
                    if (options.chars) {
                        options.chars(text);
                    }
                    return ''
                });
                index += html.length - rest$1.length;
                html = rest$1;
                parseEndTag(stackedTag, index - endTagLength, index);
            }

            if (html === last) {
                options.chars && options.chars(html);
                if ("development" !== 'production' && !stack.length && options.warn) {
                    options.warn(("Mal-formatted tag at end of template: \"" + html + "\""));
                }
                break
            }
        }






        // Clean up any remaining tags
        //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
        //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
        //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
        parseEndTag();
        //while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
        function advance(n) {
            index += n; //让索引叠加
            html = html.substring(n); //截取当前索引 和 后面的字符串。
        }

        //获取开始标签的名称,收集属性集合,开始位置和结束位置,并且返回该对象
        function parseStartTag() {
            var start = html.match(startTagOpen); //匹配开始标签 匹配开头必需是< 后面可以忽略是任何字符串  ^<((?:[a-zA-Z_][\\w\\-\\.]*\\:)?[a-zA-Z_][\\w\\-\\.]*)
            console.log(start)
            console.log(start[0].length)

            if (start) {
                var match = {
                    tagName: start[1], //标签名称
                    attrs: [], //标签属性集合
                    start: index //标签的开始索引
                };
                //标记开始标签的位置,截取了开始标签
                advance(start[0].length);
                var end, attr;

                while (
                    !(end = html.match(startTagClose)) //没有到 关闭标签 > 标签
                    && (attr = html.match(attribute)) //收集属性
                ) {
                    console.log(html)
                    //截取属性标签
                    advance(attr[0].length);
                    match.attrs.push(attr); //把属性收集到一个集合
                }
                if (end) {
                    match.unarySlash = end[1]; //如果是/>标签 则unarySlash 是/。 如果是>标签 则unarySlash 是空
                    console.log(end)

                    //截取掉开始标签,并且更新索引
                    advance(end[0].length);
                    match.end = index; //开始标签的结束位置
                    return match
                }
            }
        }

        //把数组对象属性值循环变成对象,这样可以过滤相同的属性
        //为parseHTML 节点标签堆栈 插入一个桟数据
        //调用options.start  为parse函数 stack标签堆栈 添加一个标签
        function handleStartTag(match) {
            /*
            * match = {
                     tagName: start[1], //标签名称
                     attrs: [], //标签属性集合
                     start: index, //开始标签的开始索引
                     match:index ,   //开始标签的 结束位置
                    unarySlash:'' //如果是/>标签 则unarySlash 是/。 如果是>标签 则unarySlash 是空
             };
            * */

            var tagName = match.tagName; //开始标签名称
            var unarySlash = match.unarySlash; //如果是/>标签 则unarySlash 是/。 如果是>标签 则unarySlash 是空
            console.log(expectHTML)
            console.log('lastTag==')
            console.log(lastTag)
            console.log(tagName)

            if (expectHTML) {   //true

                if (
                    lastTag === 'p' //上一个标签是p
                    /*
                      判断标签是否是
                     'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +
                     'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +
                     'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +
                     'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +
                     'title,tr,track'
                     */
                    && isNonPhrasingTag(tagName)
                ) {
                    //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
                    //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                    //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                    parseEndTag(lastTag);
                }
                if (
                    canBeLeftOpenTag$$1(tagName) &&   //判断标签是否是 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
                    lastTag === tagName //上一个标签和现在标签相同  <li><li> 编译成 <li></li>  但是这种情况是不会出现的 因为浏览器解析的时候会自动补全如果是<li>我是li标签<li> 浏览器自动解析成  <li>我是li标签</li><li> </li>
                ) {
                    //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
                    //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                    //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                    parseEndTag(tagName);
                }
            }

            var unary = isUnaryTag$$1(tagName) || //函数匹配标签是否是 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen, link,meta,param,source,track,wbr'
                !!unarySlash; //如果是/> 则为真

            var l = match.attrs.length;
            var attrs = new Array(l); //数组属性对象转换正真正的数组对象
            for (var i = 0; i < l; i++) {
                var args = match.attrs[i]; //获取属性对象
                // hackish work around FF bug https://bugzilla.mozilla.org/show_bug.cgi?id=369778
                //对FF bug进行黑客攻击:https://bugzilla.mozilla.org/show_bug.cgi?id=369778
                if (
                    IS_REGEX_CAPTURING_BROKEN &&  //这个应该是 火狐浏览器私有 标志
                    args[0].indexOf('""') === -1
                ) {
                    if (args[3] === '') {
                        delete args[3];
                    }
                    if (args[4] === '') {
                        delete args[4];
                    }
                    if (args[5] === '') {
                        delete args[5];
                    }
                }
                var value = args[3] || args[4] || args[5] || '';
                var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href'
                    ? options.shouldDecodeNewlinesForHref  // true chrome在a[href]中编码内容
                    : options.shouldDecodeNewlines;  //flase //IE在属性值中编码换行,而其他浏览器则不会

                attrs[i] = {  //把数组对象属性值循环变成对象,这样可以过滤相同的属性
                    name: args[1], //属性名称
                    //属性值
                    value: decodeAttr(value, shouldDecodeNewlines) //替换html 中的特殊符号,转义成js解析的字符串,替换 把   &lt;替换 <  , &gt; 替换 > , &quot;替换  ", &amp;替换 & , &#10;替换\n  ,&#9;替换\t

                };

            }

            console.log('==!unary==')
            console.log(!unary)

            if (!unary) { //如果不是单标签

                // 为parseHTML 节点标签堆栈 插入一个桟数据
                stack.push({ //标签堆栈
                    tag: tagName, //开始标签名称
                    lowerCasedTag: tagName.toLowerCase(), //变成小写记录标签
                    attrs: attrs //获取属性
                });
                //设置结束标签
                lastTag = tagName;
                console.log('== parseHTML handleStartTag stack==')
                console.log(stack)

            }


            //
            if (options.start) {

                //标签开始函数, 创建一个ast标签dom,  判断获取v-for属性是否存在如果有则转义 v-for指令 把for,alias,iterator1,iterator2属性添加到虚拟dom中
                //获取v-if属性,为el虚拟dom添加 v-if,v-eles,v-else-if 属性
                //获取v-once 指令属性,如果有有该属性 为虚拟dom标签 标记事件 只触发一次则销毁
                //校验属性的值,为el添加muted, events,nativeEvents,directives,  key, ref,slotName或者slotScope或者slot,component或者inlineTemplate 标志 属性
                // 标志当前的currentParent当前的 element
                //为parse函数 stack标签堆栈 添加一个标签
                options.start(
                    tagName,  //标签名称
                    attrs,  //标签属性
                    unary,  // 如果不是单标签则为真
                    match.start,  //开始标签的开始位置
                    match.end //开始标签的结束的位置
                );
            }


        }



        //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
        //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
        //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
        function parseEndTag(
            tagName,   //标签名称
            start,  //结束标签开始位置
            end    //结束标签结束位置
        ) {
            var pos,
                lowerCasedTagName;
            if (start == null) { //如果没有传开始位置
                start = index;    //就那当前索引
            }
            if (end == null) {  //如果没有传结束位置
                end = index;    //就那当前索引
            }

            if (tagName) { //结束标签名称
                lowerCasedTagName = tagName.toLowerCase(); //将字符串转化成小写
            }

            // Find the closest opened tag of the same type 查找最近打开的相同类型的标记
            if (tagName) {
                // 获取stack堆栈最近的匹配标签
                for (pos = stack.length - 1; pos >= 0; pos--) {
                    //找到最近的标签相等
                    if (stack[pos].lowerCasedTag === lowerCasedTagName) {
                        break
                    }
                }
            } else {
                // If no tag name is provided, clean shop
                //如果没有提供标签名称,请清理商店
                pos = 0;
            }


            if (pos >= 0) { //这里就获取到了stack堆栈的pos索引
                // Close all the open elements, up the stack 关闭所有打开的元素,向上堆栈
                console.log(pos)

                for (var i = stack.length - 1; i >= pos; i--) {

                    if ("development" !== 'production' && //如果stack中找不到tagName 标签的时候就输出警告日志,找不到标签
                        (i > pos || !tagName) &&
                        options.warn
                    ) {
                        options.warn(
                            ("tag <" + (stack[i].tag) + "> has no matching end tag.")
                        );
                    }
                    if (options.end) {
                        console.log(options.end)
                        //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                        //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                        options.end(
                            stack[i].tag,//结束标签名称
                            start, //结束标签开始位置
                            end //结束标签结束位置
                        );
                    }
                }
                // Remove the open elements from the stack
                //从堆栈中删除打开的元素
                // console.log(stack[pos].tag)
                // 为parseHTML 节点标签堆栈 出桟当前匹配到的标签
                stack.length = pos;
                //获取到上一个标签,就是当前节点的父节点
                lastTag = pos && stack[pos - 1].tag;
                console.log(stack)
                console.log(lastTag)




            } else if (lowerCasedTagName === 'br') {
                if (options.start) {
                    //标签开始函数, 创建一个ast标签dom,  判断获取v-for属性是否存在如果有则转义 v-for指令 把for,alias,iterator1,iterator2属性添加到虚拟dom中
                    //获取v-if属性,为el虚拟dom添加 v-if,v-eles,v-else-if 属性
                    //获取v-once 指令属性,如果有有该属性 为虚拟dom标签 标记事件 只触发一次则销毁
                    //校验属性的值,为el添加muted, events,nativeEvents,directives,  key, ref,slotName或者slotScope或者slot,component或者inlineTemplate 标志 属性
                    // 标志当前的currentParent当前的 element
                    //为parse函数 stack标签堆栈 添加一个标签
                    options.start(
                        tagName,
                        [], true,
                        start,
                        end
                    );
                }
            } else if (lowerCasedTagName === 'p') {
                if (options.start) {
                    //标签开始函数, 创建一个ast标签dom,  判断获取v-for属性是否存在如果有则转义 v-for指令 把for,alias,iterator1,iterator2属性添加到虚拟dom中
                    //获取v-if属性,为el虚拟dom添加 v-if,v-eles,v-else-if 属性
                    //获取v-once 指令属性,如果有有该属性 为虚拟dom标签 标记事件 只触发一次则销毁
                    //校验属性的值,为el添加muted, events,nativeEvents,directives,  key, ref,slotName或者slotScope或者slot,component或者inlineTemplate 标志 属性
                    // 标志当前的currentParent当前的 element
                    //为parse函数 stack标签堆栈 添加一个标签
                    options.start(
                        tagName,
                        [], false,
                        start,
                        end);
                }
                if (options.end) {
                    //删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                    //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                    options.end(
                        tagName,
                        start,
                        end
                    );
                }
            }
            console.log(lastTag)

        }
    }
```



一些匹配模板正则

```
  var onRE = /^@|^v-on:/;//判断是否是 @或者v-on:属性开头的
    var dirRE = /^v-|^@|^:/; //判断是否是 v-或者@或者:  属性开头的
    var forAliasRE = /([^]*?)\s+(?:in|of)\s+([^]*)/; //匹配 含有   字符串 in  字符串   或者  字符串 of  字符串
    var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/; //匹配上,  但是属于两边是 [{ , 点 , }]  所以匹配上   ,+字符串
    var stripParensRE = /^\(|\)$/g; //匹配括号 ()

    var argRE = /:(.*)$/; //匹配字符串是否含有:
    var bindRE = /^:|^v-bind:/; //开始匹配是 :或者是v-bind
    var modifierRE = /\.[^.]+/g; // 匹配以点开头的分组 不属于点 data.object.info.age  匹配到 ['.object','.info' , '.age']

    var decodeHTMLCached = cached(he.decode);    //获取 真是dom的textContent文本
```



## Dual data response

The dual data binding entry method is in the defineReactive function, whether it is prop or state or property listener set method or initInjections entry.

First he instantiates var dep = new Dep(); Depending on the collection Dep, the get method adds one

​       //添加一个dep
​                    dep.depend();

​    if (childOb) {  //如果子节点存在也添加一个dep
​                        childOb.dep.depend();
​                        if (Array.isArray(value)) {  //判断是否是数组 如果是数组
​                            dependArray(value);   //则数组也添加dep
​                        }
​                    }



The set method is the trigger for updating the view

//observe Add an observer

// Then add dependencies

   childOb = !shallow && observe(newVal);
    //更新数据
    dep.notify();



```
    /**
     * Define a reactive property on an Object.
     * 在对象上定义一个无功属性。
     * 更新数据
     * 通过defineProperty的set方法去通知notify()订阅者subscribers有新的值修改
     * 添加观察者 get set方法
     */
    function defineReactive(obj, //对象
        key,//对象的key
        val, //监听的数据 返回的数据
        customSetter, //  日志函数
        shallow //是否要添加__ob__ 属性
    ) {
        //实例化一个主题对象,对象中有空的观察者列表
        var dep = new Dep();
        //获取描述属性
        var property = Object.getOwnPropertyDescriptor(obj, key);
        var _property = Object.getOwnPropertyNames(obj); //获取实力对象属性或者方法,包括定义的描述属性
        console.log(property);
        console.log(_property);

        if (property && property.configurable === false) {
            return
        }

        // cater for pre-defined getter/setters

        var getter = property && property.get;
        console.log('arguments.length=' + arguments.length)

        if (!getter && arguments.length === 2) {
            val = obj[key];
        }
        var setter = property && property.set;
        console.log(val)
        //判断value 是否有__ob__    实例化 dep对象,获取dep对象  为 value添加__ob__ 属性递归把val添加到观察者中  返回 new Observer 实例化的对象
        var childOb = !shallow && observe(val);
        //定义描述
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get: function reactiveGetter() {

                var value = getter ? getter.call(obj) : val;
                if (Dep.target) {  //Dep.target 静态标志 标志了Dep添加了Watcher 实例化的对象
                    //添加一个dep
                    dep.depend();
                    if (childOb) {  //如果子节点存在也添加一个dep
                        childOb.dep.depend();
                        if (Array.isArray(value)) {  //判断是否是数组 如果是数组
                            dependArray(value);   //则数组也添加dep
                        }
                    }
                }
                return value
            },
            set: function reactiveSetter(newVal) {
                var value = getter ? getter.call(obj) : val;
                /* eslint-disable no-self-compare  新旧值比较 如果是一样则不执行了*/
                if (newVal === value || (newVal !== newVal && value !== value)) {
                    return
                }
                /* eslint-enable no-self-compare
                 *   不是生产环境的情况下
                 * */
                if ("development" !== 'production' && customSetter) {
                    customSetter();
                }
                if (setter) {
                    //set 方法 设置新的值
                    setter.call(obj, newVal);
                } else {
                    //新的值直接给他
                    val = newVal;
                }
                console.log(newVal)

                //observe 添加 观察者
                childOb = !shallow && observe(newVal);
                //更新数据
                dep.notify();
            }
        });
    }

```







## Depends on collecting Dep

 In the vue data get, whoever reads the data will collect it. Therefore, dep is a set. When the data is set, the notify method of each dep is triggered by traversing the dep to update through the view
The main function of dep is to act only as a collection, so how do you update the view after collecting the dependencies
So you need to define a new Watcher class that will update the view
Each dependency collected by the dep is actually a Watcher

```
    //主题对象Dep构造函数  主要用于添加发布事件后,用户更新数据的 响应式原理之一函数
    var Dep = function Dep() {
        //uid  初始化为0
        this.id = uid++;
        /* 用来存放Watcher对象的数组 */
        this.subs = [];
    };

    Dep.prototype.addSub = function addSub(sub) {
        /* 在subs中添加一个Watcher对象 */
        this.subs.push(sub);
    };

    Dep.prototype.removeSub = function removeSub(sub) {
        /*删除 在subs中添加一个Watcher对象 */
        remove(this.subs, sub);
    };
    //this$1.deps[i].depend();
    //为Watcher 添加 为Watcher.newDeps.push(dep); 一个dep对象
    Dep.prototype.depend = function depend() {
        //添加一个dep    target 是Watcher dep就是dep对象
        if (Dep.target) {
            //像指令添加依赖项
            Dep.target.addDep(this);
        }
    };
    /* 通知所有Watcher对象更新视图 */
    Dep.prototype.notify = function notify() {
        // stabilize the subscriber list first
        var subs = this.subs.slice();
        for (var i = 0, l = subs.length; i < l; i++) {
            //更新数据
            subs[i].update();
        }
    };

    // the current target watcher being evaluated.
    // this is globally unique because there could be only one
    // watcher being evaluated at any time.
    //当前正在评估的目标监视程序。
    //这在全球是独一无二的,因为只有一个
    //观察者在任何时候都被评估。
    Dep.target = null;
    var targetStack = [];

    function pushTarget(_target) {
        //target 是Watcher dep就是dep对象
        if (Dep.target) { //静态标志 Dep当前是否有添加了target
            //添加一个pushTarget
            targetStack.push(Dep.target);
        }
        Dep.target = _target;
    }

    //
    function popTarget() {
        // 出盏一个pushTarget
        Dep.target = targetStack.pop();
    }
```

## Data detection Watcher

 Watcher's main function is to interface to the Dep notification, and then call the update method to update the view
The callback is triggered in the update method, and the callback function is actually the generated render function

Upon calling the render function, the values in the function will get the changed value, so a new vnode will be generated
After the new vnode is generated, it is the patch process. The new vnode is compared with the old vnode. Finally, the vnode after comparison is converted into the actual dom and added to the node to which the template is mounted
After the new template is mounted, delete the old template so that the view is updated

```
     * *观察者分析表达式,收集依赖项,
     *并在表达式值更改时触发回调。
     *这用于$watch() api和指令。
     * 当前vue实例、updateComponent函数、空函数。
     */
    var Watcher = function Watcher(
        vm, //vm dom
        expOrFn,  //获取值的函数,或者是更新viwe试图函数
        cb, //回调函数,回调值给回调函数
        options, //参数
        isRenderWatcher//是否渲染过得观察者
    ) {
        console.log('====Watcher====')
        this.vm = vm;
        //是否是已经渲染过得观察者
        if (isRenderWatcher) { //把当前 Watcher 对象赋值给 vm._watcher上
            vm._watcher = this;
        }
        //把观察者添加到队列里面 当前Watcher添加到vue实例上
        vm._watchers.push(this);
        // options
        if (options) { //如果有参数
            this.deep = !!options.deep; //实际
            this.user = !!options.user; //用户
            this.lazy = !!options.lazy; //懒惰 ssr 渲染
            this.sync = !!options.sync; //如果是同步
        } else {

            this.deep = this.user = this.lazy = this.sync = false;
        }
        this.cb = cb; //回调函数
        this.id = ++uid$1; // uid for batching uid为批处理  监听者id
        this.active = true; //激活
        this.dirty = this.lazy; // for lazy watchers 对于懒惰的观察者
        this.deps = [];    // 观察者队列
        this.newDeps = []; // 新的观察者队列
        // 内容不可重复的数组对象
        this.depIds = new _Set();
        this.newDepIds = new _Set();
        // 把函数变成字符串形式
        this.expression = expOrFn.toString();
        // parse expression for getter
        //getter的解析表达式
        if (typeof expOrFn === 'function') {
            //获取值的函数
            this.getter = expOrFn;
        } else {
            //如果是keepAlive 组件则会走这里
            //path 因该是路由地址
            if (bailRE.test(path)) {  //  匹配上 返回 true     var bailRE = /[^\w.$]/;  //匹配不是 数字字母下划线 $符号   开头的为true
                return
            }

            // //匹配不上  path在已点分割
            // var segments = path.split('.');
            // return function (obj) {
            //
            //     for (var i = 0; i < segments.length; i++) {
            //         //如果有参数则返回真
            //         if (!obj) {
            //             return
            //         }
            //         //将对象中的一个key值 赋值给该对象 相当于 segments 以点拆分的数组做obj 的key
            //         obj = obj[segments[i]];
            //     }
            //     //否则返回一个对象
            //     return obj
            // }

            //匹配不是 数字字母下划线 $符号   开头的为true

            this.getter = parsePath(expOrFn);
            if (!this.getter) { //如果不存在 则给一个空的数组
                this.getter = function () {
                };
                "development" !== 'production' && warn(
                    "Failed watching path: \"" + expOrFn + "\" " +
                    'Watcher only accepts simple dot-delimited paths. ' +
                    'For full control, use a function instead.',
                    vm
                );
            }
        }
        this.value = this.lazy ?  //   lazy为真的的时候才能获取值  这个有是组件才为真
            undefined :
            this.get(); //计算getter,并重新收集依赖项。 获取值
    };

```

get is triggered when the Watcher instance constructor executes
After the get is triggered, the Watcher instance is collected
update is the method that is triggered when a Dep notification is received
The run method is called in update
The cb callback method is called inside the run method
The cb back method is actually the template compile-time render method





# Virtual DOM

Virtual DOM in vue actually identifies a dom by defining a Vnode class and adding some dom attributes to the class

The main effect is to reduce the manipulation of the actual dom to reduce the cost of browser performance

```
 /*
     * 创建标准的vue vnode
     *
     * */

    var VNode = function VNode(
        tag, /*当前节点的标签名*/
        data, /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
        children, //子节点
        text, //文本
        elm, /*当前节点的dom */
        context, /*编译作用域*/
        componentOptions, /*组件的option选项*/
        asyncFactory/*异步工厂*/) {
        /*当前节点的标签名*/
        this.tag = tag;

        /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
        this.data = data;

        /*当前节点的子节点,是一个数组*/
        this.children = children;

        /*当前节点的文本*/
        this.text = text;

        /*当前虚拟节点对应的真实dom节点*/
        this.elm = elm;

        /*当前节点的名字空间*/
        this.ns = undefined;

        /*编译作用域 vm*/
        this.context = context;

        this.fnContext = undefined;
        this.fnOptions = undefined;
        this.fnScopeId = undefined;

        /*节点的key属性,被当作节点的标志,用以优化*/
        this.key = data && data.key;

        /*组件的option选项*/
        this.componentOptions = componentOptions;

        /*当前节点对应的组件的实例*/
        this.componentInstance = undefined;

        /*当前节点的父节点*/
        this.parent = undefined;

        /*简而言之就是是否为原生HTML或只是普通文本,innerHTML的时候为true,textContent的时候为false*/
        this.raw = false;

        /*静态节点标志*/
        this.isStatic = false;

        /*是否作为跟节点插入*/
        this.isRootInsert = true;

        /*是否为注释节点*/
        this.isComment = false;

        /*是否为克隆节点*/
        this.isCloned = false;

        /*是否有v-once指令*/
        this.isOnce = false;

        /*异步工厂*/
        this.asyncFactory = asyncFactory;

        this.asyncMeta = undefined;
        this.isAsyncPlaceholder = false;
    };
```

# diff algorithm

patch, sameVnode, patchVnode, updateChildren these methods

The entry point is patch and then the sameVnode is called

```
    //sameVnode(oldVnode, vnode)2个节点的基本属性相同,那么就进入了2个节点的diff过程。
    function sameVnode(a, b) {
        return (

            a.key === b.key && (   //如果a的key 等于b的key
                (

                    a.tag === b.tag && // 如果a的tag 等于b的tag
                    a.isComment === b.isComment && // 如果a和b 都是注释节点
                    isDef(a.data) === isDef(b.data) && //如果a.data 和 b.data 都定义后,是组件,或者是都含有tag属性
                    sameInputType(a, b)   //相同的输入类型。判断a和b的属性是否相同
                ) || (
                    isTrue(a.isAsyncPlaceholder) && //判断是否是异步的
                    a.asyncFactory === b.asyncFactory &&
                    isUndef(b.asyncFactory.error)
                )
            )
        )
    }
```

If the sameVnode condition is valid, enter the patchVnode method.

The patchVnode method is mainly used to add and delete vnodes and update key. Then determine when neither virtual dom is empty and they are not equal oldCh! == ch enters the updateChildren diff update algorithm.

```
  // 对比 虚拟dom
        function patchVnode(
            oldVnode, // 旧的虚拟dom
            vnode,  // 新的虚拟dom
            insertedVnodeQueue,  // 删除虚拟dom队列
            removeOnly
        ) {
            if (oldVnode === vnode) { //如果他们相等
                return
            }

            var elm = vnode.elm = oldVnode.elm; //获取真实的dom

            // 判断是否有isAsyncPlaceholder 属性
            if (isTrue(oldVnode.isAsyncPlaceholder)) {
                //判断数据 是否不等于 undefined或者null
                if (isDef(vnode.asyncFactory.resolved)) {
                    // ssr 渲染
                    hydrate(oldVnode.elm, vnode, insertedVnodeQueue);
                } else {
                    vnode.isAsyncPlaceholder = true;
                }
                return
            }

            // reuse element for static trees.
            // note we only do this if the vnode is cloned -
            // if the new node is not cloned it means the render functions have been
            // reset by the hot-reload-api and we need to do a proper re-render.
            //为静态树重用元素。
            //注意,只有当vnode被克隆时,我们才这样做
            //如果新节点没有克隆,则表示渲染函数已经克隆
            //由hot-reload api重置,我们需要做一个适当的重新渲染。
            if (isTrue(vnode.isStatic) &&
                isTrue(oldVnode.isStatic) &&
                vnode.key === oldVnode.key &&
                (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
            ) {
                vnode.componentInstance = oldVnode.componentInstance;
                return
            }

            var i;
            var data = vnode.data;
            // 钩子函数
            if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
                i(oldVnode, vnode);
            }

            var oldCh = oldVnode.children;
            var ch = vnode.children;
            //循环组件实例 是否定义有 tag标签
            if (isDef(data) && isPatchable(vnode)) {
                // 触发钩子函数 更新钩子函数
                for (i = 0; i < cbs.update.length; ++i) {
                    cbs.update[i](oldVnode, vnode);
                }
                // 触发钩子函数
                if (isDef(i = data.hook) && isDef(i = i.update)) {
                    i(oldVnode, vnode);
                }
            }

            //如果是文本虚拟dom
            if (isUndef(vnode.text)) {
                // 两个虚拟dom都存在
                if (isDef(oldCh) && isDef(ch)) {
                    // 如果他们不相等
                    if (oldCh !== ch) {
                        // diff算法更新
                        updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly);
                    }
                } else if (isDef(ch)) {  // 如果是有新的虚拟dom
                    // 如果是文本虚拟dom 则 设置 空
                    if (isDef(oldVnode.text)) {
                        nodeOps.setTextContent(elm, '');
                    }
                    // 添加 vnode
                    addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
                } else if (isDef(oldCh)) { // 如果旧的有 新的虚拟dom没有则删除 虚拟dom
                    removeVnodes(elm, oldCh, 0, oldCh.length - 1);
                } else if (isDef(oldVnode.text)) { // 如果是文本虚拟dom则设置文本
                    nodeOps.setTextContent(elm, '');
                }


            } else if (oldVnode.text !== vnode.text) {
                // 如果新旧的文本不相同则设置文本
                nodeOps.setTextContent(elm, vnode.text);
            }
            if (isDef(data)) {
                // 触发钩子
                if (isDef(i = data.hook) && isDef(i = i.postpatch)) {
                    i(oldVnode, vnode);
                }
            }
        }

```



# ddif algorithm updateChildren

diif algorithm, the diff algorithm of vue2 is a depth-first algorithm for traversal, and then the comparison algorithm compares the old vnode with the new vnode, first compares their basic attributes, such as key labels, etc. If they are the same, the diff algorithm compares the old Vnode with the new Vnode, and then has four pointer indexes. Two new vnode start Pointers and two new vnode end Pointers, two old vnode start Pointers and old vnode end Pointers. Then first determine whether the vnode is empty, if it is empty, move to the center of the start pointer ++ end pointer --. Then, after comparing the two sides, cross-compare until the same vnode is not found. If there are more Vnodes, delete them; if there are fewer, add them. After comparing, call patchVnode to add or delete virtual dom. Then if there are Vnodes that are not the same, updateChildren is called, so deep recursion, also called depth-first search, is done, and then the child Vnodes are not updated to the real dom.

```

        // ddif 算法
        function updateChildren(
            parentElm,  // 父亲dom
            oldCh,  // 旧的虚拟dom
            newCh,  // 新的虚拟dom
            insertedVnodeQueue,
            removeOnly
        ) {
            var oldStartIdx = 0;  // 旧的虚拟dom开始指针 
            var newStartIdx = 0; // 新的虚拟dom开始指针 
            var oldEndIdx = oldCh.length - 1; // 旧的虚拟dom结束指针 
            var newEndIdx = newCh.length - 1;// 新的虚拟dom结束指针 

            var oldStartVnode = oldCh[0];  // 旧的虚拟dom开始节点
            var newStartVnode = newCh[0]; // 新的虚拟dom开始节点

            var oldEndVnode = oldCh[oldEndIdx]; // 旧的虚拟dom结束节点
            var newEndVnode = newCh[newEndIdx];// 新的虚拟dom结束节点

            var oldKeyToIdx, idxInOld, vnodeToMove, refElm;

            // removeOnly is a special flag used only by <transition-group>
            // to ensure removed elements stay in correct relative positions
            // during leaving transitions
            var canMove = !removeOnly;

            {
                // 检查同一个兄弟节点是否有重复的key,如果有则发出警告日志
                checkDuplicateKeys(newCh);
            }

            /*
            diff 算法开始
              这里diff算法其实就是

            */
            while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {

                if (isUndef(oldStartVnode)) {
                    // 如果旧的开始节点不存在或者为空
                    // 如果旧的开始节点指针往中间偏移
                    oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
                } else if (isUndef(oldEndVnode)) {
                    // 如果旧的结束节点不存在或者为空
                    // 如果旧的结束节点指针往中间偏移
                    oldEndVnode = oldCh[--oldEndIdx];

                } else if (sameVnode(oldStartVnode, newStartVnode)) {   //sameVnode(oldVnode, vnode)2个节点的基本属性相同,那么就进入了2个节点的diff过程。



                    // 在对比下虚拟dom 
                    patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue);

                    //开始指针 两个都往中间偏移
                    oldStartVnode = oldCh[++oldStartIdx];
                    newStartVnode = newCh[++newStartIdx];

                } else if (sameVnode(oldEndVnode, newEndVnode)) {  //sameVnode(oldVnode, vnode)2个节点的基本属性相同,那么就进入了2个节点的diff过程。
                    // 在对比下虚拟dom 
                    patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue);
                    // 结束指针 两个都往中间偏移
                    oldEndVnode = oldCh[--oldEndIdx];
                    newEndVnode = newCh[--newEndIdx];
                } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right  //sameVnode(oldVnode, vnode)2个节点的基本属性相同,那么就进入了2个节点的diff过程。

                    // 交叉对比 深度优先算法入口
                    patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue);
                    // 交叉对比
                    canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));

                    oldStartVnode = oldCh[++oldStartIdx];
                    newEndVnode = newCh[--newEndIdx];
                } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
                    // 交叉对比
                    patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue);
                    // 交叉对比
                    canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
                    oldEndVnode = oldCh[--oldEndIdx];
                    newStartVnode = newCh[++newStartIdx];
                } else {
                    // 如果没有key 则给塔新的key
                    if (isUndef(oldKeyToIdx)) {

                        // 创建key 如果没有key 则用索引作为key
                        oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
                    }
                    
                    // 获取 旧的vnode key
                    idxInOld = isDef(newStartVnode.key)
                        ? oldKeyToIdx[newStartVnode.key]
                          // 查找旧的vnode key
                        : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx);
                        // 如果旧的 vnode key 未定义则创建新的真实dom
                    if (isUndef(idxInOld)) { // New element
                         //创建真实 dom 节点
                        createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
                    } else {

                        vnodeToMove = oldCh[idxInOld];
                        if (sameVnode(vnodeToMove, newStartVnode)) {
                            // 对比虚拟dom
                            patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue);
                            
                            oldCh[idxInOld] = undefined;
                            // 真实节点交换
                            canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm);
                        } else {
                            // same key but different element. treat as new element
                            // 创建真实dom
                            createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
                        }
                    }
                    newStartVnode = newCh[++newStartIdx];
                }
            }
            if (oldStartIdx > oldEndIdx) {
                refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
                // 添加虚拟dom
                addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
            } else if (newStartIdx > newEndIdx) {
                // 删除虚拟dom
                removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
            }
        }

```

Specifically look at my source code and flow chart, here the text does not describe so much, the flow chart is the following network disk, source code is vue.js, basically every line has comments

link:https://pan.baidu.com/s/10IxV6mQ2TIwkRACKu2T0ng 
password:1fnu 

The above vue.js is my vue.js based on each line of vue source code with comments, and the other files are the vue.js source code small demo that I pulled out when I looked at Vue.js source code. If you feel good, please move your little finger to help me click a satr, your support is my motivation,thank you



Author: Yao Guanshou





I've been unemployed recently and I'm looking for a front-end development job. I hope any friends whose companies are recruiting can contact me. Thank you. The location can be Shenzhen or remote. Front-end architecture, senior front-end development, and team leader positions are all fine. My wechat: 18529531779, helloTalk account @18529531779, email: 281113270@qq.com, thank you.


================================================
FILE: Reflect.ownKeys.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      //Reflect.ownKeys 可以读取到Object.defineProperty 定义的key, 而Object.keys 只能定义到对象的key
      var obj = {}
      Object.defineProperty(obj, 'method1', {
          value: function () {
              alert("Non enumerable property");
          },
          enumerable: false
      })

      console.log(Object.keys(obj))
      // []
      console.log(Reflect.ownKeys(obj))
      // ["method1"]

      const obj1 = {
          id1: 42,
          id2: 13
      };
      console.log(Object.keys(obj1))
      // ['id1', 'id2']
      console.log(Reflect.ownKeys(obj1))
      // ['id1', 'id2']


  </script>
</body>
</html>

================================================
FILE: Set.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    let set6 = new Set([1, 2, 2, 3, 4, 3, 5])
    console.log('distinct 1:', set6)

    //数组去重
    let arr1 = [1, 2, 3, 4]
    let arr2 = [2, 3, 4, 5, 6]
    let set7 = new Set([...arr1, ...arr2])
    console.log('distinct 2:', set7)

    //1.向Set中添加元素。
    let set1 = new Set()
    set1.add(1)
    set1.add(2)
    set1.add(3)
    console.log('added:', set1)


    //3.判断某元素是否存在。

    let set2 = new Set()
    set2.add(1)
    set2.add(2)
    set2.add(3)
    set2.delete(1)
    console.log('has(1):', set2.has(1))
    console.log('has(2):', set2.has(2))

    //4.清除所有元素。
    let set3 = new Set()
    set3.add(1)
    set3.add(2)
    set3.add(3)
    set3.clear()
    console.log('cleared:', set3)

    //数组去重
    let arr=[1,111,33,11,11,11,34,5,6,7,4];
    console.log( new Set([...arr]))
    console.log([...arr])
</script>
</body>
</html>

================================================
FILE: StrictChecking.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      const num1 = parseInt("10", 2)
      const num2 = parseFloat("10", 2);
      const total = num1+ num2
      console.log(num1)
      console.log(num2)
      console.log(total)

  </script>
</body>
</html>

================================================
FILE: String方法之fromCharCode()和charCodeAt().html
================================================
<!DOCTYPE html>
<html class="ui-page-login">

<head>


</head>


<body>
<script type="text/javascript">
    function toUnicodeFun(data){
        if(data == '' || typeof data == 'undefined') return '请输入汉字';
        var str ='';
        for(var i=0;i<data.length;i++){
            str+="\\u"+data.charCodeAt(i).toString(16);
        }
        return str;
    }

    var resultUnicode = toUnicodeFun('中国'); // \u4e2d\u56fd
    console.log(resultUnicode);


    function toChineseWords(data){
        if(data == '' || typeof data == 'undefined') return '请输入十六进制unicode';
        data = data.split("\\u");
        var str ='';
        for(var i=0;i<data.length;i++){
            str+=String.fromCharCode(parseInt(data[i],16).toString(10));
        }
        return str;
    }

    var resultChineseWords = toChineseWords("\u4e2d\u56fd");
    console.log(resultChineseWords);//中国
    document.write(String.fromCharCode(0x7C))

</script>

</body>

</html>

================================================
FILE: Symbol.html
================================================
<!DOCTYPE html>
<html class="ui-page-login">

	<head>
		 

	</head>

 
	<body>
	   <script type="text/javascript">
	   	//声明是唯一的数据,类型和string字符串一样,不能添加属性
	   	    let s = Symbol();

            console.log(typeof s)
	   </script>

	</body>

</html>

================================================
FILE: Symbol1.html
================================================
<!DOCTYPE html>
<html class="ui-page-login">

	<head>
		 

	</head>

 
	<body>
	   <script type="text/javascript">
	   	   let s1 = Symbol('foo');
	   	   let s2 =Symbol('bar');
	   	   console.log(s1.toString());
	   	   console.log(s2.toString());
	   	   console.log(Symbol);
	   	   

	   </script>

	</body>

</html>

================================================
FILE: Symbol2.html
================================================
<!DOCTYPE html>
<html class="ui-page-login">

<head>


</head>


<body>
<script type="text/javascript">
    console.log(Symbol("bar"))


    console.log(Symbol("bar"))
    console.log(Symbol("bar")===Symbol("bar"))




</script>

</body>

</html>

================================================
FILE: Symbol3.html
================================================
<!DOCTYPE html>
<html class="ui-page-login">

<head>


</head>


<body>
<script type="text/javascript">
    let s1 = Symbol.for("foo");
    console.log(Symbol.keyFor(s1)) // "foo"

    let s2 = Symbol("foo");
    console.log(Symbol.keyFor(s2)) // undefined




</script>

</body>

</html>

================================================
FILE: _Set.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>

<script >
   let value = new Set();

   value.add('11')
    console.log(value)
   //如果没有他自己写一个
   _Set = (function () {
       function Set() {
           this.set = Object.create(null);
       }

       Set.prototype.has = function has(key) {
           return this.set[key] === true
       };
       Set.prototype.add = function add(key) {
           this.set[key] = true;
       };
       Set.prototype.clear = function clear() {
           this.set = Object.create(null);
       };

       return Set;
   }());

   let _value = new _Set();

   _value.add('11')
   console.log(_value)
</script>

</body>
</html>

================================================
FILE: __proto__.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <script>
        var obj={};
        console.log(obj.__proto__)
        obj.__proto__ = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']
        console.log(obj.__proto__)
   </script>
</body>
</html>

================================================
FILE: _c.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body></body>
</html>
<script>
    var lovingVue = 123;
    var select = 3;
    var isClass = true;

    var _c = function (tag, astObject) {
        debugger;
        console.log(tag, astObject)
    }
    var _v = function (tag, astObject) {
        debugger;
        console.log(tag, astObject)
    }
    var _s = function (tag, astObject) {
        debugger;
        console.log(tag, astObject)
    }


    var fn=(function anonymous() {
//        <div id="demo">
//                <i></i>
//                <span style="width: 100px;">
//
//                span 节点
//        {{isClass}}
//        </span>
//
//        </div>
        with (this) {
            return _c(
                    'div',
                    {attrs: {"id": "demo"}},
                    [
                        _c('i'),
                        _v(" "),
                        _c('span',
                                {staticStyle: {"width": "100px"}},
                                [
                                    _v("\n\n              span 节点\n               " + _s(isClass) + "\n        ")
                                ]
                        )
                    ]
            )
        }
    })

    fn()

    (function anonymous() {
//        <div id="demo">
//                <span style="width: 100px;">
//
//                span 节点
//        <i  :class="{'class-a':classA}">i标签</i>
//                <b>{{lovingVue}}</b>
//        </span>
//        <span  style="width: 100px;">
//
//                {{select}}
//        </span>
//
//        </div>
        with (this) {
            return _c(
                    'div',
                    {attrs: {"id": "demo"}},
                    [
                        _c(
                                'span',
                                {
                                    staticStyle: {"width": "100px"}
                                },
                                [
                                    _v("\n\n              span 节点\n              "),
                                    _c(
                                            'i',
                                            {
                                                class: {'class-a': classA}
                                            },
                                            [
                                                _v("i标签")
                                            ]
                                    ),
                                    _v(" ")
                                    ,
                                    _c(
                                            'b',
                                            [
                                                _v(_s(lovingVue))
                                            ]
                                    )
                                ]
                        ),
                        _v(" "),
                        _c(
                                'span',
                                {
                                    staticStyle: {"width": "100px"}
                                },
                                [
                                    _v("\n\n              " + _s(select) + "\n        ")
                                ]
                        )
                    ]
            )
        }
    })

</script>

================================================
FILE: add.txt
================================================


================================================
FILE: add1.txt
================================================
add111111111111111111111

================================================
FILE: advance.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      var html ='<!--我是注释节点--><div>节点</div>';
      var index=0;
      //索引
      function advance(n) {
          index += n;
          html = html.substring(n);
          console.log(html)
      }

      console.log(html.length)
      advance(13)


  </script>
</body>
</html>

================================================
FILE: appear.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
</html>

================================================
FILE: argMatch.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script >

    
    function transformString(name) {
        var argRE = /:(.*)$/; //匹配字符串是否含有:
        var argMatch = name.match(argRE);  //匹配字符串是否含有:
        let index =argMatch&&argMatch.index;
        var arg = argMatch && argMatch[1];
        console.log(argMatch)
        console.log(arg)
        if (arg) {
            name = name.slice(0, -(arg.length + 1));
        }
        if (index) {
            name = name.slice(0, index+ 1);
        }
        return name;
    }
    console.log(transformString('abc'))
    console.log(transformString('abc:efg:hig'))

</script>
</body>
</html>

================================================
FILE: arrObj.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <script>
          var arr=[];
          arr['1-11-3']=13456;
          arr.push(10)
          for(var i=0; i<arr.length; i++){
              console.log(arr[i])
          }
        console.log(arr)
    </script>
</body>
</html>

================================================
FILE: array.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>

<script >
    var obj={
         arr:[
             {
                 arr_1:[
                     {a:1},
                     {a:2},
                     {a:3},
                     {a:4},
                     {a:5},

                 ]
             },
             {
                 arr_1:[
                     {a:11},
                     {a:12},
                     {a:13},
                     {a:14},
                     {a:15},
                 ]
             },
             {
                 arr_1:[
                     {a:21},
                     {a:22},
                     {a:23},
                     {a:24},
                     {a:25},
                 ]
             },
             {
                 arr_1:[
                     {a:31},
                     {a:32},
                     {a:33},
                     {a:34},
                     {a:35},
                 ]
             },
             {
                 arr_1:[
                     {a:41},
                     {a:42},
                     {a:43},
                     {a:44},
                     {a:45},
                 ]
             },
             {
                 arr_1:[
                     {a:51},
                     {a:52},
                     {a:53},
                     {a:54},
                     {a:55},
                 ]
             },
         ]
    }
    let newArr=obj.arr.map(item=>{
      let arr= item.arr_1.map(_item=>{
            return _item.a;
        })
        return arr.join(',')
    })
    console.log(newArr.join(',').split(','))
    var arr1=[1,2,3,4,5];
    arr1.length=3;
    console.log(arr1)

</script>

</body>
</html>

================================================
FILE: attribute.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
    var html="    class='classA' :html='abc' :class='[a?aa:bb,cc]'  style='width:100px' ></div>"
    var index=0
    function advance(n) {
        index += n; //让索引叠加
        html = html.substring(n); //截取当前索引 和 后面的字符串。
    }
    while (html){
        var    attr = html.match(attribute)
        advance(attr[0].length);
        console.log(attr)
    }

</script>
</body>
</html>

================================================
FILE: bailRE.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    /**
     * Parse simple path.
     * 解析简单路径。
     */
    var bailRE = /[^\w.$]/;  //匹配任何字符 已点结束的字符串

    function parsePath(path) {
         console.log(bailRE.test(path))
        if (bailRE.test(path)) {  //匹配上 返回 true
            return
        }
        //匹配不上  path在已点分割
        var segments = path.split('.');
        return function (obj) {

            for (var i = 0; i < segments.length; i++) {
                //如果有参数则返回真
                if (!obj) {
                    return
                }
                //将对象中的一个key值 赋值给该对象 相当于 obj = obj[segments[segments.length-1]];
                obj = obj[segments[i]];
            }
            //否则返回一个对象
            return obj
        }
    }
    parsePath('~123@')
</script>
</body>
</html>

================================================
FILE: buildRegex.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var defaultTagRE = /\{\{((?:.|\n)+?)\}\}/g; //匹配viwe 视图中的{{指令}}
    var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; //匹配特殊符号  - 或者. 或者* 或者+ 或者? 或者^ 或者$ 或者{ 或者} 或者( 或者) 或者| 或者[ 或者] 或者/ 或者\


    /*
     * var aFn =  cached(function(string){
     *
     *      return string
     *  })
     * aFn(string1);
     * aFn(string2);
     * aFn(string);
     * aFn(string1);
     * aFn(string2);
     *
     * aFn 函数会多次调用 里面就能体现了
     *  用对象去缓存记录函数
     * */

    function cached(fn) {
        var cache = Object.create(null);
        return (function cachedFn(str) {
            var hit = cache[str];
            return hit || (cache[str] = fn(str))
        })
    }

    var buildRegex = cached(function (delimiters) {
        var open = delimiters[0].replace(regexEscapeRE, '\\$&'); //$&	与 regexp 相匹配的子串。 这里的意思是遇到了特殊符号的时候在正则里面需要替换加多一个/斜杠
        var close = delimiters[1].replace(regexEscapeRE, '\\$&');
        return new RegExp(open + '((?:.|\\n)+?)' + close, 'g') // 匹配开始的open +任意字符或者换行符+ close 全局匹配
    });
//   console.log(buildRegex(['${','}']))
//    console.log( 'abcdef${name},asdfsadf${age}'.match(buildRegex(['${','}'])));
    var data={
        name:'yao',
        age:28,
    }

    let str = '姓名${name},年龄${age}'.replace(/\$\{((?:.|\\n)+?\})/g,function (val) {
       let reg =  "(?<=\\{)[^\\}]+";  //匹配括号中的内容
        return data[val.match(reg)[0]]
    })
    console.log(str)

</script>
</body>
</html>

================================================
FILE: callbacks.slice(0).html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      var callbacks=[1]
      var callback  = callbacks.slice(0)
      console.log(callback)
  </script>
</body>
</html>

================================================
FILE: camelize.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 <script>
     /**
      * Camelize a hyphen-delimited string.
      * 用连字符分隔的字符串。
      * camelize = cachedFn(str)=>{ var hit = cache[str];
    return hit || (cache[str] = fn(str))}

      调用一个camelize 存一个建进来 调用两次 如果建一样就返回 hit
      可以让这样的的属性 v-model 变成 vModel
      */
     var camelizeRE = /-(\w)/g;
     var camelize = cached(function (str) {
         return str.replace(camelizeRE, function (_, c) {
             return c ? c.toUpperCase() : '';
         })
     });
     /*
      * var aFn =  cached(function(string){
      *
      *      return string
      *  })
      * aFn(string1);
      * aFn(string2);
      * aFn(string);
      * aFn(string1);
      * aFn(string2);
      *
      * aFn 函数会多次调用 里面就能体现了
      *  用对象去缓存记录函数
      * */

     function cached(fn) {
         var cache = Object.create(null);
         return (function cachedFn(str) {
             var hit = cache[str];
             return hit || (cache[str] = fn(str))
         })
     }
     console.log(camelize('abc-defg'))
 </script>
</body>
</html>

================================================
FILE: charCodeAt.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    function charCodeAt(exp) {
        let c, i;
        for (i = 0; i < exp.length; i++) {
            c = exp.charCodeAt(i);
            switch (c) {
                case 0x22:
                    console.log('c=' + c)
                    console.log('0x22=' + exp[i])
                    break                   // 匹配 "
                case 0x27:
                    console.log('c=' + c)
                    console.log('0x27=' + exp[i])
                    break                   // 匹配 '
                case 0x60:
                    console.log('c=' + c)
                    console.log('0x60=' + exp[i])
                    break                  // 匹配 `
                case 0x28:
                    console.log('c=' + c)
                    console.log('0x28=' + exp[i])
                    break                 // 匹配 (
                case 0x29:
                    console.log('c=' + c)
                    console.log('0x29=' + exp[i])
                    break                 //匹配  )
                case 0x5B:
                    console.log('c=' + c)
                    console.log('0x5B=' + exp[i])
                    break                // 匹配 [
                case 0x5D:
                    console.log('c=' + c)
                    console.log('0x5D=' + exp[i])
                    break                // 匹配 ]
                case 0x7B:
                    console.log('c=' + c)
                    console.log('0x7B=' + exp[i])
                    break                 // 匹配 {
                case 0x7D:
                    console.log('c=' + c)
                    console.log('exp[i]=' + exp[i])
                    break                 // }
                case 0x5C:              //   匹配   \
                    console.log('c=' + c)
                    console.log('0x5C=' + exp[i])
                    break
                case 0x2f:              //   匹配   /
                    console.log('c=' + c)
                    console.log('0x5C=' + exp[i])
                    break
                case 0x7C:              //   匹配   pipe
                    console.log('c=' + c)
                    console.log('0x7C=' + exp[i])
                        debugger;
                    break


            }
        }

    }

    charCodeAt(`"'()[]{} '\\ \/ pipe`);
</script>
</body>
</html>

================================================
FILE: classify.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <script>
     var  classify = (function classifyRE() {
           var classifyRE = /(?:^|[-_])(\w)/g;
//非捕获  匹配不分组 。 就是可以包含,但是不匹配上
           //过滤掉class中的 -_ 符号 并且把字母开头的改成大写
         return  function (str) {
               return str.replace(classifyRE,
                       function (c) {
                           return c.toUpperCase();
                       }).replace(/[-_]/g, '');
           };
       })();
       console.log(classify('abcd_efg-ijk'))

   </script>
</body>
</html>

================================================
FILE: classifyRE.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<input id="input" type="text"  >
    <script>
        //非捕获  匹配不分组 。 就是可以包含,但是不匹配上

//        var classifyRE = /(?:^|[-_])(\w)/g;
//
//        var classify = function (str) {
//            return str.replace(classifyRE,
//                function (c) {
//                    return c.toUpperCase();
//                }).replace(/[-_]/g, '');
//        };

//        console.log(classify(':'))
//
//     console.log(/^[a-zA-Z][\w-]*$/.test('-a5675675'))
//        console.log(/^[a-zA-Z][\w-]*$/.test('a-5675675'))
//        console.log(/^[\w]*$/.test('5675'))
//
//
//        console.log(/([a-zA-Z])|(\d{1,2})/.test(100000))

        var input = document.getElementById('input');

        input.onkeyup=function () {
            this.value=checkData(this.value)

        }


        function  checkData(string) {
            var pattern1 = /([a-zA-Z]+)|([\u4e00-\u9fa5]+)/g;
            var pattern2 =/^\d{1,2}$/;
  
            if(!isNaN(new Number(string))&&pattern2.test(new Number(string))){
        console.log(new Number(string))
                return new Number(string);
            }

            if (pattern1.test(string)){
               return string

            }


           return '';
        }



        var camelizeRE = /-(\w)/g;  //匹配带-后缀的任何字符串
        var camelize =  function (str) {
            //替换字符串
            return str.replace(camelizeRE, function (_, c) {
                return c ? c.toUpperCase() : '';
            })
        }

            console.log(camelize('ca-mel-ifffze'))



    </script>
</body>
</html>

================================================
FILE: classifyRE1.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<input id="input" type="text"  >
    <script>
        var hyphenateRE = /\B([A-Z])/g;
        var hyphenate = function (str) {
            return str.replace(hyphenateRE, '-$1').toLowerCase()
        } ;
        console.log(hyphenate('Ab 56c w 7745 6e rt'))

    </script>
</body>
</html>

================================================
FILE: comments.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<script src="vue.js"></script>
<body>
            <div id="version"></div>
            <div id="app">
                <!--this is comment-->
                <p>Hello Vue!</p>
            </div>
            <p>渲染后HTML: </p>
            <textarea id="code"></textarea>

<script>
    document.getElementById('version').innerHTML = 'Vue Version: ' + Vue.version;

    new Vue({
        el: '#app',
        comments: true,
        mounted() {
            document.getElementById('code').innerHTML = this.$el.innerHTML;
        }
    });
</script>
</body>
</html>

================================================
FILE: contextmenu.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        ul, li {
            margin: 0;
            padding: 0;
        }

        #myMenu{
            list-style: none;
            width: 150px;
            border: 1px solid #ccc;
            border-bottom: none;
            position: absolute;
            display: none;
        }

        #myMenu li{
            border-bottom: 1px solid #ccc;
            padding: 5px 10px;
            cursor: pointer;
        }

        #myMenu li:hover{
            background-color: #ccc;
        }
    </style>
</head>
<body>

<ul id="myMenu">
    <li>右键想干什么?</li>
    <li>想看源代码?</li>
    <li>还是想审查元素?</li>
</ul>
<script>
    var myMenu = document.getElementById("myMenu");
    document.addEventListener("contextmenu", function(event){
        event.preventDefault();
        myMenu.style.display = "block";
        //获取鼠标视口位置
        myMenu.style.top = event.clientY + "px";
        myMenu.style.left = event.clientX + "px";
    });
    document.addEventListener("click", function(event){
        myMenu.style.display = "none";
    });
</script>
</body>
</html>

================================================
FILE: createElementNS.html
================================================
<!DOCTYPE html>
<html>
<head>

</head>
<body>

<script>

//    看用在何处,什么程序语言。
//    顾名思义:
//    NS 是 namespace 的意思
//    createElementNS(ns,name) 通过 namespace 建立 单元
//    参数1是 字符串,单元节点 的 namespace(命名空间) 名字
//    参数2是 单元节点 的 名字
//    createElement 建立 单元
//    例如: createElement("div");
//    var newDiv = document.createElement("div");

//    createElementNS(ns,name) 方法创建带有命名空间的元素节点。 和createElement差不多
//ns	字符串,可为元素节点规定命名空间的名称。
//name	字符串,可为元素节点规定名称。

        var   newel=document.createElementNS("div","abc");
        var  newtext1=document.createTextNode("First");
//        newel.appendChild(newtext1)
        document.body.appendChild(newel)
        console.dir(newel)
        var  newe2=document.createElement("abc");
        var  newtext2=document.createTextNode("First");
//        newe2.appendChild(newtext2)
        document.body.appendChild(newe2)
        console.dir(newe2)

</script>
</body>
</html>

================================================
FILE: ddf.html
================================================
<h3>Vue mvvm simple model</h3>
<div id="app">
    <h2 v-text="title"></h2>
    <p v-text="name"></p>
    <input v-model="name">
</div>
<script type="text/javascript">
//function Vue(opt) {
//  this.data = opt.data || {};
//  this.$el = document.querySelector(opt.el) || document.body;
//  var textDom = this.$el.querySelectorAll('[v-text]');
//  var modelDom = this.$el.querySelectorAll('[v-model]');
//  var self = this;
//
//  function observe(data) {
//    // 设置开始和递归终止条件
//    if (!data || typeof data !== 'object') {
//      return;
//    }
//    // 不能直接使用for循环,避开闭包陷阱
//    Object.keys(data).forEach(function (key) {
//      defineReactive(data, key, data[key]);
//    })
//  }
//
//  function defineReactive(data, key, val) {
//    observe(val);   // 递归对象属性到基本类型为止
//    Object.defineProperty(data, key, {
//      enumerable  : true,    // 枚举
//      configurable: false, // 不可再配置
//      get         : function () {
//        return val;
//      },
//      set         : function (newVal) {
//        if (val === newVal) {
//          return;
//        }
//        val = newVal;  // setter本身已经做了赋值,val作为一个闭包变量,保存最新值
//        model2View();
//      },
//    })
//  }
//
//  function model2View() {
//    textDom.forEach(function (node) {
//      node.innerText = self.data[node.getAttribute('v-text')];
//    });
//  }
//
//  function watch() {
//    modelDom.forEach(function (node) {
//      //节点上面添加 key事件
//      node.addEventListener('keyup', function () {
//
//        self.data[node.getAttribute('v-model')] = node.value;
//      });
//    });
//  }
//
//  observe(this.data);
//  model2View();
//  watch();
//}
//
//var vm = new Vue({
//  el  : '#app',
//  data: {
//    name : 'Vue',
//    title: 'Hello Vue!',
//  },
//});
</script>

================================================
FILE: def.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      var obj={
          name:'name'
      }
      def(obj,'age',19);
      console.log(obj);
      var Observer = function Observer(value) {
          this.value = value;
          this.dep = new Dep();
          this.vmCount = 0;
          def(value, '__ob__', this);
          if (Array.isArray(value)) {
              var augment = hasProto
                      ? protoAugment
                      : copyAugment;
              augment(value, arrayMethods, arrayKeys);
              this.observeArray(value);
          } else {
              this.walk(value);
          }
      };


      function def(obj, key, val, enumerable) {
          Object.defineProperty(obj, key, {
              value: val, //值
              enumerable: !!enumerable,  //定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
              writable: true, //可以 改写 value
              configurable: true  //configurable特性表示对象的属性是否可以被删除,以及除writable特性外的其他特性是否可以被修改。
          });
      }
      Observer.prototype.observeArray = function observeArray(items) {
          for (var i = 0, l = items.length; i < l; i++) {
              observe(items[i]);
          }
      };

      function observe(value, asRootData) {
          if (!isObject(value) || value instanceof VNode) {
              return
          }
          var ob;
          if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
              ob = value.__ob__;
          } else if (
                  observerState.shouldConvert &&
                  !isServerRendering() &&
                  (Array.isArray(value) || isPlainObject(value)) &&
                  Object.isExtensible(value) &&
                  !value._isVue
          ) {
              ob = new Observer(value);
          }
          if (asRootData && ob) {
              ob.vmCount++;
          }
          return ob
      }

      var arrayProto = Array.prototype;
      var arrayMethods = Object.create(arrayProto);

      [
          'push',
          'pop',
          'shift',
          'unshift',
          'splice',
          'sort',
          'reverse'
      ].forEach(function (method) {
          // cache original method 缓存原始方法

          var original = arrayProto[method];
          //第1个参数是obj
          //第2个参数是key
          //第3个参数是value
          def(
                  arrayMethods,
                  method,
                  function mutator() {
                      console.log('mutator')
                      var args = [], len = arguments.length;
                      while (len--) args[len] = arguments[len];

                      var result = original.apply(this, args);
                      var ob = this.__ob__;
                      console.log(this.__ob__)
                      debugger;
                      var inserted;
                      switch (method) {
                          case 'push':
                          case 'unshift':
                              inserted = args;
                              break
                          case 'splice':
                              inserted = args.slice(2);
                              break
                      }
                      if (inserted) {
                          ob.observeArray(inserted);
                      }
                      // notify change
                      ob.dep.notify();
                      return result
                  }
          );
      });

      console.log(arrayProto)
      console.log(arrayMethods)
      console.log(arrayMethods.push('aa'))
  </script>
</body>
</html>

================================================
FILE: defineProperty.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      var obj={
          name:'name'
      }
      function def(obj, key, val, enumerable) {

          Object.defineProperty(obj, key, {
              value: val, //值
              enumerable: !!enumerable,  //定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
              writable: true, //可以 改写 value
              configurable: true  //configurable特性表示对象的属性是否可以被删除,以及除writable特性外的其他特性是否可以被修改。
          });
      }
      def(obj,'age', '29');
      var property_name = Object.getOwnPropertyDescriptor(obj, 'name');
      var property = Object.getOwnPropertyDescriptor(obj, 'age');
      var _property = Object.getOwnPropertyNames(obj);
      console.log(property_name);
      console.log(property);
      console.log(_property);



  </script>
</body>
</html>

================================================
FILE: exec.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
//全局匹配代码:的时候会有个lastIndex 索引 所以可以循环 这样就可以匹配出多个
    var reg=/(\w)l(\w)/g;
    var str="hello world hello 123 hello programmer hello test";
    var arr=reg.exec(str);
    while(arr){
        console.dir(arr);
        console.log("lastIndex:"+reg.lastIndex);
        arr=reg.exec(str);
    }
var reg2=/(\w)s(\w)/;
var str2="ws1esr";
var result=str2.match(reg2);
console.log(result)
debugger
var i=0;
while(result){
    i++;
    if(i<=4){
        console.dir(result);
        console.log("lastIndex:"+reg2.lastIndex);
    }
    else{
        break;
    }
}
</script>
</body>
</html>

================================================
FILE: exex.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var text="cat,bat,sat,fat";
    var pattern1=/.at/g;
    var matches=pattern1.exec(text);
    var matches1=pattern1.exec(text);
    var matches2=pattern1.exec(text);
    var matches3=pattern1.exec(text);
    var matches4=pattern1.exec(text);

    console.log(matches)
    console.log(matches1)
    console.log(matches2)
    console.log(matches3)
    console.log(matches4)
//    console.log(matches.index);//0
//    console.log(matches[0]);//cat
//    console.log(pattern1.lastIndex);//3



     matches=pattern1.exec(text);
//    console.log(matches)
//    console.log(matches.index);//5
//    console.log(matches[0]);//bat
//    console.log(pattern1.lastIndex);//7


//    var str = "abc123";
//    var re = /a.c/g
//    var result1 = re.test(str);
//    var result2 = re.test(str);
//    var result3 = re.test(str);
//    var result4 = re.test(str);
//    var result5 = re.test(str);
//    var result6 = re.test(str);
//    console.log(result1)
//    console.log(result2)
//    console.log(result3)
//    console.log(result4)
//    console.log(result5)
//    console.log(result6)


</script>
</body>
</html>

================================================
FILE: forIteratorRE.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var forAliasRE = /([^]*?)\s+(?:in|of)\s+([^]*)/; //匹配 含有   字符串 in  字符串   或者  字符串 of  字符串
    var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
    console.log('(value, key, index) in data'.match(forAliasRE));
    console.log('value, key, index'.match(forIteratorRE));
    console.log('( value, key, index)'.match(forIteratorRE));
    console.log('[ value, key, index]'.match(forIteratorRE)); //匹配不上
    console.log('{ value, key, index}'.match(forIteratorRE));//匹配不上
</script>
</body>
</html>

================================================
FILE: formatComponentName.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <script>

           var match = 'asdfsdfdd-asdf-\.vue'.match(/([^/\\]+)\.vue$/);
           console.log(match)

   </script>
</body>
</html>

================================================
FILE: genCheckboxModel.js
================================================
var $$a = item.selected,
    $$el = $event.target,
    $$c = $$el.checked ? (true) : (false);
if (Array.isArray($$a)) {
    var $$v = "index",
        $$i = _i($$a, $$v);
    if ($$el.checked) {
        $$i < 0 && ($set(item, "selected", $$a.concat([$$v])))
    } else {
        $$i > -1 && ($set(item, "selected", $$a.slice(0, $$i).concat($$a.slice($$i + 1))))
    }
} else {
    $set(item, "selected", $$c)
}

================================================
FILE: genStaticKeys.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>
      function genStaticKeys(modules) {
           let arr =  modules.reduce(
                  //reduce 累计相加api
               function (keys, m) {
                       console.log(m.staticKeys)
                     return keys.concat(m.staticKeys || [])
               }
                ,[]
          )
          console.log(arr)
         return  arr.join(',');
      }
      console.log(genStaticKeys([{ staticKeys:1},{staticKeys:2},{staticKeys:3}]) )
  </script>
</body>
</html>

================================================
FILE: getComputedStyle.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    #elem-container{
        position: absolute;
        left:     100px;
        top:      200px;
        height:   100px;
    }
</style>
<body>
<div id="elem-container">dummy</div>
<div id="output"></div>
<script>

function getTheStyle(){
let elem = document.getElementById("elem-container");
//    Window.getComputedStyle()方法返回一个对象,
// 该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有CSS属性的值
// 私有的CSS属性值可以通过对象提供的API或通过简单地使用CSS属性名称进行索引来访问。
 let    style =window.getComputedStyle(elem,null)
let theCSSprop = style.getPropertyValue("height");
    console.log(style)
    console.log(theCSSprop)

document.getElementById("output").innerHTML = theCSSprop;
}
getTheStyle();
</script>
</body>
</html>

================================================
FILE: getHookArgumentsLength.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <script>

      //判断数据 是否不等于 undefined或者null
      function isDef(v) {
          return v !== undefined && v !== null
      }
      //判断数据 是否是undefined或者null
      function isUndef(v) {
          return v === undefined || v === null
      }
      function getHookArgumentsLength(fn) {
          if (isUndef(fn)) {
              return false
          }
          console.log(fn)
          var invokerFns = fn.fns;

          if (isDef(invokerFns)) {
              console.log(invokerFns)
              // invoker
              return getHookArgumentsLength(
                      Array.isArray(invokerFns) ?
                              invokerFns[0] :
                              invokerFns
              )
          } else {
              console.log(fn.length)
              debugger
              return (fn._length || fn.length) > 1
          }
      }
      /*
      数据必须是这样才返回真,也可以是n层fns只要规律是一样嵌套下去就行
      var fn1=[1,2,3,4];
            var fn={
                fns:[

                        [1,2,3,45,34]

              ]
           }
      var fn2={
          fns:[
              {
                  fns:[
                      {
                          fns:[[1,2,3,45,9]]
                      }
                  ]
              }
          ]
      }
       */

      console.log(getHookArgumentsLength(fn))
  </script>
</body>
</html>

================================================
FILE: getOwnPropertyNames.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <script>
          function  Person(name,age) {
               this.name=name;
               this.age=age;
          }
          Person.prototype={
                 getAge:function () {
                      return this.age;
                 },
                 getName:function () {
                     return this.name;
                 }
          }
    var ps= new Person('name',27);
       console.log(Object.getOwnPropertyNames(ps))
   </script>
</body>
</html>

================================================
FILE: getShouldDecode.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    function getShouldDecode(href) {
      var   div =   document.createElement('div');
        div.innerHTML = href ? "<a href=\"\n\"/>" : "<div a=\"\n\"/>";
        //html里title属性换行的方法: &#10;  <div title="123& #10;456">text</div>
        return div.innerHTML.indexO
Download .txt
gitextract_aaudxq4u/

├── 0.html
├── 05自定义指令.html
├── 06provide组件通信.html
├── 07.html
├── 08delimiters.html
├── 09v-model.html
├── 1.html
├── 10tag标签.html
├── 10标签匹配.html
├── 11tag标签.html
├── 11标签匹配.html
├── 12tag标签.html
├── 12高阶组件.html
├── 13组件.html
├── 14高阶组件.html
├── 15 vonde.html
├── 16transition动画1.html
├── 16transition动画2.html
├── 16transition动画3.html
├── 17transition动画中的appear.html
├── 2.html
├── 3.html
├── 4.html
├── 5.html
├── 6.html
├── 6属性.html
├── 7for属性.html
├── 8event属性.html
├── HTMLUnknownElement.html
├── IS_REGEX_CAPTURING_BROKEN.html
├── JS里charCodeAt()和fromCharCode().html
├── JS里charCodeAt()和fromCharCode()方法拓展应用:加密与解密.html
├── MessageChannel.html
├── MessageChannel_0.html
├── MessageChannel_1.html
├── Proxy_1.html
├── Proxy_2.html
├── Proxy_3.html
├── Proxy_4.html
├── Proxy_5.html
├── Proxy_6.html
├── README.md
├── README_EN.md
├── Reflect.ownKeys.html
├── Set.html
├── StrictChecking.html
├── String方法之fromCharCode()和charCodeAt().html
├── Symbol.html
├── Symbol1.html
├── Symbol2.html
├── Symbol3.html
├── _Set.html
├── __proto__.html
├── _c.html
├── add.txt
├── add1.txt
├── advance.html
├── appear.html
├── argMatch.html
├── arrObj.html
├── array.html
├── attribute.html
├── bailRE.html
├── buildRegex.html
├── callbacks.slice(0).html
├── camelize.html
├── charCodeAt.html
├── classify.html
├── classifyRE.html
├── classifyRE1.html
├── comments.html
├── contextmenu.html
├── createElementNS.html
├── ddf.html
├── def.html
├── defineProperty.html
├── exec.html
├── exex.html
├── forIteratorRE.html
├── formatComponentName.html
├── genCheckboxModel.js
├── genStaticKeys.html
├── getComputedStyle.html
├── getHookArgumentsLength.html
├── getOwnPropertyNames.html
├── getShouldDecode.html
├── getTransitionInfo.html
├── getTransitionInfo获取css3 Transition 信息.html
├── getTransitionInfo获取css3 Transition 信息2.html
├── getType.html
├── getTypeIndex.html
├── hookRE.html
├── hyphenate.html
├── hyphenateRE.html
├── ieNSBug.html
├── index.html
├── indexOf.html
├── inline-template.html
├── is.html
├── isReserved.html
├── isUnknownElement.html
├── javascript 匿名函数自执行调用.html
├── js Worker 线程.docx
├── js 字符串截取方法.html
├── js 数组截取.html
├── js_watch.html
├── js_watch1.html
├── js中with、this的用法.html
├── js命令者.html
├── js如何判断数组含有某值,in,includes,inArray,indexOf方案对比.html
├── js观察者.xmind
├── js观察者_1.xmind
├── lastIndexOf.html
├── length.html
├── length0.html
├── modifierRE.html
├── mount.html
├── new Array(val).html
├── new Proxy.html
├── newFunction.html
├── nodeType.html
├── normalizeArrayChildren.html
├── object.html
├── object.keys.html
├── once.html
├── parseFilters.html
├── parseModel.html
├── parseModifiers.html
├── parsePath.html
├── parseStyleText.html
├── parseText.html
├── performance.html
├── performance对象.docx
├── prohibitedKeywordRE.html
├── promise.html
├── proxy.html
├── repeat.html
├── requestAnimationFrame.html
├── requestAnimationFrame2.html
├── setget.html
├── simpleCheckRE.html
├── slice splice.html
├── split.html
├── startTagClose.html
├── stopImmediatePropagation.html
├── stripStringRE.html
├── toUnicodeFun.html
├── transformModel.html
├── transition.html
├── unaryOperatorsRE.html
├── unaryOperatorsRE匹配字符串前一个字符串是什么.html
├── unaryOperatorsRE匹配字符串前一个字符串是什么2.html
├── vm._watcher === watcher.html
├── vue.js
├── vue.js中HOOK函数.docx
├── vue实现单页返回缓存,下一页刷新.doc
├── vue数据监听.docx
├── vue源码分析.docx
├── vue源码帖子分析.docx
├── vue零散代码分析.html
├── window_performance.html
├── window_performance1.html
├── with.html
├── wrapFilter.html
├── 三木分析.html
├── 三木分析1.html
├── 匿名函数执行.html
├── 发布-订阅模式.html
├── 数组api.html
├── 数组的扩展-array.some()和array.every()区别?.docx
├── 正则$.html
├── 理解vue实现原理,实现一个简单的Vue框架.docx
├── 虚拟dom.docx
├── 观察者模式.html
├── 静态方法与原型.html
└── 高阶组件.html
Download .txt
SYMBOL INDEX (351 symbols across 1 files)

FILE: vue.js
  function isUndef (line 26) | function isUndef(v) {
  function isDef (line 31) | function isDef(v) {
  function isTrue (line 36) | function isTrue(v) {
  function isFalse (line 41) | function isFalse(v) {
  function isPrimitive (line 50) | function isPrimitive(value) {
  function isObject (line 66) | function isObject(obj) {
  function toRawType (line 77) | function toRawType(value) {
  function isPlainObject (line 86) | function isPlainObject(obj) {
  function isRegExp (line 91) | function isRegExp(v) {
  function isValidArrayIndex (line 103) | function isValidArrayIndex(val) {
  function toString (line 114) | function toString(val) {
  function toNumber (line 128) | function toNumber(val) {
  function makeMap (line 141) | function makeMap(str,
  function remove (line 174) | function remove(arr, item) {
  function hasOwn (line 189) | function hasOwn(obj, key) {
  function cached (line 231) | function cached(fn) {
  function polyfillBind (line 288) | function polyfillBind(fn, ctx) {
  function nativeBind (line 303) | function nativeBind(fn, ctx) {
  function toArray (line 316) | function toArray(list, start) {
  function extend (line 344) | function extend(to, _from) {
  function toObject (line 369) | function toObject(arr) {
  function noop (line 385) | function noop(a, b, c) {
  function genStaticKeys (line 410) | function genStaticKeys(modules) {
  function looseEqual (line 425) | function looseEqual(a, b) {
  function looseIndexOf (line 468) | function looseIndexOf(arr, val) {
  function once (line 481) | function once(fn) {
  function isReserved (line 629) | function isReserved(str) {
  function def (line 643) | function def(obj, key, val, enumerable) {
  function parsePath (line 660) | function parsePath(path) {
  function isNative (line 751) | function isNative(Ctor) {
  function Set (line 785) | function Set() {
  function pushTarget (line 1046) | function pushTarget(_target) {
  function popTarget (line 1056) | function popTarget() {
  function createTextVNode (line 1168) | function createTextVNode(val) {
  function cloneVNode (line 1188) | function cloneVNode(vnode, deep) {
  function cloneVNodes (line 1225) | function cloneVNodes(vnodes, deep) {
  function toggleObserving (line 1329) | function toggleObserving(value) {
  function protoAugment (line 1405) | function protoAugment(target, src, keys) {
  function copyAugment (line 1421) | function copyAugment(target, src, keys) {
  function observe (line 1438) | function observe(value, asRootData) {
  function defineReactive (line 1483) | function defineReactive(obj, //对象
  function set (line 1572) | function set(target, key, val) {
  function del (line 1621) | function del(target, key) {
  function dependArray (line 1669) | function dependArray(value) {
  function mergeData (line 1717) | function mergeData(to, from) {
  function mergeDataOrFn (line 1741) | function mergeDataOrFn(
  function mergeHook (line 1822) | function mergeHook(
  function mergeAssets (line 1853) | function mergeAssets(
  function checkComponents (line 1966) | function checkComponents(options) {
  function validateComponentName (line 1974) | function validateComponentName(name) {
  function normalizeProps (line 2000) | function normalizeProps(options, vm) {
  function normalizeInject (line 2056) | function normalizeInject(options, vm) {
  function normalizeDirectives (line 2095) | function normalizeDirectives(options) {
  function assertObjectType (line 2114) | function assertObjectType(name, value, vm) {
  function mergeOptions (line 2131) | function mergeOptions(parent, //父值
  function resolveAsset (line 2201) | function resolveAsset(options, //参数
  function validateProp (line 2281) | function validateProp(
  function getPropDefaultValue (line 2353) | function getPropDefaultValue(vm, prop, key) {
  function assertProp (line 2406) | function assertProp(
  function assertType (line 2467) | function assertType(value, type) {
  function getType (line 2507) | function getType(fn) {
  function isSameType (line 2513) | function isSameType(a, b) {
  function getTypeIndex (line 2520) | function getTypeIndex(type, expectedTypes) {
  function handleError (line 2552) | function handleError(err, vm, info) {
  function globalHandleError (line 2579) | function globalHandleError(err, vm, info) {
  function logError (line 2595) | function logError(err, vm, info) {
  function flushCallbacks (line 2615) | function flushCallbacks() {
  function withMacroTask (line 2712) | function withMacroTask(fn) {
  function nextTick (line 2723) | function nextTick(cb, ctx) {
  function traverse (line 2918) | function traverse(val) {
  function _traverse (line 2935) | function _traverse(val, seen) {
  function createFnInvoker (line 3021) | function createFnInvoker(fns) {
  function updateListeners (line 3051) | function updateListeners(
  function mergeVNodeHook (line 3118) | function mergeVNodeHook(def, hookKey, hook) {
  function extractPropsFromVNodeData (line 3165) | function extractPropsFromVNodeData(
  function checkProp (line 3244) | function checkProp(
  function simpleNormalizeChildren (line 3291) | function simpleNormalizeChildren(children) {
  function normalizeChildren (line 3305) | function normalizeChildren(children) {
  function isTextNode (line 3314) | function isTextNode(node) {
  function normalizeArrayChildren (line 3334) | function normalizeArrayChildren(
  function ensureCtor (line 3413) | function ensureCtor(comp, base) {
  function createAsyncPlaceholder (line 3433) | function createAsyncPlaceholder(factory, //工厂
  function resolveAsyncComponent (line 3452) | function resolveAsyncComponent(
  function isAsyncPlaceholder (line 3570) | function isAsyncPlaceholder(node) {
  function getFirstComponentChild (line 3579) | function getFirstComponentChild(children) {
  function initEvents (line 3596) | function initEvents(vm) {
  function add (line 3615) | function add(event, fn, once) {
  function remove$1 (line 3626) | function remove$1(event, fn) {
  function updateComponentListeners (line 3631) | function updateComponentListeners(vm,  //虚拟dom
  function eventsMixin (line 3645) | function eventsMixin(Vue) {
  function resolveSlots (line 3788) | function resolveSlots(children,
  function isWhitespace (line 3843) | function isWhitespace(node) {
  function resolveScopedSlots (line 3879) | function resolveScopedSlots(fns, // see flow/vnode
  function initLifecycle (line 3900) | function initLifecycle(vm) {
  function lifecycleMixin (line 3935) | function lifecycleMixin(Vue) {
  function mountComponent (line 4083) | function mountComponent(
  function updateChildComponent (line 4192) | function updateChildComponent(
  function isInInactiveTree (line 4275) | function isInInactiveTree(vm) { //活动中的树
  function activateChildComponent (line 4285) | function activateChildComponent(vm, // 虚拟dom vode
  function deactivateChildComponent (line 4306) | function deactivateChildComponent(vm, direct) {
  function callHook (line 4324) | function callHook(vm,  //虚拟dom  vonde
  function resetSchedulerState (line 4372) | function resetSchedulerState() {
  function flushSchedulerQueue (line 4385) | function flushSchedulerQueue() {
  function callUpdatedHooks (line 4451) | function callUpdatedHooks(queue) {
  function queueActivatedComponent (line 4468) | function queueActivatedComponent(vm) {
  function callActivatedHooks (line 4476) | function callActivatedHooks(queue) {
  function queueWatcher (line 4491) | function queueWatcher(watcher) {
  function proxy (line 4841) | function proxy(target, sourceKey, key) {
  function initState (line 4852) | function initState(vm) {
  function initProps (line 4894) | function initProps(vm, propsOptions) {
  function initData (line 4963) | function initData(vm) {
  function getData (line 5020) | function getData(data, vm) {
  function initComputed (line 5040) | function initComputed(vm, computed) {
  function defineComputed (line 5083) | function defineComputed(target, //目标
  function createComputedGetter (line 5118) | function createComputedGetter(key) {
  function initMethods (line 5139) | function initMethods(vm, methods) {
  function initWatch (line 5175) | function initWatch(vm, watch) {
  function createWatcher (line 5201) | function createWatcher(vm,  //vm对象
  function stateMixin (line 5222) | function stateMixin(Vue) {
  function initProvide (line 5304) | function initProvide(vm) {
  function initInjections (line 5314) | function initInjections(vm) {
  function resolveInject (line 5345) | function resolveInject(inject, vm) {
  function renderList (line 5393) | function renderList(val, //值
  function renderSlot (line 5431) | function renderSlot(name, //子组件中slot的name,匿名default
  function resolveFilter (line 5498) | function resolveFilter(id) {
  function isKeyNotMatch (line 5506) | function isKeyNotMatch(expect, actual) {
  function checkKeyCodes (line 5520) | function checkKeyCodes(eventKeyCode, //事件key
  function bindObjectProps (line 5549) | function bindObjectProps(data, //数据
  function renderStatic (line 5613) | function renderStatic(index, //索引
  function markOnce (line 5640) | function markOnce(tree,
  function markStatic (line 5649) | function markStatic(tree, //树
  function markStaticNode (line 5667) | function markStaticNode(node, key, isOnce) {
  function bindObjectListeners (line 5677) | function bindObjectListeners(data, value) {
  function installRenderHelpers (line 5701) | function installRenderHelpers(target) {
  function FunctionalRenderContext (line 5727) | function FunctionalRenderContext(
  function createFunctionalComponent (line 5822) | function createFunctionalComponent(
  function cloneAndMarkFunctionalResult (line 5924) | function cloneAndMarkFunctionalResult(vnode,   //vnode 虚拟dom
  function mergeProps (line 5946) | function mergeProps(to, from) {
  function createComponent (line 6081) | function createComponent(
  function createComponentInstanceForVnode (line 6266) | function createComponentInstanceForVnode(
  function installComponentHooks (line 6289) | function installComponentHooks(
  function transformModel (line 6313) | function transformModel(options, data) {
  function createElement (line 6339) | function createElement(
  function _createElement (line 6371) | function _createElement(context,  //vm vue实例化的对象
  function applyNS (line 6534) | function applyNS(
  function registerDeepBindings (line 6566) | function registerDeepBindings(data) {
  function initRender (line 6581) | function initRender(vm) {
  function renderMixin (line 6649) | function renderMixin(Vue) {
  function initMixin (line 6758) | function initMixin(Vue) {
  function initInternalComponent (line 6830) | function initInternalComponent(
  function resolveConstructorOptions (line 6862) | function resolveConstructorOptions(Ctor) {
  function resolveModifiedOptions (line 6894) | function resolveModifiedOptions(Ctor) {
  function dedupe (line 6913) | function dedupe(
  function Vue (line 6942) | function Vue(options) {
  function initUse (line 6959) | function initUse(Vue) {
  function initMixin$1 (line 6984) | function initMixin$1(Vue) {
  function initExtend (line 6994) | function initExtend(Vue) {
  function initProps$1 (line 7101) | function initProps$1(Comp) {
  function initComputed$1 (line 7109) | function initComputed$1(Comp) {
  function initAssetRegisters (line 7120) | function initAssetRegisters(Vue) {
  function getComponentName (line 7169) | function getComponentName(opts) {
  function matches (line 7174) | function matches(pattern, name) {
  function pruneCache (line 7186) | function pruneCache(keepAliveInstance, //当前保持活着的实例
  function pruneCacheEntry (line 7209) | function pruneCacheEntry(cache, //缓存对象
  function initGlobalAPI (line 7341) | function initGlobalAPI(Vue) {
  function genClassForVnode (line 7487) | function genClassForVnode(vnode) {
  function mergeClassData (line 7508) | function mergeClassData(child, parent) {
  function renderClass (line 7519) | function renderClass(
  function concat (line 7536) | function concat(a, b) {
  function stringifyClass (line 7547) | function stringifyClass(value) {
  function stringifyArray (line 7564) | function stringifyArray(value) {
  function stringifyObject (line 7579) | function stringifyObject(value) {
  function getTagNamespace (line 7637) | function getTagNamespace(tag) {
  function isUnknownElement (line 7656) | function isUnknownElement(tag) {
  function query (line 7699) | function query(el) {
  function createElement$1 (line 7717) | function createElement$1(tagName, vnode) {
  function createElementNS (line 7736) | function createElementNS(namespace, tagName) {
  function createTextNode (line 7745) | function createTextNode(text) {
  function createComment (line 7750) | function createComment(text) {
  function insertBefore (line 7755) | function insertBefore(parentNode, newNode, referenceNode) {
  function removeChild (line 7761) | function removeChild(node, child) {
  function appendChild (line 7766) | function appendChild(node, child) {
  function parentNode (line 7771) | function parentNode(node) {
  function nextSibling (line 7776) | function nextSibling(node) {
  function tagName (line 7781) | function tagName(node) {
  function setTextContent (line 7786) | function setTextContent(node, text) {
  function setStyleScope (line 7792) | function setStyleScope(node, scopeId) {
  function registerRef (line 7834) | function registerRef(vnode, isRemoval) {
  function sameVnode (line 7880) | function sameVnode(a, b) {
  function sameInputType (line 7900) | function sameInputType(a, b) {
  function createKeyToOldIdx (line 7913) | function createKeyToOldIdx(children, beginIdx, endIdx) {
  function createPatchFunction (line 7926) | function createPatchFunction(backend) {
  function updateDirectives (line 9061) | function updateDirectives(oldVnode, vnode) {
  function _update (line 9069) | function _update(oldVnode, vnode) {
  function normalizeDirectives$1 (line 9177) | function normalizeDirectives$1(
  function getRawDirName (line 9206) | function getRawDirName(dir) {
  function callHook$1 (line 9216) | function callHook$1(
  function updateAttrs (line 9250) | function updateAttrs(oldVnode, vnode) {
  function setAttr (line 9298) | function setAttr(el, key, value) {
  function baseSetAttr (line 9338) | function baseSetAttr(el, //dom节点
  function updateClass (line 9385) | function updateClass(oldVnode, vnode) {
  function parseFilters (line 9434) | function parseFilters(exp) {
  function wrapFilter (line 9619) | function wrapFilter(exp, filter) {
  function baseWarn (line 9649) | function baseWarn(msg) {
  function pluckModuleFunction (line 9654) | function pluckModuleFunction(
  function addProp (line 9666) | function addProp(el, name, value) {
  function addAttr (line 9672) | function addAttr(el, name, value) {
  function addRawAttr (line 9679) | function addRawAttr(el, name, value) {
  function addDirective (line 9688) | function addDirective(
  function addHandler (line 9709) | function addHandler(
  function getBindingAttr (line 9808) | function getBindingAttr(el, //虚拟dom  vonde
  function getAndRemoveAttr (line 9845) | function getAndRemoveAttr(el, //el  虚拟dom
  function genComponentModel (line 9872) | function genComponentModel(
  function genAssignmentCode (line 9929) | function genAssignmentCode(
  function parseModel (line 9982) | function parseModel(val) {
  function next (line 10030) | function next() {
  function eof (line 10036) | function eof() {
  function isStringStart (line 10042) | function isStringStart(chr) {
  function parseBracket (line 10048) | function parseBracket(chr) {
  function parseString (line 10070) | function parseString(chr) {
  function model (line 10091) | function model(
  function genCheckboxModel (line 10158) | function genCheckboxModel(
  function genRadioModel (line 10250) | function genRadioModel(
  function genSelect (line 10279) | function genSelect(
  function genDefaultModel (line 10319) | function genDefaultModel(
  function normalizeEvents (line 10399) | function normalizeEvents(on) {
  function createOnceHandler (line 10424) | function createOnceHandler(
  function add$1 (line 10447) | function add$1(
  function remove$2 (line 10473) | function remove$2(
  function updateDOMListeners (line 10487) | function updateDOMListeners(oldVnode, vnode) {
  function updateDOMProps (line 10515) | function updateDOMProps(oldVnode, vnode) {
  function shouldUpdateValue (line 10588) | function shouldUpdateValue(elm, checkVal) {
  function isNotInFocusAndDirty (line 10596) | function isNotInFocusAndDirty(elm, checkVal) {
  function isDirtyWithModifiers (line 10609) | function isDirtyWithModifiers(elm, newVal) {
  function normalizeStyleData (line 10656) | function normalizeStyleData(data) {
  function normalizeStyleBinding (line 10671) | function normalizeStyleBinding(bindingStyle) {
  function getStyle (line 10689) | function getStyle(
  function updateStyle (line 10780) | function updateStyle(oldVnode, vnode) {
  function addClass (line 10846) | function addClass(el, cls) {
  function removeClass (line 10877) | function removeClass(el, cls) {
  function resolveTransition (line 10915) | function resolveTransition(def) {
  function nextFrame (line 10981) | function nextFrame(fn) {
  function addTransitionClass (line 10987) | function addTransitionClass(el, cls) {
  function removeTransitionClass (line 10997) | function removeTransitionClass(el, cls) {
  function whenTransitionEnds (line 11007) | function whenTransitionEnds(
  function getTransitionInfo (line 11047) | function getTransitionInfo(
  function getTimeout (line 11115) | function getTimeout(delays, durations) {
  function toMs (line 11129) | function toMs(s) {
  function enter (line 11134) | function enter(
  function leave (line 11356) | function leave(
  function checkDuration (line 11475) | function checkDuration(val, name, vnode) {
  function isValidDuration (line 11491) | function isValidDuration(val) {
  function getHookArgumentsLength (line 11531) | function getHookArgumentsLength(fn) {
  function _enter (line 11549) | function _enter(_, vnode) {
  function setSelected (line 11701) | function setSelected(el, binding, vm) {
  function actuallySetSelected (line 11711) | function actuallySetSelected(el, binding, vm) {
  function hasNoMatchingOption (line 11744) | function hasNoMatchingOption(value, options) {
  function getValue (line 11750) | function getValue(option) {
  function onCompositionStart (line 11756) | function onCompositionStart(e) {
  function onCompositionEnd (line 11760) | function onCompositionEnd(e) {
  function trigger (line 11769) | function trigger(el, type) {
  function locateNode (line 11778) | function locateNode(vnode) {
  function getRealChild (line 11869) | function getRealChild(vnode) {
  function extractTransitionData (line 11878) | function extractTransitionData(comp) {
  function placeholder (line 11894) | function placeholder(h, rawChild) {
  function hasParentTransition (line 11902) | function hasParentTransition(vnode) {
  function isSameChild (line 11910) | function isSameChild(child, oldChild) {
  function callPendingCbs (line 12183) | function callPendingCbs(c) {
  function recordPosition (line 12194) | function recordPosition(c) {
  function applyTranslation (line 12198) | function applyTranslation(c) {
  function parseText (line 12308) | function parseText(text, //字符串
  function transformNode (line 12356) | function transformNode(
  function genData (line 12392) | function genData(el) {
  function transformNode$1 (line 12414) | function transformNode$1(el, options) {
  function genData$1 (line 12445) | function genData$1(el) {
  function decodeAttr (line 12559) | function decodeAttr(
  function parseHTML (line 12575) | function parseHTML(
  function createASTElement (line 13082) | function createASTElement(tag,  //标签名称
  function parse (line 13100) | function parse(
  function processPre (line 13524) | function processPre(el) {
  function processRawAttrs (line 13531) | function processRawAttrs(el) {
  function processElement (line 13550) | function processElement(element, options) {
  function processKey (line 13579) | function processKey(el) {
  function processRef (line 13592) | function processRef(el) {
  function processFor (line 13603) | function processFor(el) {
  function parseFor (line 13624) | function parseFor(exp //字符串 列如 是 (item,index) in data 或 item in data 或it...
  function processIf (line 13654) | function processIf(el) {
  function processIfConditions (line 13673) | function processIfConditions(el, parent) {
  function findPrevElement (line 13693) | function findPrevElement(children) {
  function addIfCondition (line 13711) | function addIfCondition(
  function processOnce (line 13721) | function processOnce(el) {
  function processSlot (line 13729) | function processSlot(el) {
  function processComponent (line 13786) | function processComponent(el) {
  function processAttrs (line 13796) | function processAttrs(el) {
  function checkInFor (line 13964) | function checkInFor(el) {
  function parseModifiers (line 13976) | function parseModifiers(name) {
  function makeAttrsMap (line 13994) | function makeAttrsMap(attrs) {
  function isTextTag (line 14012) | function isTextTag(el) {
  function isForbiddenTag (line 14017) | function isForbiddenTag(el) {
  function guardIESVGBug (line 14035) | function guardIESVGBug(attrs) {
  function checkForAliasModel (line 14050) | function checkForAliasModel(el, value) {
  function preTransformNode (line 14083) | function preTransformNode(
  function cloneASTElement (line 14175) | function cloneASTElement(el) {
  function text (line 14197) | function text(el, dir) {
  function html (line 14210) | function html(el, dir) {
  function optimize (line 14301) | function optimize(root, options) {
  function genStaticKeys$1 (line 14319) | function genStaticKeys$1(keys) {
  function markStatic$1 (line 14326) | function markStatic$1(node) {
  function markStaticRoots (line 14363) | function markStaticRoots(node, isInFor) {
  function isStatic (line 14408) | function isStatic(node) {
  function isDirectChildOfTemplateFor (line 14430) | function isDirectChildOfTemplateFor(node) {
  function genHandlers (line 14495) | function genHandlers(
  function genHandler (line 14507) | function genHandler(
  function genKeyFilter (line 14574) | function genKeyFilter(keys) {
  function genFilterCode (line 14578) | function genFilterCode(key) {
  function on (line 14597) | function on(el, dir) {
  function bind$1 (line 14609) | function bind$1(el, dir) {
  function generate (line 14701) | function generate(
  function genElement (line 14733) | function genElement(
  function genStatic (line 14803) | function genStatic(el, state) {
  function genOnce (line 14820) | function genOnce(el, state) {
  function genIf (line 14852) | function genIf(
  function genIfConditions (line 14868) | function genIfConditions(
  function genFor (line 14903) | function genFor(
  function genData$2 (line 14937) | function genData$2(el, state) {
  function genDirectives (line 15022) | function genDirectives(el, state) {
  function genInlineTemplate (line 15072) | function genInlineTemplate(el, state) {
  function genScopedSlots (line 15087) | function genScopedSlots(slots,
  function genScopedSlot (line 15094) | function genScopedSlot(key,
  function genForScopedSlot (line 15109) | function genForScopedSlot(key,
  function genChildren (line 15124) | function genChildren(el,  //dom
  function getNormalizationType (line 15171) | function getNormalizationType(
  function needsNormalization (line 15200) | function needsNormalization(el) {
  function genNode (line 15205) | function genNode(node, state) {
  function genText (line 15221) | function genText(text) {
  function genComment (line 15228) | function genComment(comment) {
  function genSlot (line 15233) | function genSlot(el, state) {
  function genComponent (line 15255) | function genComponent(
  function genProps (line 15267) | function genProps(props) {
  function transformSpecialNewlines (line 15288) | function transformSpecialNewlines(text) {
  function detectErrors (line 15333) | function detectErrors(ast) {
  function checkNode (line 15343) | function checkNode(node, errors) {
  function checkEvent (line 15379) | function checkEvent(exp, text, errors) {
  function checkFor (line 15394) | function checkFor(node,  //节点
  function checkIdentifier (line 15412) | function checkIdentifier(ident, //识别
  function checkExpression (line 15427) | function checkExpression(exp, text, errors) {
  function createFunction (line 15459) | function createFunction(code, errors) {
  function createCompileToFunctionFn (line 15478) | function createCompileToFunctionFn(compile) {
  function createCompilerCreator (line 15617) | function createCompilerCreator(
  function getShouldDecode (line 15806) | function getShouldDecode(href) {
  function getOuterHTML (line 15975) | function getOuterHTML(el) {
Condensed preview — 176 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,069K chars).
[
  {
    "path": "0.html",
    "chars": 2447,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "05自定义指令.html",
    "chars": 1756,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "06provide组件通信.html",
    "chars": 1984,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "07.html",
    "chars": 932,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "08delimiters.html",
    "chars": 648,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "09v-model.html",
    "chars": 3581,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "1.html",
    "chars": 1711,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "10tag标签.html",
    "chars": 2492,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "10标签匹配.html",
    "chars": 1453,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "11tag标签.html",
    "chars": 613,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n<body>\r\n<p><"
  },
  {
    "path": "11标签匹配.html",
    "chars": 1363,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "12tag标签.html",
    "chars": 2485,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "12高阶组件.html",
    "chars": 2550,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "13组件.html",
    "chars": 2756,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "14高阶组件.html",
    "chars": 2570,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "15 vonde.html",
    "chars": 1180,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "16transition动画1.html",
    "chars": 735,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "16transition动画2.html",
    "chars": 994,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "16transition动画3.html",
    "chars": 662,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "17transition动画中的appear.html",
    "chars": 1552,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "2.html",
    "chars": 507,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "3.html",
    "chars": 1729,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "4.html",
    "chars": 871,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "5.html",
    "chars": 1883,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "6.html",
    "chars": 254,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n\r\n    \r\n\r\n\r\n</head>\r\n"
  },
  {
    "path": "6属性.html",
    "chars": 911,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "7for属性.html",
    "chars": 893,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "8event属性.html",
    "chars": 2139,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "HTMLUnknownElement.html",
    "chars": 526,
    "preview": "<html>\r\n    <head>\r\n        <meta>\r\n    </head>\r\n    <body>\r\n        <script>\r\n            var el = document.createEleme"
  },
  {
    "path": "IS_REGEX_CAPTURING_BROKEN.html",
    "chars": 364,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n\r\n</head>\r\n\r\n\r\n<scrip"
  },
  {
    "path": "JS里charCodeAt()和fromCharCode().html",
    "chars": 244,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n\r\n<scr"
  },
  {
    "path": "JS里charCodeAt()和fromCharCode()方法拓展应用:加密与解密.html",
    "chars": 2362,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<p><te"
  },
  {
    "path": "MessageChannel.html",
    "chars": 711,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<ifram"
  },
  {
    "path": "MessageChannel_0.html",
    "chars": 544,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "MessageChannel_1.html",
    "chars": 1093,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "Proxy_1.html",
    "chars": 689,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "Proxy_2.html",
    "chars": 427,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "Proxy_3.html",
    "chars": 359,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "Proxy_4.html",
    "chars": 639,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "Proxy_5.html",
    "chars": 763,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "Proxy_6.html",
    "chars": 1400,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "README.md",
    "chars": 45669,
    "preview": " ***English document***: https://github.com/ygs-code/vue/blob/master/README_EN.md\n#   开始\n\n vue源码业余时间差不多看了一年,以前在网上找帖子,发现很"
  },
  {
    "path": "README_EN.md",
    "chars": 51121,
    "preview": "#   begin\n\n vue source code spare time to see almost a year, before looking for posts on the Internet, found that many p"
  },
  {
    "path": "Reflect.ownKeys.html",
    "chars": 763,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "Set.html",
    "chars": 1002,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "StrictChecking.html",
    "chars": 344,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "String方法之fromCharCode()和charCodeAt().html",
    "chars": 990,
    "preview": "<!DOCTYPE html>\r\n<html class=\"ui-page-login\">\r\n\r\n<head>\r\n\r\n\r\n</head>\r\n\r\n\r\n<body>\r\n<script type=\"text/javascript\">\r\n    f"
  },
  {
    "path": "Symbol.html",
    "chars": 266,
    "preview": "<!DOCTYPE html>\r\n<html class=\"ui-page-login\">\r\n\r\n\t<head>\r\n\t\t \r\n\r\n\t</head>\r\n\r\n \r\n\t<body>\r\n\t   <script type=\"text/javascri"
  },
  {
    "path": "Symbol1.html",
    "chars": 343,
    "preview": "<!DOCTYPE html>\r\n<html class=\"ui-page-login\">\r\n\r\n\t<head>\r\n\t\t \r\n\r\n\t</head>\r\n\r\n \r\n\t<body>\r\n\t   <script type=\"text/javascri"
  },
  {
    "path": "Symbol2.html",
    "chars": 270,
    "preview": "<!DOCTYPE html>\r\n<html class=\"ui-page-login\">\r\n\r\n<head>\r\n\r\n\r\n</head>\r\n\r\n\r\n<body>\r\n<script type=\"text/javascript\">\r\n    c"
  },
  {
    "path": "Symbol3.html",
    "chars": 312,
    "preview": "<!DOCTYPE html>\r\n<html class=\"ui-page-login\">\r\n\r\n<head>\r\n\r\n\r\n</head>\r\n\r\n\r\n<body>\r\n<script type=\"text/javascript\">\r\n    l"
  },
  {
    "path": "_Set.html",
    "chars": 763,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n<body>\r\n\r\n<s"
  },
  {
    "path": "__proto__.html",
    "chars": 340,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "_c.html",
    "chars": 3595,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n<body></body"
  },
  {
    "path": "add.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "add1.txt",
    "chars": 24,
    "preview": "add111111111111111111111"
  },
  {
    "path": "advance.html",
    "chars": 418,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "appear.html",
    "chars": 132,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n\r\n</bo"
  },
  {
    "path": "argMatch.html",
    "chars": 730,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "arrObj.html",
    "chars": 356,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n    <s"
  },
  {
    "path": "array.html",
    "chars": 1852,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n<body>\r\n\r\n<s"
  },
  {
    "path": "attribute.html",
    "chars": 615,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "bailRE.html",
    "chars": 908,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "buildRegex.html",
    "chars": 1585,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "callbacks.slice(0).html",
    "chars": 251,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "camelize.html",
    "chars": 1183,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n <scri"
  },
  {
    "path": "charCodeAt.html",
    "chars": 2509,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "classify.html",
    "chars": 625,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "classifyRE.html",
    "chars": 1725,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n<body>\r\n<inp"
  },
  {
    "path": "classifyRE1.html",
    "chars": 414,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n<body>\r\n<inp"
  },
  {
    "path": "comments.html",
    "chars": 685,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<script src=\"v"
  },
  {
    "path": "contextmenu.html",
    "chars": 1215,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n    <style>\r\n        "
  },
  {
    "path": "createElementNS.html",
    "chars": 946,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n\r\n</head>\r\n<body>\r\n\r\n<script>\r\n\r\n//    看用在何处,什么程序语言。\r\n//    顾名思义:\r\n//    NS 是 namespace"
  },
  {
    "path": "ddf.html",
    "chars": 1820,
    "preview": "<h3>Vue mvvm simple model</h3>\r\n<div id=\"app\">\r\n    <h2 v-text=\"title\"></h2>\r\n    <p v-text=\"name\"></p>\r\n    <input v-mo"
  },
  {
    "path": "def.html",
    "chars": 3775,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "defineProperty.html",
    "chars": 912,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "exec.html",
    "chars": 728,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "exex.html",
    "chars": 1281,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "forIteratorRE.html",
    "chars": 633,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "formatComponentName.html",
    "chars": 265,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "genCheckboxModel.js",
    "chars": 423,
    "preview": "var $$a = item.selected,\r\n    $$el = $event.target,\r\n    $$c = $$el.checked ? (true) : (false);\r\nif (Array.isArray($$a))"
  },
  {
    "path": "genStaticKeys.html",
    "chars": 625,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "getComputedStyle.html",
    "chars": 826,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<style>\r\n    #"
  },
  {
    "path": "getHookArgumentsLength.html",
    "chars": 1526,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "getOwnPropertyNames.html",
    "chars": 603,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "getShouldDecode.html",
    "chars": 528,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "getTransitionInfo.html",
    "chars": 4699,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<style"
  },
  {
    "path": "getTransitionInfo获取css3 Transition 信息.html",
    "chars": 8594,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<style"
  },
  {
    "path": "getTransitionInfo获取css3 Transition 信息2.html",
    "chars": 5504,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<style"
  },
  {
    "path": "getType.html",
    "chars": 601,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "getTypeIndex.html",
    "chars": 1494,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "hookRE.html",
    "chars": 354,
    "preview": "<html>\r\n    <head>\r\n        <meta>\r\n    </head>\r\n    <body>\r\n        <script>\r\n\r\n                     var hookRE = /^hoo"
  },
  {
    "path": "hyphenate.html",
    "chars": 1167,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "hyphenateRE.html",
    "chars": 1757,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "ieNSBug.html",
    "chars": 229,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n\r\n<script>\r\n"
  },
  {
    "path": "index.html",
    "chars": 1438,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "indexOf.html",
    "chars": 208,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n\r\n<script>\r\n"
  },
  {
    "path": "inline-template.html",
    "chars": 1730,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "is.html",
    "chars": 2742,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "isReserved.html",
    "chars": 332,
    "preview": "<html>\r\n<head>\r\n    <meta>\r\n</head>\r\n<body>\r\n<script>\r\n\r\n    /**\r\n     * Check if a string starts with $ or _\r\n     * 检查"
  },
  {
    "path": "isUnknownElement.html",
    "chars": 3457,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n  <head>\r\n    <meta charset=\"UTF-8\" />\r\n    <title>Title</title>\r\n  </head>\r\n  <body>"
  },
  {
    "path": "javascript 匿名函数自执行调用.html",
    "chars": 527,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<script>\r\n    "
  },
  {
    "path": "js 字符串截取方法.html",
    "chars": 813,
    "preview": "<html>\r\n<head>\r\n    <meta>\r\n</head>\r\n<body>\r\n<script>\r\n    var str='abcedfg|hijk';\r\n//split() 使用一个指定的分隔符把一个字符串分割存储到数组\r\n "
  },
  {
    "path": "js 数组截取.html",
    "chars": 903,
    "preview": "<html>\r\n<head>\r\n    <meta>\r\n</head>\r\n<body>\r\n<script>\r\n    //    arrayObject.slice(start,end)\r\n    //    start\t必需。规定从何处开"
  },
  {
    "path": "js_watch.html",
    "chars": 508,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <title>Title</title>\r\n</head>\r\n<body>\r\n<script>\r\n//"
  },
  {
    "path": "js_watch1.html",
    "chars": 1069,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <title>Title</title>\r\n</head>\r\n<body>\r\n<script>\r\n /"
  },
  {
    "path": "js中with、this的用法.html",
    "chars": 742,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "js命令者.html",
    "chars": 827,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<butto"
  },
  {
    "path": "js如何判断数组含有某值,in,includes,inArray,indexOf方案对比.html",
    "chars": 302,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "lastIndexOf.html",
    "chars": 328,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "length.html",
    "chars": 322,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "length0.html",
    "chars": 289,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "modifierRE.html",
    "chars": 246,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "mount.html",
    "chars": 460,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<meta charset=\"UTF-8\">\r\n<body>\r\n\r\n<script>\r\n   function Person() {\r\n\r\n   }\r\n   Person.prototype"
  },
  {
    "path": "new Array(val).html",
    "chars": 136,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<meta charset=\"UTF-8\">\r\n<body>\r\n\r\n<script>\r\n  console.log(new Array(10))\r\n\r\n</script>\r\n\r\n\r\n\r\n</"
  },
  {
    "path": "new Proxy.html",
    "chars": 1262,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "newFunction.html",
    "chars": 1023,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<meta charset=\"UTF-8\">\r\n<body>\r\n\r\n\r\n  new function  用来检测js错误 可以替代eval() 字符串转js代码检查  字符串编译解析成js指"
  },
  {
    "path": "nodeType.html",
    "chars": 628,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<meta charset=\"UTF-8\">\r\n<body><p id=\"demo\">请点击按钮来获得 body 元素子节点的节点类型。</p>\r\n\r\n<button onclick=\"my"
  },
  {
    "path": "normalizeArrayChildren.html",
    "chars": 7167,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "object.html",
    "chars": 302,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "object.keys.html",
    "chars": 2173,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "once.html",
    "chars": 1882,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <script src=\"vue.js"
  },
  {
    "path": "parseFilters.html",
    "chars": 7842,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "parseModel.html",
    "chars": 4144,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "parseModifiers.html",
    "chars": 989,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "parsePath.html",
    "chars": 921,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "parseStyleText.html",
    "chars": 2063,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "parseText.html",
    "chars": 12075,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "performance.html",
    "chars": 840,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "prohibitedKeywordRE.html",
    "chars": 798,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "promise.html",
    "chars": 1007,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "proxy.html",
    "chars": 1137,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "repeat.html",
    "chars": 781,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "requestAnimationFrame.html",
    "chars": 1563,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<style>\r\n    #"
  },
  {
    "path": "requestAnimationFrame2.html",
    "chars": 1657,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<style>\r\n    #"
  },
  {
    "path": "setget.html",
    "chars": 458,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "simpleCheckRE.html",
    "chars": 1111,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "slice splice.html",
    "chars": 865,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "split.html",
    "chars": 926,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "startTagClose.html",
    "chars": 383,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "stopImmediatePropagation.html",
    "chars": 1007,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<meta charset=\"UTF-8\">\r\n<title>Title</title>\r\n<head>\r\n    <style>\r\n        p { height: 30px; wi"
  },
  {
    "path": "stripStringRE.html",
    "chars": 737,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "toUnicodeFun.html",
    "chars": 990,
    "preview": "<!DOCTYPE html>\r\n<html class=\"ui-page-login\">\r\n\r\n<head>\r\n\r\n\r\n</head>\r\n\r\n\r\n<body>\r\n<script type=\"text/javascript\">\r\n    f"
  },
  {
    "path": "transformModel.html",
    "chars": 1228,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "transition.html",
    "chars": 132,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n\r\n</bo"
  },
  {
    "path": "unaryOperatorsRE.html",
    "chars": 770,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "unaryOperatorsRE匹配字符串前一个字符串是什么.html",
    "chars": 816,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "unaryOperatorsRE匹配字符串前一个字符串是什么2.html",
    "chars": 891,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "vm._watcher === watcher.html",
    "chars": 449,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "vue.js",
    "chars": 556251,
    "preview": "/*!\n * Vue.js v2.5.16\n * (c) 2014-2018 Evan You\n * Released under the MIT License.\n * development   开发\n * production    "
  },
  {
    "path": "vue零散代码分析.html",
    "chars": 384,
    "preview": " <html>\r\n   <body>\r\n<script type=\"text/javascript\">\r\n     /* istanbul ignore next */\r\nfunction isNative (Ctor) {\r\n\r\n  re"
  },
  {
    "path": "window_performance.html",
    "chars": 2521,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <link rel=\"styleshe"
  },
  {
    "path": "window_performance1.html",
    "chars": 1180,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n    <link rel=\"styleshe"
  },
  {
    "path": "with.html",
    "chars": 1060,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n\r\n</head>\r\n<body>\r\n<scr"
  },
  {
    "path": "wrapFilter.html",
    "chars": 1172,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "三木分析.html",
    "chars": 550,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<style"
  },
  {
    "path": "三木分析1.html",
    "chars": 821,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "匿名函数执行.html",
    "chars": 216,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "发布-订阅模式.html",
    "chars": 3769,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n  <scr"
  },
  {
    "path": "数组api.html",
    "chars": 1468,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n<scrip"
  },
  {
    "path": "正则$.html",
    "chars": 604,
    "preview": "<html>\r\n<meta charset=\"UTF-8\">\r\n<script language=\"javascript\" type=\"text/javascript\">\r\n    // 那个$0,$1....$9是表示正则匹配的组。\r\n "
  },
  {
    "path": "观察者模式.html",
    "chars": 7532,
    "preview": "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n    <title>The \"Click the button\" page</title>\r\n    <meta charset=\"UTF-8\">\r\n</head>\r\n<b"
  },
  {
    "path": "静态方法与原型.html",
    "chars": 409,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n   <sc"
  },
  {
    "path": "高阶组件.html",
    "chars": 132,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <title>Title</title>\r\n</head>\r\n<body>\r\n\r\n</bo"
  }
]

// ... and 12 more files (download for full content)

About this extraction

This page contains the full source code of the qq281113270/vue-ddf- GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 176 files (850.1 KB), approximately 234.4k tokens, and a symbol index with 351 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!