Mount the this distinction between the page and the component

Mount this on page

Page({
    something: "Mount this variable on page".onLoad() {
        console.log("Page this content".this);
        this.handleOther();
    },

    handleOther(){}});Copy the code

Both Something and handleOther are available, and the prototype Proto also has a copy.

Mount this in component

Component({
    something: "Mount this variable in Component".lifetimes: {
        attached() {
            this.componentTest = "componentTest";
            this.handleOther();
            console.log("Component this content".this); }},methods: {
        handleOther(){},}});Copy the code

Only componentTest variable, not something variable. And the method exists on the prototype _proto_.

Impact: If the data related to UI rendering is thought to be stored in this.data object, but not needed for rendering, it is not placed in the developer of this.data object (this will speed up rendering somewhat and reduce the size of this.data). If you want to store data in this object, you need to distinguish between page and compenent:

  1. Page({xx: yy}); this.xx;
  2. If it is component, you can’t directly attach it to Component({xx:yy}). You need to attach it to this object manually during page initialization, such as attached() {this.xx = yy; }

The widget Component does not get the correct this in the closure function

The parent component WXML

<testComponent value="{{1}}" />
<testComponent value="{{2}}" />
<testComponent value="{{3}}" />
Copy the code

Can’t get this

Component({
    properties: {
        value: {
            type: Number.value: 0,}},lifetimes: {
        attached() {
            this.handleTest(this.data.value); }},methods: {
        handleTest: (function () {
            let instance = undefined;
            return function (value) {
                if(! instance) { instance =function (value) {
                        console.log("test", value, this); }; } instance(value); }; }) (),}});Copy the code

Get the same case of this

Component({
    properties: {
        value: {
            type: Number.value: 0,}},lifetimes: {
        attached() {
            this.handleTest(this.data.value); }},methods: {
        handleTest: (function () {
            let instance = undefined;
            return function (value) {
                if(! instance) { instance =(value) = > {	// The arrow function is created with this pointing to
                        console.log("test", value, this.this.data.value); }; } instance(value); }; }) (),}});Copy the code

Plan 1

The runtime executes the closure function, passing this outside the function to the inner function.

Disadvantages: Lack of elegance in passing values.

Component({
    properties: {
        value: {
            type: Number.value: 0,}},lifetimes: {
        attached() {
            this.handleTest()(this.data.value);	/ / attention}},methods: {
        handleTest: function () {
            let instance = undefined;
            const that = this;	/ / attention
            return function (value) {
                if(! instance) { instance =function (value) {
                        console.log("test", value, that);	/ / attention}; } instance(value); }; ,}}});Copy the code

Scheme 2

When the closure function executes, the call method is passed this.

Disadvantages: Lack of elegance in passing values.

Component({
    properties: {
        id: {
            type: Number.value: 0,}},lifetimes: {
        attached() {
            this.handleTest(this.id); }},methods: {
        handleTest: (function () {
            let instance = undefined;
            return function (id) {
                if(! instance) { instance =function (id) {	/ / attention
                        console.log("test", id, this);
                    };
                }
                instance.call(this, id);	/ / attention}; }) (),}});Copy the code

Plan 3

Let’s make instance global, so the global gets this.

Disadvantages: Instance is actually the business of the handleTest function (an internal variable), and is only used in the handleTest function. It does not need to be defined as a global variable.

Component({
    properties: {
        value: {
            type: Number.value: 0,}},lifetimes: {
        attached() {
            this.instance = undefined;	/ / attention
            this.handleTest(this.data.value); }},methods: {
        handleTest: (function () {	// There is no need to wrap a layer of functions
            return function (value) {
                if (!this.instance) {
                    this.instance = function (value) {	/ / attention
                        console.log("test", value, this);
                    };
                }
                this.instance(value);	/ / attention}; }) (),}});Copy the code

Several test cases combining the anti – shake throttling function

The variable this can be obtained, but without throttling (the handleTest function prints a log every time it is executed, not every 3 seconds) :

handleTest: (() = > {
    let instance = undefined;
    return function (value) {
        if (!this.instance) {
            instance = ThrottleUtil.throttle(3000.(value) = > {
                console.log('test'.this); }); } instance(value); }; }) (),Copy the code

By passing this, there is a throttling effect, but this is not available.

handleTest: (() = > {
    return ThrottleUtil.throttle(3000.(value, that) = > {	// Value is the evt argument to the action callback, not this.data.value
        console.log('test', value, that); }); }) (),Copy the code

By passing this, there is a throttling effect, but this is not available.

handleTest: ThrottleUtil.throttle(3000.(value, that) = > {	// Value is the evt argument to the action callback, not this.data.value
    console.log('test', value, that);
}),
Copy the code

Do not pass this, closure, throttling effect, this can be correctly retrieved.

handleTest: (function () {
    let instance = undefined;
    if(! instance) { instance = ThrottleUtil.throttle(3000.function (value) {
                console.log('this', value, this.this.data.value);	// The first argument value is the evt argument to the action callback, not this.data.value}); }returninstance; }) (),Copy the code

export default class ThrottleUtil {
    /** * throttling * Only executes the function once in a while. *@param Delay Determine time *@param Action Actual method *@param * {* toggleLastArg // Boolean. The default value is false (only the first click) *} *@returns {Function} Callback, callback the actual method */
    static throttle = (delay, action = () => {}, options) = > {  // Arrow function
        let last = 0;
        consttoggleLastArg = !! (options && options.toggleLastArg);let toggleLastArgTimer = null;
        // eslint-disable-next-line func-names
        return function (. args) {  // Anonymous function
            if (toggleLastArgTimer) clearTimeout(toggleLastArgTimer);
            const curr = new Date().getTime();
            if (curr - last > delay) {
                action.call(this. args);// Bind this to the callback with call
                last = curr;
            } else if (toggleLastArg) {
                toggleLastArgTimer = setTimeout(() = > {
                    action.call(this. args); }, delay); }}; }/** * Anti-shake * definition: after triggering the event for many times, the event handler only executes once, and is executed at the end of triggering operation * Principle: delay the processing function for delay operation, if the set delay comes, trigger the event again, then clear the last delay operation timer, re-timing. *@param Delay Determine time *@param Action Actual method *@returns {Function} Callback, callback the actual method */
    static debounce = (delay, action = () => {}) = > {
        let timer = null;
        // eslint-disable-next-line func-names
        return function (. args) {
            if (timer) {
                clearTimeout(timer);
            }
            timer = setTimeout(() = > {
                action.call(this. args); }, delay); }; }}Copy the code
The resources

The bind/call/apply the difference:

Bind returns the corresponding function (each time a new function is returned), so that it can be called later. Apply, call is called immediately. In addition, under the arrow function of ES6, call and apply’s this binding is disabled, meaning that even if call\apply binds this manually, it does not change its orientation.

Arrow function this:

  • The this object inside the function is the object at which it is defined, not used;
  • It should not be used as a constructor, that is, the new command should not be used, otherwise an error will be thrown.
  • You cannot use the Arguments object, which does not exist in the function body. The Rest argument can be used instead.
  • Yield cannot be used, so arrow functions cannot be used as Generator functions;