1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Vue 源碼解析 (二)initProxy 初始化代理

        共 10063字,需瀏覽 21分鐘

         ·

        2021-05-04 22:53

        Vue 源碼解析 (二)initProxy 初始化代理

        在 src/core/instance/proxy.js 找到源碼

        makeMap,allowedGlobals

        我們先來看看 makeMap 這個(gè)方法,做了什么處理:

        /*makeMap函數(shù), str參數(shù)是接受的字符串, expectsLowerCase參數(shù)是否需要小寫*/
         function makeMap(str, expectsLowerCase {
          /* 創(chuàng)建一個(gè)對象 */
          var map = Object.create(null);
          /*將字符串分割成數(shù)組*/
          var list = str.split(',');
          /*對數(shù)組進(jìn)行遍歷*/
          for (var i = 0; i < list.length; i++) {
             /*將每個(gè)key對應(yīng)的值設(shè)置為true*/
             map[list[i]] = true;
          }
          /*最終返回, 根據(jù)參數(shù)設(shè)置是否是需要轉(zhuǎn)換大小寫*/
          return expectsLowerCase
               ? function (val{
                  return map[val.toLowerCase()];
               }
               : function (val{
                  return map[val];
               }
        }

        然后給一些 js 內(nèi)置的全局方法做了相應(yīng)的處理:

        var allowedGlobals = makeMap(
            'Infinity,undefined,NaN,isFinite,isNaN,' +
            'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
            'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
            'require' // for Webpack/Browserify
        );

        makeMap 函數(shù)的只要作用把這些全局的API轉(zhuǎn)成以下的形式,

        {
            Infinity:true,
            undefined:true
        }

        isNative

        可以學(xué)習(xí)一下源碼是如何檢測是不是支持原生方法

        export function isNative (Ctor: any): boolean {
          return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
        }

        warnNonPresent

        這個(gè)方法的意思是不存在,未定義的屬性,方法被使用給出警告,我們來看看例子:

        <!DOCTYPE html>
        <html lang="en">

        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
        </head>

        <body>
            <script src="../vue.js"></script>
            <div id="app">
                <p>
                    {{msg}}
                </p>
            </div>
            <script>
                const vm = new Vue({
                    el: '#app',
                })
                console.log(vm)
            </script>
        </body>

        </html>

        上面例子直接在魔板中使用 msg 變量,但是他沒有在 data 中定義,此時(shí) warnNonPresent 會(huì)處理拋出警告如圖所示

        warnReservedPrefix

        源碼如下:

        const warnReservedPrefix = (target, key) => {
            warn(
              `Property "${key}" must be accessed with "$data.${key}" because ` +
              'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
              'prevent conflicts with Vue internals. ' +
              'See: https://vuejs.org/v2/api/#data',
              target
            )
          }

        用于檢測屬性 key 的聲明方法,是否是 $ 或者 _ 開頭的,如果是,會(huì)給出警告,拿個(gè)簡單的例子來看下效果:

        <!DOCTYPE html>
        <html lang="en">

        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
        </head>

        <body>
            <script src="../vue.js"></script>
            <div id="app">
                <p>
                    {{$hhh}}
                    {{_dddd}}
                </p>
            </div>
            <script>
                const vm = new Vue({
                    el'#app',
                    data() {
                        return {
                            $hhh'ddd',
                            _dddd'ffff'
                        }
                    },
                })
                console.log(vm)
            
        </script>
        </body>

        </html>

        hasHandler

        var hasHandler = {
            /*target要代理的對象, key在外部操作時(shí)訪問的屬性*/
            hasfunction has(target, key{
                /*key in target返回true或者false*/
                var has = key in target;
                /*在模板引擎里面,有一些屬性vm沒有進(jìn)行代理, 但是也能使用, 像Number,Object等*/
                var isAllowed = allowedGlobals(key) ||
                    (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data));
                /*在上面的has和isAllowed為false的情況下*/
                if (!has && !isAllowed) {
                    if (key in target.$data) {
                        warnReservedPrefix(target, key);
                    }
                    /*warnNonPresent函數(shù), 當(dāng)訪問屬性,沒有存在vm實(shí)例上, 會(huì)報(bào)錯(cuò)提示*/
                    else {
                        warnNonPresent(target, key);
                    }
                }
                /*has或者isAllowed*/
                return has || !isAllowed
            }
        };

        hasHandler 只配置了 has 鉤子 ,當(dāng)進(jìn)行propKey in proxy in 操作符 或者 with() 操作時(shí), 會(huì)觸發(fā) has鉤子函數(shù)

        hasHandler在查找key時(shí),從三個(gè)方向進(jìn)行查找

        • 代理的 target 對象 通過 in 操作符
        • 全局對象API allowedGlobals 函數(shù)
        • 查找是否是渲染函數(shù)的內(nèi)置方法 第一個(gè)字符以_開始 typeof key === 'string' && key.charAt(0) === '_'

        hasHandler, 首先去檢測 vm 實(shí)例上是否有該屬性, 下面的代碼是vm實(shí)例上可以查看到test

        new Vue({
           el:"#app",
           template:"<div>{{test}}</div>",
           data:{
               test
           }
        })

        如果在 vm 實(shí)例上沒有找到, 然后再去判斷下是否是一些全局的對象, 例如 Number 等, Number是語言所提供的 在模板中也可以使用

        new Vue({
           el:"#app",
           /*Number屬于語言提供的全局API*/
           template:"<div> {{ Number(test) +1 }}</div>",
           data:{
               test
           }
        })

        getHandler

        const getHandler = {
            get(target, key) {
              if (typeof key === 'string' && !(key in target)) {
                // 檢測 data 是屬性 key 是不是 $,_ 開頭
                if (key in target.$data) warnReservedPrefix(target, key)
                else warnNonPresent(target, key)
              }
              return target[key]
            }
        }

        initProxy

        initProxy = function initProxy(vm{
        /*hasProxy 判斷當(dāng)前環(huán)境是否支持es 提供的 Proxy*/
        if (hasProxy) {
           // determine which proxy handler to use
           var options = vm.$options;
           /*不同條件返回不同的handlers, getHandler或者h(yuǎn)asHandler */
           var handlers = options.render && options.render._withStripped
               ? getHandler
               : hasHandler;
           /* 代理vm實(shí)例 */
           vm._renderProxy = new Proxy(vm, handlers);
        else {
           vm._renderProxy = vm;
            }
        };


        瀏覽 69
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲狼友 | 欧美日本乱伦 | 日屄在线观看 | 和公在野外好爽好hhh视频 | 操逼在线看 | 久久嫩操| 日韩亚洲美洲欧洲二三区在线看 | 欧美日逼视频 | 人人天天爽 | 日韩精品福利 |