[JavaScript] Several methods of accessing externally-scoped variables with the same name or this

We have discussed the difference in scope between python and js when implementing closures.

https://blog.csdn.net/qq_16181837/article/details/104805151

I encountered a related problem today

How does js access the variable with the same name in the external scope?
In python, we have nolocal and global keywords, which can easily declare the scope of a variable:

def outer():
	outer_var = 'outer'
	def inner():
		# 闭包
		nolocal outer_var
		outer_var = 'inner'
		return outer_var
	print(inner())
	
outer()

Output:

inner


But as far as I know, js does not have such keywords.
Checked a lot of information

I offer a few methods here:

Method one, access the object of external packaging

function outer() {
    
    
    var variable = 'outer';
    var obj = {
    
    
        outer_var: variable
    };
    function inner() {
    
    
        var variable = 'inner';
        console.log(obj.outer_var);
    }
    inner();
}
outer()

Output:

inner

Method two, access external variables through functions

function outer() {
    
    
    var variable = 'outer';

    function get_outer() {
    
    
        return variable;
    }
    function inner() {
    
    
        var variable = 'inner';
        console.log(get_outer());
    }
    inner();
}
outer()

Output:

inner


You may ask, why do we have to make internal variables have the same names as external ones?
Indeed, in some cases we can declare a variable such as local_variable internally to show distinction, but in some cases it is not possible

Look at this example:

class test {
    
    
    constructor(btn) {
    
    
        // 给传进来的 btn 绑定一个回调事件
        // 调用对象的 method 方法

        $(btn).on('click', function(outer_this) {
    
    
            // 但是这里的 this 是调用回调函数的对象,即 btn 而不是指向对象的 this
            // 如何访问外部作用域的 this?
            return function() {
    
    
                this.method();
            }
        }(this));
    }

    method() {
    
    
        console.log('Calling method.');
    }
}

var obj = new test($('.btn-1')[0])

Error:
Insert picture description here
Let's take a look at who this this points to: When
Insert picture description here
registering an event, the function is bound to the object .btn-1 as a property.
So naturally, this will point to this object when calling back.

We all say js everything is an object, so why do I say

In some cases, we can declare a variable such as local_variable internally to show distinction, but in some cases it is not possible

How to do it?
The first method above can be used, that is, to access the externally packaged object,
but the second method is not possible, because the this in the get_outer function points to its caller, that is, the global object or undefined.
For this situation, I would like to introduce three methods:

Method one, change the function this point

Here we use a method bind of the function , which provides an object argument for the bind method, which returns a copy of the function bound to the object.
That is, fun.bind(obj) will return an obj.fun for later calling.

class test {
    
    
    constructor(btn) {
    
    
        btn.addEventListener('click', function() {
    
    
            this.method();
        }.bind(this));
    }
    method() {
    
    
        console.log('Calling method.');
    }
}
var obj = new test($('.btn-1')[0]);

Output:

Calling method.

Two methods are expanded here:

fun.call(obj[, arg1[, arg2[, arg3…]]])
fun.apply(obj, arg1, arg2, arg3…)

These two methods will execute the function immediately, and change the this at runtime to the first parameter obj, and pass in the specified parameters.
The difference is that the second parameter of the apply method is an array, while call is a list.

Method two, transfer parameters

Ashamed, I have been thinking about how to directly access external variables like python, ignoring the simplest method,
but there is a problem. The addEventListener method of native webapi does not provide an interface for passing in the parameters of the callback function, so Here you need to use closures to achieve:

Primitive webapi:

 class test {
    
    
     constructor(btn) {
    
    
         btn.addEventListener('click', function(outer_this) {
    
    
             return function() {
    
    
                 outer_this.method();
             }
         }(this));
     }
     method() {
    
    
         console.log('Calling method.');
     }
 }

 var obj = new test($('.btn-1')[0]);

jQuery:

In comparison, jquery is much more convenient because it provides an interface for passing in parameters:

 class test {
    
    
     constructor(btn) {
    
    
         $(btn).on('click', {
    
    
             outer_this: this
         }, function(jq_event) {
    
    
             jq_event.data.outer_this.method();
         });
     }
     method() {
    
    
         console.log('Calling method.');
     }
 }

 var obj = new test($('.btn-1')[0]);

Method three

There is a simpler one. This should be the most natural way of thinking, but I think it’s complicated

 class test {
    
    
     constructor(btn) {
    
    
     	var that = this;
         $(btn).on('click', function(jq_event) {
    
    
             that.method();
         });
     }
     method() {
    
    
         console.log('Calling method.');
     }
 }

 var obj = new test($('.btn-1')[0]);

The on of jq allows you to pass in an object. When the function is called back, jq will call the function and pass in a jq event object. The data attribute in it is the object you passed in when you registered.

So far, the problem is basically solved. But in fact, this is a remedy. It's a pity that js lacks the elegant keywords that directly declare the scope of variables like python.

Guess you like

Origin blog.csdn.net/qq_16181837/article/details/104965043