Rumah >hujung hadapan web >View.js >Mari kita bincangkan tentang masalah penunjuk ini dalam vue2.x Mengapakah ia menunjuk kepada contoh vue?

Mari kita bincangkan tentang masalah penunjuk ini dalam vue2.x Mengapakah ia menunjuk kepada contoh vue?

青灯夜游
青灯夜游ke hadapan
2022-01-20 10:23:564112semak imbas

Artikel ini akan membincangkan masalah penunjuk ini dalam vue2.x, dan memperkenalkan sebab ini menunjukkan contoh vue. Saya harap ia akan membantu semua orang.

Mari kita bincangkan tentang masalah penunjuk ini dalam vue2.x Mengapakah ia menunjuk kepada contoh vue?

Laluan kod dalam kumpulan secara tidak sengaja menyebut mengapa ini boleh dipanggil terus ke nilai dalam data, kaedah, prop dan dikira, kemudian semua orang mempunyai beberapa tekaan. tetapi tiada satu pun daripada mereka yang jelas untuk menjelaskan soalan ini, saya menyemak kod sumber vue saya mempunyai sedikit pemahaman dan menulis artikel untuk merekodkannya.

Timbulkan soalan

Biasanya bangunkan kod vue, hampir selalu tulis seperti ini

export default {
    data() {
        return {
            name: '彭鱼宴'
        }
    },
    methods: {
        greet() {
            console.log(`hello, 我是${this.name}`)
        }
    }
}

Mengapa this.name di sini boleh diakses terus ? Bagaimana pula dengan nama yang ditakrifkan dalam data, atau this.someFn boleh terus mengakses fungsi yang ditakrifkan dalam kaedah Dengan memikirkan soalan ini, saya mula melihat kod sumber vue2.x untuk mencari jawapannya.

Analisis kod sumber

Berikut ialah alamat kod sumber vue kod sumber vue. Mari kita lihat pada pembina contoh vue Pembina berada dalam direktori kod sumber /vue/src/core/instance/index.js Tidak banyak kod tersebut 🎜>

Struktur ini sangat mudah
function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue
menentukan sama ada kata kunci

digunakan untuk memanggil pembina, amaran dilemparkan di sini. Jika kata kunci if (!(this instanceof Vue)){} digunakan seperti biasa, maka fungsi new digunakan bukankah ia sangat mudah? thisnew_init

_analisis fungsi init

fungsi _init agak panjang dan melakukan banyak perkara, jadi saya tidak akan menerangkannya satu demi satu di sini Kandungan yang berkaitan dengan penerokaan ini harus berada dalam fungsi initState(vm).

let uid = 0

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // a uid
    vm._uid = uid++

    let startTag, endTag
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== &#39;production&#39; && config.performance && mark) {
      startTag = `vue-perf-start:${vm._uid}`
      endTag = `vue-perf-end:${vm._uid}`
      mark(startTag)
    }

    // a flag to avoid this being observed
    vm._isVue = true
    // merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== &#39;production&#39;) {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, &#39;beforeCreate&#39;)
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, &#39;created&#39;)

    /* istanbul ignore if */
    if (process.env.NODE_ENV !== &#39;production&#39; && config.performance && mark) {
      vm._name = formatComponentName(vm, false)
      mark(endTag)
      measure(`vue ${vm._name} init`, startTag, endTag)
    }

    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}

analisis fungsi initState

Dapat dilihat bahawa initState melakukan 5 perkara

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

Memulakan prop

    Memulakan kaedah
  • Memulakan data
  • Memulakan pengiraan
  • Memulakan jam tangan
  • Mari kita fokus pada kaedah permulaan dahulu

kaedah permulaan initMethods

initMethods terutamanya beberapa pertimbangan:

function initMethods (vm, methods) {
    var props = vm.$options.props;
    for (var key in methods) {
      {
        if (typeof methods[key] !== &#39;function&#39;) {
          warn(
            "Method \"" + key + "\" has type \"" + (typeof methods[key]) + "\" in the component definition. " +
            "Did you reference the function correctly?",
            vm
          );
        }
        if (props && hasOwn(props, key)) {
          warn(
            ("Method \"" + key + "\" has already been defined as a prop."),
            vm
          );
        }
        if ((key in vm) && isReserved(key)) {
          warn(
            "Method \"" + key + "\" conflicts with an existing Vue instance method. " +
            "Avoid defining component methods that start with _ or $."
          );
        }
      }
      vm[key] = typeof methods[key] !== &#39;function&#39; ? noop : bind(methods[key], vm);
    }
}

