繁体   English   中英

在运行时无法获取函数的全局执行上下文变量

[英]can't get function's global execution context variable in runtime

我想这是纯香草的javascript问题。

我需要重写一个函数showDatepicker ,我这样做是这样的:

            const Base = (Handsontable.editors.DateEditor as any).prototype as any;
            const DateEditorHelper = Base.extend();

            DateEditorHelper.prototype.showDatepicker = function (event: any[]) {                    
                Base.showDatepicker.apply(this, event)

                this.$datePicker.config(this.getDatePickerConfig());

                var offset = this.TD.getBoundingClientRect();
                var dateFormat = this.cellProperties.dateFormat || this.defaultDateFormat;
                var datePickerConfig = this.$datePicker.config();
                var dateStr = void 0;
                var isMouseDown = this.instance.view.isMouseDown();
                var isMeta = event ? (0, _unicode.isMetaKey)(event.keyCode) : false;

                this.datePickerStyle.top = offset.top >= $(window).height() - 224 ? window.pageYOffset + offset.top - 224 + (0, _element.outerHeight)(this.TD) + 'px' : window.pageYOffset + offset.top + (0, _element.outerHeight)(this.TD) + 'px';
                this.datePickerStyle.left = window.pageXOffset + offset.left + 'px';

                this.$datePicker._onInputFocus = function () { };
                datePickerConfig.format = dateFormat;

                if (this.originalValue) {
                    dateStr = this.originalValue;

                    if ((0, _moment2.default)(dateStr, dateFormat, true).isValid()) {
                        this.$datePicker.setMoment((0, _moment2.default)(dateStr, dateFormat), true);
                    }

                    // workaround for date/time cells - pikaday resets the cell value to 12:00 AM by default, this will overwrite the value.
                    if (this.getValue() !== this.originalValue) {
                        this.setValue(this.originalValue);
                    }

                    if (!isMeta && !isMouseDown) {
                        this.setValue('');
                    }
                } else if (this.cellProperties.defaultDate) {
                    dateStr = this.cellProperties.defaultDate;

                    datePickerConfig.defaultDate = dateStr;

                    if ((0, _moment2.default)(dateStr, dateFormat, true).isValid()) {
                        this.$datePicker.setMoment((0, _moment2.default)(dateStr, dateFormat), true);
                    }

                    if (!isMeta && !isMouseDown) {
                        this.setValue('');
                    }
                } else {
                    // if a default date is not defined, set a soft-default-date: display the current day and month in the
                    // datepicker, but don't fill the editor input
                    this.$datePicker.gotoToday();
                }

                this.datePickerStyle.display = 'block';
                this.$datePicker.show();
            }

它实际上是原始函数的代码,在其中做了一些小的修改。 我认为该函数的内部代码变量将在运行时进行评估(我不是在谈论内部函数作用域变量作为其参数或在其中声明的变量,而是关于执行上下文的全局变量)。 在函数执行之前,根本没有任何错误(当浏览器读取函数时,它不会抱怨某些变量未定义),但是在运行时,我遇到了这个错误:

Uncaught ReferenceError: _unicode is not defined
    at eval (eval at DateEditorHelper.showDatepicker (module.js?v=64fd5db96274:40281), <anonymous>:1:1)
    at e.DateEditorHelper.showDatepicker (module.js?v=64fd5db96274:40281)

被覆盖的函数与应在原始函数运行的上下文中运行,我不知道为什么未定义全局变量。

原始功能是可动手操作的内置编辑器(datePicker)。 我从这个线程这个得到的首要思想

您说您是从原始函数复制了代码并进行了较小的更改。 问题似乎是您正在使用名为_unicode的变量。 您要定义该变量吗?

用修改后的“原始”代码替换方法的代码时,必须确保也复制了旧代码引用的任何其他变量/函数。

您必须考虑到原始方法是在另一个上下文中定义的。 作者可能并不打算派生此类或重写其方法。

模块(或IIFE)的优点是,您可以在封装实现的私有部分的同时定义公共API。 当然,这意味着覆盖方法或功能要困难得多。

在这种情况下,变量_unicode显然旨在成为私有实现的一部分。 其名称遵循以下划线开头的约定这一事实几乎证明了这一点。 它可能在与DatePickerHelper相同的模块中定义,或从另一个模块中导入,但是无论如何我几乎确定它没有导出,因此您无法访问它,并且代码失败。

为了使覆盖_unicode ,您必须更改代码以避免使用_unicode变量,或者以与原始代码相同的方式自己定义。 当然,取决于定义的方式,您可能最终不得不“复制”大量代码,但这是任何试图从外部库中重写方法的JavaScript程序员都遇到的问题。

让我们看一下这个“私有实现”的例子:

 (function() { // this is a function I want to keep private. function giveMeHello() { return 'hello, '; } // this is the class I want to share class Greeting { greet(name) { console.log(giveMeHello() + name); } } window.Greeting = Greeting; })(); const greet1 = new Greeting(); greet1.greet('Oscar'); // outputs 'hello, Oscar'. // As a consumer of Greeting, I don't like the way if greets people. I want the name to be in uppercase // implementation is practically identical to original code Greeting.prototype.greet = function() { console.log(giveMeHello() + name.toUpperCase()); }; // Let's use it! greet1.greet('John'); // Oh! Error! giveMeHello is not defined! 

如您所见,在此示例中,我也是如此。 但是,我的实现与原始方法一样,依赖于giveMeHello函数。 但是giveMeHello不是全局或公共函数。 从我重写该功能的那一刻起,我还没有访问它的权限。 因此,当我执行该方法时,它将失败。

如果现在我只是在覆盖该方法之前复制了giveMeHello函数,它将起作用。

你现在明白了吗? 如果没有,我建议您阅读有关JavaScript范围的更多信息,这超出了StackOverflow的目的。

暂无
暂无

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

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