最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Safari on IOS generates "ReferenceError: Ca ni n't find variable:" - Stack Overflow

programmeradmin3浏览0评论

The following code is working correctly for all browsers including Safari on Mac, with the exception of Safari on the iPhone.

I have a timer Object that could potentially be running that is defined like so:

//delay background change until animation is finished
lastTimer = setTimeout(function () {
  $('#' + targetDiv).removeClass('open');
}, 150);

Later, I need to check if the timer is running, and if so cancel it. Here is the code I am using:

if (lastTimer != null) { clearTimeout(lastTimer); }

This is where IOS Safari generates the JavaScript Error:

"ReferenceError: Can't find variable: lastTimer".

Any ideas on why the check for null is not preventing the error, like it seems to with the other browsers?

Here is the full code for the two pertaining functions in answer to the reply below: (edited with solution)

// Class for handling the animations for the drop down menus
var dropDownMenu = {
lastTimer: null,
openMenu: function (targetDiv) {
    if (targetDiv != null) {
        var targetHeight = $('#' + targetDiv).height();
        $('#' + targetDiv).stop(true); //stop an previous animations and clear queue
        if (this.lastTimer != null) { clearTimeout(this.lastTimer); } //stop possible pending timer to prevent background change
        console.log("testing b");
        $('#mainNavigation #dropDownMenu ul').removeClass('open'); // make sure all closed menus show corrent bgd
        $('#' + targetDiv).animate({
            bottom: -(targetHeight + 30)
        }, 200, 'swing');
        $('#' + targetDiv).addClass('open');
    }

},
closeMenu: function (targetDiv) {
    if (targetDiv != null) {
        $('#' + targetDiv).stop(true); //stop an previous animations and clear queue
        $('#' + targetDiv).animate({
            bottom: 0
        }, 200, 'swing');
        //delay background change until animation is finished
        this.lastTimer = setTimeout(function () {
            $('#' + targetDiv).removeClass('open');
        }, 150);
    }
}
}

When the error happens in iOS the execution stops and my test console.log immediately after does not execute.

The following code is working correctly for all browsers including Safari on Mac, with the exception of Safari on the iPhone.

I have a timer Object that could potentially be running that is defined like so:

//delay background change until animation is finished
lastTimer = setTimeout(function () {
  $('#' + targetDiv).removeClass('open');
}, 150);

Later, I need to check if the timer is running, and if so cancel it. Here is the code I am using:

if (lastTimer != null) { clearTimeout(lastTimer); }

This is where IOS Safari generates the JavaScript Error:

"ReferenceError: Can't find variable: lastTimer".

Any ideas on why the check for null is not preventing the error, like it seems to with the other browsers?

Here is the full code for the two pertaining functions in answer to the reply below: (edited with solution)

// Class for handling the animations for the drop down menus
var dropDownMenu = {
lastTimer: null,
openMenu: function (targetDiv) {
    if (targetDiv != null) {
        var targetHeight = $('#' + targetDiv).height();
        $('#' + targetDiv).stop(true); //stop an previous animations and clear queue
        if (this.lastTimer != null) { clearTimeout(this.lastTimer); } //stop possible pending timer to prevent background change
        console.log("testing b");
        $('#mainNavigation #dropDownMenu ul').removeClass('open'); // make sure all closed menus show corrent bgd
        $('#' + targetDiv).animate({
            bottom: -(targetHeight + 30)
        }, 200, 'swing');
        $('#' + targetDiv).addClass('open');
    }

},
closeMenu: function (targetDiv) {
    if (targetDiv != null) {
        $('#' + targetDiv).stop(true); //stop an previous animations and clear queue
        $('#' + targetDiv).animate({
            bottom: 0
        }, 200, 'swing');
        //delay background change until animation is finished
        this.lastTimer = setTimeout(function () {
            $('#' + targetDiv).removeClass('open');
        }, 150);
    }
}
}

When the error happens in iOS the execution stops and my test console.log immediately after does not execute.

Share Improve this question edited Jun 16, 2020 at 15:25 QuickSilver 4,0452 gold badges14 silver badges30 bronze badges asked Jun 13, 2012 at 18:59 Mark1270287Mark1270287 4211 gold badge4 silver badges14 bronze badges 8
  • Is it a global variable? Is there any code that is conditionally run based on the browser? Can you provide more code? – user1106925 Commented Jun 13, 2012 at 19:07
  • added full code for the two functions above. They are in a class together, but the timer itself is not global. It worked in all other browsers correctly, so I was hoping to avoid making it a global var. – Mark1270287 Commented Jun 13, 2012 at 19:17
  • If it isn't global, where is it declared? I don't see a var lastTimer anywhere. If you haven't declared the variable, then try putting var lastTimer; just before the var dropDownMenu = { line. – user1106925 Commented Jun 13, 2012 at 19:20
  • 1 @Mark1270287: That's not what I said to do. You've made it a property of the object. Please try what I suggested before trying something else. JavaScript does not have classes. If you do want it as a property, then you'd need to change to this.lastTimer. – user1106925 Commented Jun 13, 2012 at 19:28
  • 1 Okay, defining it as a property and adding the this fixed it. Thank you! – Mark1270287 Commented Jun 13, 2012 at 19:32
 |  Show 3 more comments

5 Answers 5

Reset to default 12

I want to chime in on this to explain. Mobile Safari is less forgiving when checking for undefined using the simple check,

if variable

When you come across situations like this then use,

if typeof variable === "undefined"

Attaching the variable to "this" is one solution here but it's just taking advantage of the fact that definedVariable.undefinedProperty returns undefined, whereas referencing an undefined variable directly will cause the reference error in some runtime environments.

I would advise not getting into the habit of attaching to "this" if it's not necessary.

There's one other potential issue that I think needs to be stated. Safari on iOS* can be very aggressive on caching and not reloading a clean copy of your code.

e.g. if you executed one version of your code without the variable defined, then fixed the code but the error continues to show on reloading (even if you close the browser/reboot the phone)

To solve this, tap and hold (aka Long Press) the reload icon in the address bar and a menu pops up with 2 options Request Desktop Site and Reload Without Content Blockers. Choosing either one of these causes a Real reload of all of the content... which resolves the issue with any cached buggy code.

*Not just Safari. Chrome on iOS (which is built on Apple's version of WebKit) can exhibit the same issue.

Your issue seems to be that on IOS, the openMenu is being invoked first.

This means that you're trying to get the value of an undeclared variable, resulting in the ReferenceError.

Oddly, you can assign to an undeclared variable, which implicitly makes it global. So if closeMenu is called first, then the assignment happens first, making the variable implicitly declared.

The proper solution is to always declare variables before using them.

var lastTimer;

But as it turned out, you preferred to use a property on the current object instead of a variable. As such, the solution was to access the property in the methods...

this.lastTimer

This will never throw a ReferenceError, even if the property is not declared.

You have a global variable in your code. Not declaring var makes it global.

Try changing:

if (lastTimer != null)

to

if (typeof lastTimer !=="undefined" && lastTimer)

if you are sticking with it being global.

In my case Safari 13 didnt work with ES6 const hence i needed to replace it with var

发布评论

评论列表(0)

  1. 暂无评论