Kecuali pertimbangan yang dinyatakan di atas,

The perkara yang paling penting ialah untuk mentakrifkan semua kaedah dalam contoh vue, dan gunakan fungsi bind untuk menunjukkan fungsi ini kepada contoh Vue
判断methods中定义的函数是不是函数,不是函数就抛warning;
判断methods中定义的函数名是否与props冲突,冲突抛warning;
判断methods中定义的函数名是否与已经定义在Vue实例上的函数相冲突,冲突的话就建议开发者用_或者$开头命名;
, yang merupakan objek contoh Vue() baharu kami.

Ini menjelaskan mengapa ini boleh terus mengakses kaedah dalam kaedah.

data permulaan initData

Apakah yang dilakukan oleh initdata:

function initData (vm) {
    var data = vm.$options.data;
    data = vm._data = typeof data === &#39;function&#39;
      ? getData(data, vm)
      : data || {};
    if (!isPlainObject(data)) {
      data = {};
      warn(
        &#39;data functions should return an object:\n&#39; +
        &#39;https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function&#39;,
        vm
      );
    }
    // proxy data on instance
    var keys = Object.keys(data);
    var props = vm.$options.props;
    var methods = vm.$options.methods;
    var i = keys.length;
    while (i--) {
      var key = keys[i];
      {
        if (methods && hasOwn(methods, key)) {
          warn(
            ("Method \"" + key + "\" has already been defined as a data property."),
            vm
          );
        }
      }
      if (props && hasOwn(props, key)) {
        warn(
          "The data property \"" + key + "\" is already declared as a prop. " +
          "Use prop default value instead.",
          vm
        );
      } else if (!isReserved(key)) {
        proxy(vm, "_data", key);
      }
    }
    // observe data
    observe(data, true /* asRootData */);
}

Pertama tetapkan nilai kepada instance_data, fungsi getData Fungsi pemprosesan data mengembalikan objek

    untuk menilai data terakhir yang diperoleh, dan bukan objek untuk memberi amaran.
  • Tentukan sama ada fungsi dalam kaedah bercanggah dengan kunci dalam data
  • Tentukan sama ada terdapat konflik antara prop dan kunci dalam data
  • Tentukan sama ada ia adalah peribadi dalaman atribut terpelihara. Jika tidak, buat lapisan proksi, proksi kepada _data
  • Akhir sekali dengar data dan jadikan ia data responsif
  • Lihat fungsi proksi:

Malah,

di sini digunakan untuk mentakrifkan objek Tujuan
function noop (a, b, c) {}
var sharedPropertyDefinition = {
    enumerable: true,
    configurable: true,
    get: noop,
    set: noop
};

function proxy (target, sourceKey, key) {
    sharedPropertyDefinition.get = function proxyGetter () {
      return this[sourceKey][key]
    };
    sharedPropertyDefinition.set = function proxySetter (val) {
      this[sourceKey][key] = val;
    };
    Object.defineProperty(target, key, sharedPropertyDefinition);
}

Object.defineProperty
adalah untuk menjadikan

menunjuk ke seluruh

<.>proxy Fungsi observe bukan dalam skop perbincangan ini kawan-kawan yang berminat boleh menyemak sendiri source code. this.namethis._data.name

Ringkasan

Kembali kepada soalan yang dibangkitkan pada permulaan dan berikan jawapan: Kaedah dalam

pas
    menentukan
  • sebagai contoh Vue baharu (

    ), dan fungsi dalam kaedah juga ditakrifkan pada methods, jadi anda boleh mengakses terus fungsi dalam bind melalui this. vmvmthismethods

    Objek data yang dikembalikan oleh fungsi juga disimpan dalam
  • pada contoh Vue baharu (
  • ), yang sebenarnya diakses apabila mengakses

    Ia ialah data selepas proksi. vm_datathis.nameObject.definePropertyMengenai kelebihan dan kekurangan corak reka bentuk data ini, anda boleh terus meneroka, lagipun, ia bukan sebahagian daripada perbincangan ini. this._data.name

    [Cadangan berkaitan:
  • tutorial video vue.js
]

Atas ialah kandungan terperinci Mari kita bincangkan tentang masalah penunjuk ini dalam vue2.x Mengapakah ia menunjuk kepada contoh vue?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.cn. Jika ada pelanggaran, sila hubungi admin@php.cn Padam