checking for undefined variable with Underscore.js

2019-02-19 20:29发布

I'm having a problem with Underscore.js templates and Internet Explorer. Here's part of the template which is causing trouble:

<p>
  <% if ( typeof description !== 'undefined' ) { %>
    <%- description %>
  <% } else { %>
    No description
  <% } %>
</p>

When the variable description is undefined (which means I'm not supplying it to the template at all, the variable does not exist), this works just fine in Safari, Firefox, Chrome.

Internet Explorer however, doesn't work correctly. Instead of showing No description IE8 and IE9 show [object HTMLMetaElement], and IE7 shows [object].

Checking the result of typeof description returns undefined in Safari, Firefox, Chrome, but apparently Internet Explorer returns object instead.

I already tried Underscore.js's _.isUndefined(value) function, but that one doesn't work when the variable does not exist.

Does anyone know a workaround for this problem? (note that I am unable to supply the variable with no value - it either exists, or it doesn't)

Update I found a workaround in one of the Underscore.js Github issues https://github.com/documentcloud/underscore/issues/237#issuecomment-1781951

Can someone explain why IE behaves differently, and why the workaround actually works?

Update 2 @John-DavidDalton has provided another, better workaround in the comments below (linking directly to it doesn't seem to work)

2条回答
\"骚年 ilove
2楼-- · 2019-02-19 20:57

If you typeof something and the something is null, object is returned. Try checking for null after checking for 'undefined'.

查看更多
淡お忘
3楼-- · 2019-02-19 21:22

From the fine manual:

By default, template places the values from your data in the local scope via the with statement.

You can see what's going on using the compiled template's source property:

​var t = _.template('<%= v %>');
console.log(t.source);​​​​​​​​​​​​​​​​​​​

gives you (tweaked for clarity):

function(obj) {
    var __t, __p = '';
    with(obj || {}) {
      __p += '' + ((__t = ( v )) == null ? '' : __t) + '';
    }
    return __p;
}

The with is the source of your problem:

JavaScript looks up an unqualified name by searching a scope chain associated with the execution context of the script or function containing that unqualified name. The 'with' statement adds the given object to the head of this scope chain during the evaluation of its statement body. If an unqualified name used in the body matches a property in the scope chain, then the name is bound to the property and the object containing the property. Otherwise a 'ReferenceError' is thrown.

So given this:

with(obj) {
    console.log(pancakes)
}

JavaScript will first look for obj.pancakes and if there is no pancakes property in obj, it will look for pancakes in the global scope. Apparently IE has a window.description value which represents one of the page's <meta> tags. Using your own namespace inside the template (as in the work-around) sort of negates what with does and keeps you from getting to the global window properties.

查看更多
登录 后发表回答