简体   繁体   English

允许 JavaScript 闭包从父作用域继承变量

[英]Allowing JavaScript closure to inherit variables from the parent's scope

I am able to pass a variable from the parents scope to an anonymous function as follows:我能够将变量从父作用域传递给匿名函数,如下所示:

var f = function(myVar) {
    alert(myVar);
}
f('hello');

I don't wish to do so, but instead allow the closure to directly access the parent's scope.我不想这样做,而是允许闭包直接访问父级的作用域。

PHP allows me to do so as described by http://php.net/manual/en/functions.anonymous.php . PHP 允许我按照http://php.net/manual/en/functions.anonymous.php 的描述进行操作。 For instance, by using use ($message) , the parent's $message variable is available in the closure.例如,通过使用use ($message) ,父级的$message变量在闭包中可用。

Closures may also inherit variables from the parent scope.闭包也可以从父作用域继承变量。 Any such variables must be passed to the use language construct.任何此类变量都必须传递给使用语言结构。 ... ...

Example #3 Inheriting variables from the parent scope Example #3 从父作用域继承变量

// Inherit $message $example = function () use ($message) { var_dump($message); }; $example();

How can this be performed using JavaScript?如何使用 JavaScript 执行此操作?

The specific parts I am struggling with are this part of the below script.我正在努力解决的具体部分是以下脚本的这一部分。

select: function(e, ui) {
    //...
    if (typeof options.autocomplete.select !== "undefined"){
        options.autocomplete.select();
    }
}

select: function() {
    //How can I access editable, elem, and ui.  It shows each as being undefined yet I can access it in the parents scope
}

When executing the script, it shows them as undefined, yet I see they are defined by my console.log in the parent scope.执行脚本时,它将它们显示为未定义,但我看到它们是由我的console.log在父作用域中定义的。

Furthermore, if I explicitly pass them using options.autocomplete.select(editable, ui, elem);此外,如果我使用options.autocomplete.select(editable, ui, elem);显式传递它们options.autocomplete.select(editable, ui, elem); , I can access them. ,我可以访问它们。

full script:完整脚本:

xWrap(dialog.find('a.car'),'autocomplete',chartsId, {name:'carId', title:'Car Name', autocomplete: {
    url: "/1.0/cars",
    params: {term:null, fields:['id','name']},
    select: function(editable, elem, ui) {
        console.log('chart-list select','editable',editable,'elem',elem,'this',this,'ui', ui)
        var $td=$(elem).parent()
        var series = $td.closest('table').find('th').eq($td.index()).data('id');
        var category=$td.parent().data('id');
        editable.option('params', {'carId': ui.item.id});
        editable.option('url', '/1.0/cars/'+carId+'/'+series+'/'+category)
    }
}});

$.fn.xEdit = function(type, options) {
    //console.log('xEdit',this,type, options);
    function chk(o, a) {
        for (var i = 0; i < a.length; i++) {
            if (typeof o[a[i]] === "undefined"){
                $.error('Property "' +  a[i] + '" must be provided to jQuery.xEdit');
            }
        }
    }
    var common={
        placement: 'right',
        ajaxOptions: {type: "PUT"},
        send: 'always'
        // pk: null, title: null, params: {name: null}, url: null, //Must be passed
    }
    if (typeof options.name === "undefined"){
        $.error('Property "name" must be provided to jQuery.xEdit');
    }
    options.params={name: options.name};
    delete(options.name);
    switch(type) {
        case 'text':
            options.type='text';
            chk(options,['pk','title','url']);
            this.editable($.extend({}, common, options));
            break;
        case 'select':
            options.type='select';
            chk(options,['pk','title','url', 'source']);
            this.editable($.extend({}, common, {value: null}, options));
            break;
        case 'autocomplete':
            options.type='text';
            chk(options,['pk','title','url','autocomplete']);
            chk(options.autocomplete,['url','params']);
            this.editable($.extend({}, common, {value: null}, options))
            .on('shown', function(e, editable) {
                //console.log('on.show','this',this,'e',e,'editable',editable)
                var elem=this;    //Needed only for rare case 
                var $input=editable.input.$input.val('');
                var $button=$input.parent().next().find('button.editable-submit').css('opacity', 0.3)
                .bind('click.prevent', function() {return false;});
                $input.focus(function() {
                    $button.css('opacity', 0.3).bind('click.prevent', function() {return false;});
                })
                .autocomplete({
                    source: function( request, response ) { //get All Points
                        options.autocomplete.params.term=request.term;
                        $.getJSON( options.autocomplete.url, options.autocomplete.params, function(json) {
                            var data=[];
                            for (var j = 0; j < json.length; j++) {
                                data.push({id:json[j].id,label:json[j].name});
                            }
                            response(data);
                        } );
                    },
                    minLength: 2,
                    position: { my : "left top+20", at: "left bottom" },
                    select: function(e, ui) {
                        console.log('xEdit select','editable',editable,'elem',elem,'this',this,'ui', ui, 'options', options)
                        $input.blur();
                        $button.css('opacity', 1).unbind('click.prevent');
                        if (typeof options.autocomplete.select !== "undefined"){
                            options.autocomplete.select(editable, elem, ui,);
                        }
                    }
                })
                .autocomplete('widget').click(function() {return false;});
            });
            break;
        default: $.error('Type "' +  type + '" is not available for jQuery.xEdit');
    }
};

Global variable全局变量

 var myVar = "hello"; function f () { console.log(myVar); } function myMainFn() { f(); } myMainFn();

Using arrow functions使用箭头函数

 var f = () => { console.log(this.myVar); } function myMainFn() { // The arrow function above has access to window's context window.myVar = "hello"; f(); } myMainFn();

Binding the this context绑定this上下文

 function f () { console.log(this.myVar); } function myMainFn() { this.myVar = "hello"; f.bind(this)(); } myMainFn();

Use an object to hold the variable使用对象来保存变量

The closure will be made on the object, but modifications to internal elements will be visible.关闭将在对象上进行,但对内部元素的修改将是可见的。

 function f () { var myObj = { myVar: "hello" } function myMainFn() { f(); } myMainFn(); console.log(myObj.myVar); }

According to your code, an alternative would be bind the this context and set those attributes:根据您的代码,另一种方法是绑定this上下文并设置这些属性:

select: function(e, ui) {
    //...
    if (typeof options.autocomplete.select !== "undefined") {
        this.editable = editable;
        this.elem = elem;
        this.ui = ui;
                                          +--- Bind with the current context 'this'
                                          |
                                          v
        options.autocomplete.select.bind(this)();
    }
}

select: function() {
    //How can I access editable, elem, and ui.  It shows each as being undefined yet I can access it in the parents scope
    console.log(this.editable);
    console.log(this.elem);
    console.log(this.ui);
}

You can already access variables from the enclosing scope:您已经可以从封闭范围访问变量:

 let foo = 3; function bar() { console.log(foo); } bar();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM