1. Computed attributes Advantages of computed and simple usage

1. Simple use of computed attributes

  1. The computed parameter passes a function that is handled internally by vUE as a get function, and the set function is set by default to a console alarm that the user changes the plusOne value
    const count = ref(1)
    const plusOne = computed(() = > count.value + 1)

    console.log(plusOne.value) / / 2

    plusOne.value++ // error
Copy the code
  1. The computed parameter is an object that contains user-written GET and SET functions, which are used internally by default in vUE
const count = ref(1)
const plusOne = computed({
  get: () = > count.value + 1.set: val= > {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) / / 0
Copy the code

2. Calculate the benefits of attributes

  1. The calculated property itself is lazy, and the value result can be cached. The calculated property will be computed to obtain the latest value only after the value dependent on the calculated property is changed. Compared to ordinary functions, computed attributes save performance costs caused by unnecessary function execution
  2. The core of calculation attribute itself is also the core API effect side effect function of responsive system. Track relies on collection function and Trriger trigger dependent function. When the calculation attribute is executed, The effect function of the calculated property is collected when the value of the property accessed within the calculated property is changed. When this value is released, the effect function of the calculated property is executed again to update the data

2. Calculate the property logic implementation

  1. You normalize the parameters first, because parameters to evaluate properties can be passed to objects and functions, so you get and default the GET and set functions based on the type of the parameter
 const computed = (getterOrOptions) = > {
    /* * The first standardized parameter * getterOrOptions has two formats * 1. The user passes the function, assigning getterOrOptions directly to the getter function * 2. The user passes in an object that contains a getter and a setter function, fetches the getter and stter, respectively. Second step for computed function creation Passes in three parameters * 1. Getter function * 2. Setter function * indicates whether a set can be set. Read only */ based on whether getterOrOptions is a function and whether setters exist
    let getter;
    let setter;
    if (isFunction(getterOrOptions)) {
        getter = getterOrOptions;
        setter = () = > { console.error("Cannot assign a value to a calculated property")}}else {
        const { get, set } = getterOrOptions;
        getter = get || (() = >{}); setter = set || (() = >{}); }// , isFunction(getterOrOptions) || ! getterOrOptions.set
    return new Computed(getter, setter)
}
Copy the code
  1. The Computed class is implemented below, and inside is the main logic for Computed attributes
    1. The first values are dirty and _value. Dirty is used to determine whether to re-evaluate the effect side effect function of the calculated attribute. Dirty is set to true in the Trriger function only when the value of the calculated attribute depends on changes. The default value for dirty is true, because the first execution of the computed property requires the computed property’s value to be computed. _value is used to store the value of the calculated attribute, which defaults to an empty string
class Computed {
    constructor(getter, setter) {
        / / the getter function
        this.getter = getter;
        / / setter function
        this.setter = setter;
        // Read-only Cannot set the value
        // Used to indicate whether the calculated attributes need to be recalculated
        this.dirty = true;
        // Calculates the value of the attribute
        this._value = ""; }}Copy the code
  1. The user-written getter function is encapsulated by the effect side function. When the value dependent on the calculated property changes, the effect function is executed. The user-written getter function is executed inside the effect function to obtain the final value of the calculated property
class Computed {
    constructor(getter, setter) {
        / /... Omit previous code
        // Calculates the value of the attribute
        this._value = "";
         // Create a side effect function for calculated properties
        this.effect = effect(getter, {
            // The effect function is not executed by default when the lazy flag is true. The effect function is evaluated only when the calculated property is actually used
            lazy: true.// When scheduler triggers, the dependent data changes and needs to be recalculated. Dirty must be set to true
            // This scheduler function is executed when the value of the dependency changes
            scheduler: () = > {
                if (!this.dirty) {
                    this.dirty = true;
                    // When the calculated property value changes, the notification is used where the calculated property value is to be updated
                    trigger(this, TriggerOpTypes.SET, "value"); }})}}Copy the code
  1. When the user obtains the calculated property value, such as in the simple use example at the beginning of this article, the calculated property value is obtained with plusone. value, because the getter and setter of JS are used to obtain and set the value, and the store and value function are set for a certain property. Intercepts the access behavior of this property.
   class Computed {
       get value () {
           // Do some logic here, then return the value
       }

       set value (val) {
           // Perform some logic here, and then modify the specified value}}Copy the code

Setting values is relatively simple, just use Computed instantiation of the setter function passed in. This.setter (val);

  1. Gets the logical processing of the value

    1. When obtaining the value of dirty, the first step is to determine the value of dirty. When dirty is true, it indicates that the value of calculated dependence has changed. Then effect is executed to obtain the latest value of calculated attribute, and dirty is reset to false after obtaining the value. Otherwise, when you evaluate a property, you always use the last evaluation

    2. After the evaluation of calculated attributes is completed, track needs to collect the corresponding dependencies (that is, the effect function of the calculated attributes is used to facilitate the subsequent notification of updating the calculated attributes).

    class Computed {
        get value () {
            // When obtaining the value, determine whether to recalculate the value according to the dirty.
            // Rerun the effect side effect function if necessary, with dirty set to true or read directly from the _value cache
            if (this.dirty) {
                this._value = this.effect();
                this.dirty = false;
            }
            // Collect compute function dependencies
            track(this."value");
            / / return a value
            return this._value
        }

        set value (val) {
             this.setter(val); }}Copy the code

5.Com PuTED overall code

class Computed {
    constructor(getter, setter) {
        / / the getter function
        this.getter = getter;
        / / setter function
        this.setter = setter;
        // Read-only Cannot set the value
        // Used to indicate whether the calculated attributes need to be recalculated
        this.dirty = true;
        // Calculates the value of the attribute
        this._value = "";
        // Create a side effect function for calculated properties
        this.effect = effect(getter, {
            // Effect is not executed by default when the lazy flag is true. Effect is executed only when the calculated property is actually used
            lazy: true.// When scheduler triggers, it indicates the dependent data changes that need to be recalculated. Dirty must be set to true
            scheduler: () = > {
                if (!this.dirty) {
                    this.dirty = true;
                    // When the calculated property value changes, the notification is used where the calculated property value is to be updated
                    trigger(this, TriggerOpTypes.SET, "value");
                }
            }
        })
    }
    get value () {
        // When obtaining the value, determine whether the value needs to be recalculated according to the dirty. If so, rerun the effect function.
        // Set dirty to true or read directly from the _value cache
        if (this.dirty) {
            this._value = this.effect();
            this.dirty = false;
        }
        // Collect compute function dependencies
        track(this."value");
        / / return a value
        return this._value
    }

    set value (val) {
        this.setter(val); }}Copy the code

3. Making the address

The code links to the miniVue3 folder for a simple implementation of vue3 code