New Host Object Primer

Discussion in 'Javascript' started by David Mark, Mar 23, 2010.

  1. David Mark

    David Mark Guest

    David Mark, Mar 23, 2010
    #1
    1. Advertising

  2. David Mark wrote:

    > I have posted a new primer related to host objects and feature
    > detection/testing.
    >
    > http://www.cinsoft.net/host.html
    >
    > I think that about sums up the progress (and lack thereof) of the last
    > few years.


    ISTM the RegExp is borken:

    var reFeaturedMethod = new RegExp('^function|object$', 'i');

    It matches case-insensitive either "function" at the begin of input or
    "object" at the end, when it should match case-insensitive an input that is
    either "function" or "object":

    var reFeaturedMethod = new RegExp('^(function|object)$', 'i');

    Furthermore, AISB,

    return !!((reFeaturedMethod.test(t) && o[m]) || t == 'unknown');

    becomes more efficient when writing

    return !!(t == 'unknown' || (reFeaturedMethod.test(t) && o[m]));

    The double negation to cast to boolean is a matter of taste; I do not think
    it is necessary, because one possible result is a boolean already and the
    other has been proven by this that it can be used in a type-converting
    test.

    Either the identifier or the code of isHostObjectProperty() does not make
    sense.

    I am going to comment on the rest later.


    PointedEars
    --
    var bugRiddenCrashPronePieceOfJunk = (
    navigator.userAgent.indexOf('MSIE 5') != -1
    && navigator.userAgent.indexOf('Mac') != -1
    ) // Plone, register_function.js:16
     
    Thomas 'PointedEars' Lahn, Mar 23, 2010
    #2
    1. Advertising

  3. David Mark

    David Mark Guest

    Thomas 'PointedEars' Lahn wrote:
    > David Mark wrote:
    >
    >> I have posted a new primer related to host objects and feature
    >> detection/testing.
    >>
    >> http://www.cinsoft.net/host.html
    >>
    >> I think that about sums up the progress (and lack thereof) of the last
    >> few years.

    >
    > ISTM the RegExp is borken:
    >
    > var reFeaturedMethod = new RegExp('^function|object$', 'i');
    >
    > It matches case-insensitive either "function" at the begin of input or
    > "object" at the end, when it should match case-insensitive an input that is
    > either "function" or "object":


    You got it. That reflects either sloppiness or cluelessness on my part
    at the time I wrote that line (first one I wrote for My Library). :)
    it's fixed in the pasted example and the library. Thanks!

    And BTW, I forgot to mention your isMethodType as the inspiration for
    that function. I'll add that when I have a chance. I need to explain a
    little bit more about that one anyway.

    >
    > var reFeaturedMethod = new RegExp('^(function|object)$', 'i');
    >
    > Furthermore, AISB,
    >
    > return !!((reFeaturedMethod.test(t) && o[m]) || t == 'unknown');
    >
    > becomes more efficient when writing
    >
    > return !!(t == 'unknown' || (reFeaturedMethod.test(t) && o[m]));


    Could be. I'm not sure.

    >
    > The double negation to cast to boolean is a matter of taste; I do not think
    > it is necessary, because one possible result is a boolean already and the
    > other has been proven by this that it can be used in a type-converting
    > test.


    I just like for the function to return a boolean for all cases.

    >
    > Either the identifier or the code of isHostObjectProperty() does not make
    > sense.


    The identifier is not particularly descriptive. Read the description
    carefully. There is an assertion you must make as part of the contract
    with that (and isHostMethod). Remember that some objects (e.g.
    childNodes) can have typeof "function". You are asserting that you will
    do something other than call it, which is why the "unknown" types are
    excluded. I need to flesh out the explanation, which was copied
    straight from the skeletal library documentation.

    >
    > I am going to comment on the rest later.


    Comments welcome! :)
     
    David Mark, Mar 23, 2010
    #3
  4. David Mark

    David Mark Guest

    David Mark wrote:
    > Thomas 'PointedEars' Lahn wrote:
    >> David Mark wrote:
    >>
    >>> I have posted a new primer related to host objects and feature
    >>> detection/testing.
    >>>
    >>> http://www.cinsoft.net/host.html
    >>>
    >>> I think that about sums up the progress (and lack thereof) of the last
    >>> few years.

    >> ISTM the RegExp is borken:
    >>
    >> var reFeaturedMethod = new RegExp('^function|object$', 'i');
    >>
    >> It matches case-insensitive either "function" at the begin of input or
    >> "object" at the end, when it should match case-insensitive an input that is
    >> either "function" or "object":

    >
    > You got it. That reflects either sloppiness or cluelessness on my part
    > at the time I wrote that line (first one I wrote for My Library). :)
    > it's fixed in the pasted example and the library. Thanks!
    >
    > And BTW, I forgot to mention your isMethodType as the inspiration for
    > that function. I'll add that when I have a chance. I need to explain a
    > little bit more about that one anyway.


    Now mentioned, as well as the blog post that followed Peter's site.
     
    David Mark, Mar 23, 2010
    #4
  5. Thomas 'PointedEars' Lahn wrote:
    > David Mark wrote:
    >
    >> I have posted a new primer related to host objects and feature
    >> detection/testing.


    [...]

    >
    > ISTM the RegExp is borken:
    >
    > var reFeaturedMethod = new RegExp('^function|object$', 'i');
    >
    > It matches case-insensitive either "function" at the begin of input or
    > "object" at the end, when it should match case-insensitive an input that is
    > either "function" or "object":
    >
    > var reFeaturedMethod = new RegExp('^(function|object)$', 'i');
    >


    A Literal would be shorter and would stay cached:

    /^(?:func|obj)/;

    > Furthermore, AISB,
    >
    > return !!((reFeaturedMethod.test(t) && o[m]) || t == 'unknown');
    >
    > becomes more efficient when writing
    >
    > return !!(t == 'unknown' || (reFeaturedMethod.test(t) && o[m]));
    >
    > The double negation to cast to boolean is a matter of taste; I do not think
    > it is necessary, because one possible result is a boolean already and the
    > other has been proven by this that it can be used in a type-converting
    > test.
    >

    Double negation on a boolean is pointless. However, `o[m]` should not be
    a boolean; it should be a function or an object.

    Caveats:
    Object `o` could be callable and falsish, such as nonstandard callable
    "document.all".

    Object `o` could be the `item` method, for which typeof will result
    "string" in IE. This would result in isHostMethod returning false.
    --
    Garrett
    comp.lang.javascript FAQ: http://jibbering.com/faq/
     
    Garrett Smith, Mar 23, 2010
    #5
  6. David Mark wrote:
    > I have posted a new primer related to host objects and feature
    > detection/testing.
    >
    > http://www.cinsoft.net/host.html
    >


    | The isHostObjectProperty function tests if the specified host object
    | property references an object that is safe to evaluate.

    The term "evaluate" is non-standard terminology. What do you mean?

    [snip comments about John Resig]
    --
    Garrett
    comp.lang.javascript FAQ: http://jibbering.com/faq/
     
    Garrett Smith, Mar 23, 2010
    #6
  7. David Mark

    David Mark Guest

    Garrett Smith wrote:
    > Thomas 'PointedEars' Lahn wrote:
    >> David Mark wrote:
    >>
    >>> I have posted a new primer related to host objects and feature
    >>> detection/testing.

    >
    > [...]
    >
    >>
    >> ISTM the RegExp is borken:
    >>
    >> var reFeaturedMethod = new RegExp('^function|object$', 'i');
    >>
    >> It matches case-insensitive either "function" at the begin of input or
    >> "object" at the end, when it should match case-insensitive an input
    >> that is either "function" or "object":
    >>
    >> var reFeaturedMethod = new RegExp('^(function|object)$', 'i');
    >>

    >
    > A Literal would be shorter and would stay cached:
    >
    > /^(?:func|obj)/;


    I fail to see how that is the same thing, but the non-capturing bit is a
    good idea.

    As for caching, I don't see how it makes any difference as I create the
    RegExp object once.

    >
    >> Furthermore, AISB,
    >>
    >> return !!((reFeaturedMethod.test(t) && o[m]) || t == 'unknown');
    >>
    >> becomes more efficient when writing
    >>
    >> return !!(t == 'unknown' || (reFeaturedMethod.test(t) && o[m]));
    >>
    >> The double negation to cast to boolean is a matter of taste; I do not
    >> think it is necessary, because one possible result is a boolean
    >> already and the other has been proven by this that it can be used in a
    >> type-converting test.
    >>

    > Double negation on a boolean is pointless. However, `o[m]` should not be
    > a boolean; it should be a function or an object.


    Right.

    >
    > Caveats:
    > Object `o` could be callable and falsish, such as nonstandard callable
    > "document.all".
    >
    > Object `o` could be the `item` method, for which typeof will result
    > "string" in IE. This would result in isHostMethod returning false.


    Yes, I should add both of those stipulations to the docs and this example.
     
    David Mark, Mar 23, 2010
    #7
  8. David Mark

    David Mark Guest

    Garrett Smith wrote:
    > David Mark wrote:
    >> I have posted a new primer related to host objects and feature
    >> detection/testing.
    >>
    >> http://www.cinsoft.net/host.html
    >>

    >
    > | The isHostObjectProperty function tests if the specified host object
    > | property references an object that is safe to evaluate.
    >
    > The term "evaluate" is non-standard terminology. What do you mean?


    Anything along the lines of type conversion, assigning a reference to a
    variable, etc. What would you call it?
     
    David Mark, Mar 23, 2010
    #8
  9. David Mark

    David Mark Guest

    kangax wrote:
    > On 3/23/10 12:52 PM, David Mark wrote:
    >> I have posted a new primer related to host objects and feature
    >> detection/testing.
    >>
    >> http://www.cinsoft.net/host.html

    >
    > Is there a reason `isHostObjectProperty` is not called `isHostProperty`
    > (to be consistent with `isHostMethod`)?


    The "Object" goes with "Property", not the "Host" part.

    >
    > Also, `findProperietaryStyle` doesn't include "Ms" prefix. Why?
    > (<http://blogs.msdn.com/ie/archive/2008/09/08/microsoft-css-vendor-extensions.aspx>)


    Happenstance. It was written before IE8 came out and the sorts of
    things I've used it for have had only non-CSS equivalents (e.g. opacity,
    transform). I'll add it as they do have a handful of proprietary CSS3
    implementations that could be useful to detect (e.g. text-overflow). I
    thought I had since added MS for that one in particular, but it may have
    been on some other project (I hastily copied the posted implementation
    from a My Library add-on).

    >
    >
    > Finally, it might be worth mentioning that `isEventSupported` could (and
    > _does_, as any other inference) return false positives; from those I
    > know about — `window`'s "error" in Chrome (present but "defunct"), and
    > "contextmenu" in Opera 10.50 (even when corresponding option is off in
    > settings!).


    It is only meant to be used with elements (which I should stipulate of
    course). As for "contextmenu", I never considered that a false
    positive. The event is supported, but like many things in browsers, the
    user has the ability to get in the way. But from your wording, it
    sounds as if there is a bug in Opera 10.5 that should be noted (and
    reported).

    Thanks for the input!
     
    David Mark, Mar 23, 2010
    #9
  10. David Mark wrote:

    > Garrett Smith wrote:
    >> Thomas 'PointedEars' Lahn wrote:
    >>> var reFeaturedMethod = new RegExp('^(function|object)$', 'i');

    >>
    >> A Literal would be shorter and would stay cached:
    >>
    >> /^(?:func|obj)/;

    >
    > I fail to see how that is the same thing, but the non-capturing bit is a
    > good idea.


    Not if you want this to be backwards-compatible. The Matrix says:

    ES JavaScript JScript V8 JSCore Opera KJS
    /(?:…)/ : RegExp 3 1.5 5.5.6330 1.3 525.13 7.02 3.5.9

    > As for caching, I don't see how it makes any difference as I create the
    > RegExp object once.


    The question is moot anyway since ES5 implementations instantiate a new
    object each time they encounter the literal. (This is different in ES3.)

    >>> Furthermore, AISB,
    >>>
    >>> return !!((reFeaturedMethod.test(t) && o[m]) || t == 'unknown');
    >>>
    >>> becomes more efficient when writing
    >>>
    >>> return !!(t == 'unknown' || (reFeaturedMethod.test(t) && o[m]));
    >>>
    >>> The double negation to cast to boolean is a matter of taste; I do not
    >>> think it is necessary, because one possible result is a boolean
    >>> already and the other has been proven by this that it can be used in a
    >>> type-converting test.

    >>
    >> Double negation on a boolean is pointless.


    Yes.

    >> However, `o[m]` should not be a boolean; it should be a function or an
    >> object.


    I beg your pardon?

    > Right.


    return (t == 'unknown' || (reFeaturedMethod.test(t) && !!o[m]));

    But AISB the `!!' does not really save anything as in a boolean context the
    return value would be subject to type conversion anyway.

    >> Caveats:
    >> Object `o` could be callable and falsish, such as nonstandard callable
    >> "document.all".


    Is there a good reason for document.all(...) instead of document.all[...]?
    If not, that fact is largely irrelevant.

    >> Object `o` could be the `item` method, for which typeof will result
    >> "string" in IE. This would result in isHostMethod returning false.

    >
    > Yes, I should add both of those stipulations to the docs and this
    > example.


    That argument only makes sense if _o[m]_ refers to the item() method of
    NodeList or HTMLCollection implementations. Then again, is there a good
    reason to call o.item(i) instead of accessing o? If not, that fact is
    largely irrelevant.


    PointedEars
    --
    Danny Goodman's books are out of date and teach practices that are
    positively harmful for cross-browser scripting.
    -- Richard Cornford, cljs, <cife6q$253$1$> (2004)
     
    Thomas 'PointedEars' Lahn, Mar 23, 2010
    #10
  11. David Mark

    David Mark Guest

    Thomas 'PointedEars' Lahn wrote:
    > David Mark wrote:
    >
    >> Garrett Smith wrote:
    >>> Thomas 'PointedEars' Lahn wrote:
    >>>> var reFeaturedMethod = new RegExp('^(function|object)$', 'i');
    >>> A Literal would be shorter and would stay cached:
    >>>
    >>> /^(?:func|obj)/;

    >> I fail to see how that is the same thing, but the non-capturing bit is a
    >> good idea.

    >
    > Not if you want this to be backwards-compatible. The Matrix says:
    >
    > ES JavaScript JScript V8 JSCore Opera KJS
    > /(?:…)/ : RegExp 3 1.5 5.5.6330 1.3 525.13 7.02 3.5.9


    I wasn't sure about that, which is why I tend to stick with what I know
    for sure. Thanks for illuminating that. Verboten for My Library.

    >
    >> As for caching, I don't see how it makes any difference as I create the
    >> RegExp object once.

    >
    > The question is moot anyway since ES5 implementations instantiate a new
    > object each time they encounter the literal. (This is different in ES3.)


    Interesting. What possessed them to do that?

    >
    >>>> Furthermore, AISB,
    >>>>
    >>>> return !!((reFeaturedMethod.test(t) && o[m]) || t == 'unknown');
    >>>>
    >>>> becomes more efficient when writing
    >>>>
    >>>> return !!(t == 'unknown' || (reFeaturedMethod.test(t) && o[m]));
    >>>>
    >>>> The double negation to cast to boolean is a matter of taste; I do not
    >>>> think it is necessary, because one possible result is a boolean
    >>>> already and the other has been proven by this that it can be used in a
    >>>> type-converting test.
    >>> Double negation on a boolean is pointless.

    >
    > Yes.
    >
    >>> However, `o[m]` should not be a boolean; it should be a function or an
    >>> object.

    >
    > I beg your pardon?


    o[m] will not normally be a boolean, hence the double negation.

    >
    >> Right.

    >
    > return (t == 'unknown' || (reFeaturedMethod.test(t) && !!o[m]));
    >
    > But AISB the `!!' does not really save anything as in a boolean context the
    > return value would be subject to type conversion anyway.


    That's true. But I prefer to have the function return booleans only.

    >
    >>> Caveats:
    >>> Object `o` could be callable and falsish, such as nonstandard callable
    >>> "document.all".

    >
    > Is there a good reason for document.all(...) instead of document.all[...]?
    > If not, that fact is largely irrelevant.


    I missed that that second part was mentioned. I already mentioned about
    the sometimes callable objects in the explanation and documentation.
    Don't request an opinion from isHostMethod on those.

    >
    >>> Object `o` could be the `item` method, for which typeof will result
    >>> "string" in IE. This would result in isHostMethod returning false.

    >> Yes, I should add both of those stipulations to the docs and this
    >> example.

    >
    > That argument only makes sense if _o[m]_ refers to the item() method of
    > NodeList or HTMLCollection implementations. Then again, is there a good
    > reason to call o.item(i) instead of accessing o? If not, that fact is
    > largely irrelevant.
    >


    Right. It is odd that the one exception to an otherwise golden rule is
    something you would/should never need anyway. Still, it's an
    interesting caveat and I think I will mention it.
     
    David Mark, Mar 23, 2010
    #11
  12. David Mark wrote:
    > Garrett Smith wrote:
    >> Thomas 'PointedEars' Lahn wrote:
    >>> David Mark wrote:
    >>>
    >>>> I have posted a new primer related to host objects and feature
    >>>> detection/testing.

    >> [...]
    >>
    >>> ISTM the RegExp is borken:
    >>>
    >>> var reFeaturedMethod = new RegExp('^function|object$', 'i');
    >>>
    >>> It matches case-insensitive either "function" at the begin of input or
    >>> "object" at the end, when it should match case-insensitive an input
    >>> that is either "function" or "object":
    >>>
    >>> var reFeaturedMethod = new RegExp('^(function|object)$', 'i');
    >>>

    >> A Literal would be shorter and would stay cached:
    >>
    >> /^(?:func|obj)/;

    >
    > I fail to see how that is the same thing, but the non-capturing bit is a
    > good idea.
    >

    It is not the same thing.

    Either would do the job as well as:
    /^(?:function|object)$/;

    Being case-insensitive is pointless, though. I'd ditch the 'i' flag
    either way.

    > As for caching, I don't see how it makes any difference as I create the
    > RegExp object once.
    >


    The difference would be when the object is created. Either at runtime
    (as with constructor) or during lexical scan for regexp literal.
    --
    Garrett
    comp.lang.javascript FAQ: http://jibbering.com/faq/
     
    Garrett Smith, Mar 23, 2010
    #12
  13. David Mark wrote:
    > Garrett Smith wrote:
    >> David Mark wrote:
    >>> I have posted a new primer related to host objects and feature
    >>> detection/testing.
    >>>
    >>> http://www.cinsoft.net/host.html
    >>>

    >> | The isHostObjectProperty function tests if the specified host object
    >> | property references an object that is safe to evaluate.
    >>
    >> The term "evaluate" is non-standard terminology. What do you mean?

    >
    > Anything along the lines of type conversion, assigning a reference to a
    > variable, etc. What would you call it?


    I like to see the standard terminology to describe the problems.
    I mentioned a few of the problems with host objects here:

    http://jibbering.com/faq/notes/code-guidelines/#hostObjects

    Posted inline, for convenience:
    | Host Objects:
    |
    | * Operators:
    | o Do not use delete operator with host object (IE Errors)
    | o Do not add any expando properties (unselectable is safe)
    | o Host objects that error upon [[Get]] access are often ActiveX
    | objects. These include, but are not limited to:
    | + Disconnected nodes whose parentNode is not an element
    | (node.offsetParent)
    | + XMLHttpRequest methods (open, send, etc).
    | + filters: elem.filters.alpha, elem.style.filters.alpha, etc.
    | + document.styleSheets[99999] - Error from [[Get]] for a
    | nonexistent numeric property of a styleSheets collection.
    | + link.href for nntp: links in IE.
    | + NodeList in Safari 2 - do not attempt access a nonexistent
    | property (e.g. document.childNodes.slice).
    |
    | * Type conversion
    | [[ToString]]
    | Perform string conversion by starting concatenation with a string
    | value. See Newsgroup message explanation.
    <URL:
    http://groups.google.bg/group/comp.lang.javascript/msg/1528f612e31f09fe >
    --
    Garrett
    comp.lang.javascript FAQ: http://jibbering.com/faq/
     
    Garrett Smith, Mar 23, 2010
    #13
  14. kangax wrote:
    > On 3/23/10 6:00 PM, David Mark wrote:
    >> kangax wrote:
    >>> On 3/23/10 12:52 PM, David Mark wrote:
    >>>> I have posted a new primer related to host objects and feature
    >>>> detection/testing.


    [...]

    > Yeah, I should report it to them. The fact that Opera bug tracker is not
    > open is annoying (I have no idea what's going on with the bugs I filed
    > in the past).
    >

    "Signs point to yes"
    (source: magic 8 ball).
    --
    Garrett
    comp.lang.javascript FAQ: http://jibbering.com/faq/
     
    Garrett Smith, Mar 23, 2010
    #14
  15. David Mark wrote:
    > Thomas 'PointedEars' Lahn wrote:
    >> David Mark wrote:
    >>
    >>> Garrett Smith wrote:
    >>>> Thomas 'PointedEars' Lahn wrote:
    >>>>> var reFeaturedMethod = new RegExp('^(function|object)$', 'i

    [...]

    >> But AISB the `!!' does not really save anything as in a boolean context the
    >> return value would be subject to type conversion anyway.

    >
    > That's true. But I prefer to have the function return booleans only.
    >

    Having gthe function return boolean provides clear expectations to the
    caller. WIth an "is" method, the caller should be able to expect a
    boolean value.

    This expectation could be clearly defined by a unit test. I might write
    it like this:

    "testIsHostMethod - contains" : function(){
    var actualResult = isHostMethod(document.body.contains);
    Assert.isTrue(actualResult);
    }

    That isHostMethod returning something other than false would end up
    failing that test. By always returning boolean value, the expectation is
    simpler.

    >>>> Caveats:
    >>>> Object `o` could be callable and falsish, such as nonstandard callable
    >>>> "document.all".

    >> Is there a good reason for document.all(...) instead of document.all[...]?
    >> If not, that fact is largely irrelevant.

    >
    > I missed that that second part was mentioned. I already mentioned about
    > the sometimes callable objects in the explanation and documentation.
    > Don't request an opinion from isHostMethod on those.
    >


    I was not suggesting a workaround for the document.all anomaly.

    The use of document.all should be abstained from.

    >>
    >>>> Object `o` could be the `item` method, for which typeof will result
    >>>> "string" in IE. This would result in isHostMethod returning false.
    >>> Yes, I should add both of those stipulations to the docs and this
    >>> example.

    >> That argument only makes sense if _o[m]_ refers to the item() method of
    >> NodeList or HTMLCollection implementations. Then again, is there a good
    >> reason to call o.item(i) instead of accessing o? If not, that fact is
    >> largely irrelevant.
    >>

    >
    > Right. It is odd that the one exception to an otherwise golden rule is
    > something you would/should never need anyway. Still, it's an
    > interesting caveat and I think I will mention it.


    I can't think of a good reason for preferring item() over [].

    I recall testing Firefox up to 1.5 and [] was faster than item() there.
    Browsers nowadays are so fast that that difference (which may not exist
    any longer) would hardly matter much.
    --
    Garrett
    comp.lang.javascript FAQ: http://jibbering.com/faq/
     
    Garrett Smith, Mar 23, 2010
    #15
  16. David Mark

    David Mark Guest

    kangax wrote:
    > On 3/23/10 6:00 PM, David Mark wrote:
    >> kangax wrote:
    >>> On 3/23/10 12:52 PM, David Mark wrote:
    >>>> I have posted a new primer related to host objects and feature
    >>>> detection/testing.
    >>>>
    >>>> http://www.cinsoft.net/host.html
    >>>
    >>> Is there a reason `isHostObjectProperty` is not called `isHostProperty`
    >>> (to be consistent with `isHostMethod`)?

    >>
    >> The "Object" goes with "Property", not the "Host" part.

    >
    > I understand that :) But what does "Property" clarify there? What's
    > wrong with having `isHostMethod` and `isHostProperty` — where first one
    > is for testing anything that's intended to be called (i.e. method), and
    > latter — for anything that won't be called (i.e. property).


    Because it only tests for object properties (i.e. not booleans, strings,
    numbers, etc.)

    >
    > [...]
    >
    >>>
    >>> Finally, it might be worth mentioning that `isEventSupported` could (and
    >>> _does_, as any other inference) return false positives; from those I
    >>> know about — `window`'s "error" in Chrome (present but "defunct"), and
    >>> "contextmenu" in Opera 10.50 (even when corresponding option is off in
    >>> settings!).

    >>
    >> It is only meant to be used with elements (which I should stipulate of
    >> course). As for "contextmenu", I never considered that a false
    >> positive. The event is supported, but like many things in browsers, the
    >> user has the ability to get in the way. But from your wording, it
    >> sounds as if there is a bug in Opera 10.5 that should be noted (and
    >> reported).

    >
    > Yeah, I should report it to them. The fact that Opera bug tracker is not
    > open is annoying (I have no idea what's going on with the bugs I filed
    > in the past).
    >


    Yeah, I hope they get that fixed. ISTM, their preferences dialog
    sometimes gets out of whack with the reality of the browser window.
    Still, I like it and have taken to using it as my primary browser.
     
    David Mark, Mar 24, 2010
    #16
  17. David Mark

    David Mark Guest

    Garrett Smith wrote:
    > David Mark wrote:
    >> Garrett Smith wrote:
    >>> Thomas 'PointedEars' Lahn wrote:
    >>>> David Mark wrote:
    >>>>
    >>>>> I have posted a new primer related to host objects and feature
    >>>>> detection/testing.
    >>> [...]
    >>>
    >>>> ISTM the RegExp is borken:
    >>>>
    >>>> var reFeaturedMethod = new RegExp('^function|object$', 'i');
    >>>>
    >>>> It matches case-insensitive either "function" at the begin of input or
    >>>> "object" at the end, when it should match case-insensitive an input
    >>>> that is either "function" or "object":
    >>>>
    >>>> var reFeaturedMethod = new RegExp('^(function|object)$', 'i');
    >>>>
    >>> A Literal would be shorter and would stay cached:
    >>>
    >>> /^(?:func|obj)/;

    >>
    >> I fail to see how that is the same thing, but the non-capturing bit is a
    >> good idea.
    >>

    > It is not the same thing.
    >
    > Either would do the job as well as:
    > /^(?:function|object)$/;


    I don't want to let anything through that is "func" or "obj". That's a
    slippery slope (i.e. why not just test for "fu" and "ob").

    >
    > Being case-insensitive is pointless, though. I'd ditch the 'i' flag
    > either way.


    I suppose.

    >
    >> As for caching, I don't see how it makes any difference as I create the
    >> RegExp object once.
    >>

    >
    > The difference would be when the object is created. Either at runtime
    > (as with constructor) or during lexical scan for regexp literal.


    Right, but I didn't understand what was meant by "caching" as it is a
    one-shot deal in either case.
     
    David Mark, Mar 24, 2010
    #17
  18. David Mark

    David Mark Guest

    Garrett Smith wrote:
    > David Mark wrote:
    >> Garrett Smith wrote:
    >>> David Mark wrote:
    >>>> I have posted a new primer related to host objects and feature
    >>>> detection/testing.
    >>>>
    >>>> http://www.cinsoft.net/host.html
    >>>>
    >>> | The isHostObjectProperty function tests if the specified host object
    >>> | property references an object that is safe to evaluate.
    >>>
    >>> The term "evaluate" is non-standard terminology. What do you mean?

    >>
    >> Anything along the lines of type conversion, assigning a reference to a
    >> variable, etc. What would you call it?

    >
    > I like to see the standard terminology to describe the problems.


    Yes, and that would be what in this case? I mean a single word to
    replace evaluate. I realized when I wrote it it wasn't technically
    specified, but couldn't come up with a better word.

    > I mentioned a few of the problems with host objects here:
    >
    > http://jibbering.com/faq/notes/code-guidelines/#hostObjects


    Yes, and speaking of the FAQ:-

    http://www.jibbering.com/faq/#onlineResources

    ....needs section for browser scripting resources (e.g. mine, Kangax'
    blog, etc.) And:-

    http://www.jibbering.com/faq/faq_notes/contributors.html

    ....needs my name added. At the very least, the confirm issue I fixed:-

    http://www.jibbering.com/faq/#changeBrowserDialog

    >
    > Posted inline, for convenience:
    > | Host Objects:
    > |
    > | * Operators:
    > | o Do not use delete operator with host object (IE Errors)


    Sound, but I would ditch the parenthetical. Could happen to any browser.

    > | o Do not add any expando properties (unselectable is safe)


    What is this one's aside about?

    > | o Host objects that error upon [[Get]] access are often ActiveX
    > | objects. These include, but are not limited to:


    Host object _properties_ that throw errors on [[Get]] (a term that is
    too subterranean for my primers) often indicate that the containing
    object is an ActiveX implementation. All such method properties do it.

    > | + Disconnected nodes whose parentNode is not an element
    > | (node.offsetParent)


    In some cases, all properties of element nodes go AWOL ("unknown" typeof
    results). IIRC, that happens when they are orphaned by an innerHTML
    replacement.

    > | + XMLHttpRequest methods (open, send, etc).


    And its ActiveX equivalents.

    > | + filters: elem.filters.alpha, elem.style.filters.alpha, etc.


    The filters object is implemented with ActiveX, so its properties are
    suspect.

    > | + document.styleSheets[99999] - Error from [[Get]] for a
    > | nonexistent numeric property of a styleSheets collection.


    That one may not be due to ActiveX, but just an allowable exception for
    an out of bounds request.

    > | + link.href for nntp: links in IE.


    Yes, the Stockton href incident. That one was truly unexpected (and
    likely a bug) as how else are you to get the href value. (!)

    > | + NodeList in Safari 2 - do not attempt access a nonexistent
    > | property (e.g. document.childNodes.slice).


    That's an odd one. Likely also a bug.

    > |
    > | * Type conversion
    > | [[ToString]]
    > | Perform string conversion by starting concatenation with a string
    > | value. See Newsgroup message explanation.
    > <URL:
    > http://groups.google.bg/group/comp.lang.javascript/msg/1528f612e31f09fe >


    I don't see how the explanation relates to host objects, which don't
    have to follow the specs at all.
     
    David Mark, Mar 24, 2010
    #18
  19. David Mark

    David Mark Guest

    Garrett Smith wrote:
    > David Mark wrote:
    >> Thomas 'PointedEars' Lahn wrote:
    >>> David Mark wrote:
    >>>
    >>>> Garrett Smith wrote:
    >>>>> Thomas 'PointedEars' Lahn wrote:
    >>>>>> var reFeaturedMethod = new RegExp('^(function|object)$', 'i

    > [...]
    >
    >>> But AISB the `!!' does not really save anything as in a boolean
    >>> context the return value would be subject to type conversion anyway.

    >>
    >> That's true. But I prefer to have the function return booleans only.
    >>

    > Having gthe function return boolean provides clear expectations to the
    > caller. WIth an "is" method, the caller should be able to expect a
    > boolean value.
    >
    > This expectation could be clearly defined by a unit test. I might write
    > it like this:
    >
    > "testIsHostMethod - contains" : function(){
    > var actualResult = isHostMethod(document.body.contains);
    > Assert.isTrue(actualResult);
    > }


    isHostMethod(document.body, 'contains')

    But I don't see that as a good unit test for this method as it will fail
    if that host method is missing. I would prefer to simply test that the
    result is a boolean.

    >
    > That isHostMethod returning something other than false would end up
    > failing that test. By always returning boolean value, the expectation is
    > simpler.


    Perhaps I am reading your test wrong. Did you mean something like
    isBoolean (and returns something other than true/false?)

    >
    >>>>> Caveats:
    >>>>> Object `o` could be callable and falsish, such as nonstandard callable
    >>>>> "document.all".
    >>> Is there a good reason for document.all(...) instead of
    >>> document.all[...]?
    >>> If not, that fact is largely irrelevant.

    >>
    >> I missed that that second part was mentioned. I already mentioned about
    >> the sometimes callable objects in the explanation and documentation.
    >> Don't request an opinion from isHostMethod on those.
    >>

    >
    > I was not suggesting a workaround for the document.all anomaly.
    >
    > The use of document.all should be abstained from.


    Absolutely.

    >
    >>>
    >>>>> Object `o` could be the `item` method, for which typeof will result
    >>>>> "string" in IE. This would result in isHostMethod returning false.
    >>>> Yes, I should add both of those stipulations to the docs and this
    >>>> example.
    >>> That argument only makes sense if _o[m]_ refers to the item() method
    >>> of NodeList or HTMLCollection implementations. Then again, is there
    >>> a good reason to call o.item(i) instead of accessing o? If not,
    >>> that fact is largely irrelevant.
    >>>

    >>
    >> Right. It is odd that the one exception to an otherwise golden rule is
    >> something you would/should never need anyway. Still, it's an
    >> interesting caveat and I think I will mention it.

    >
    > I can't think of a good reason for preferring item() over [].


    Me neither. I've never used it.

    >
    > I recall testing Firefox up to 1.5 and [] was faster than item() there.
    > Browsers nowadays are so fast that that difference (which may not exist
    > any longer) would hardly matter much.


    Less operations would seem to indicate it would be faster, but you can
    never be 100% sure with such a small variation (and, as noted, it's not
    likely to be a significant difference anyway).
     
    David Mark, Mar 24, 2010
    #19
  20. David Mark wrote:
    > Garrett Smith wrote:
    >> David Mark wrote:
    >>> Thomas 'PointedEars' Lahn wrote:
    >>>> David Mark wrote:
    >>>>
    >>>>> Garrett Smith wrote:
    >>>>>> Thomas 'PointedEars' Lahn wrote:
    >>>>>>> var reFeaturedMethod = new RegExp('^(function|object)$', 'i

    >> [...]
    >>
    >>>> But AISB the `!!' does not really save anything as in a boolean
    >>>> context the return value would be subject to type conversion anyway.
    >>> That's true. But I prefer to have the function return booleans only.
    >>>

    >> Having gthe function return boolean provides clear expectations to the
    >> caller. WIth an "is" method, the caller should be able to expect a
    >> boolean value.
    >>
    >> This expectation could be clearly defined by a unit test. I might write
    >> it like this:
    >>
    >> "testIsHostMethod - contains" : function(){
    >> var actualResult = isHostMethod(document.body.contains);
    >> Assert.isTrue(actualResult);
    >> }

    >
    > isHostMethod(document.body, 'contains')
    >


    Right.

    > But I don't see that as a good unit test for this method as it will fail
    > if that host method is missing. I would prefer to simply test that the
    > result is a boolean.
    >
    >> That isHostMethod returning something other than false would end up
    >> failing that test. By always returning boolean value, the expectation is
    >> simpler.

    >
    > Perhaps I am reading your test wrong. Did you mean something like
    > isBoolean (and returns something other than true/false?)
    >


    No, that makes sense, but it is not what I meant.

    I was going for testing under known conditions, that the method does
    what is expected it will do.

    A "contains" method will be absent in some implementations, so no good
    as test.

    A valid test might be to set up a case where the result is known or
    assumed to be true or false. For example, if the test case assumes that
    the environment has a `document.getElementById` that is potentially
    callable and that `document.title` would never be callable:

    testIsHostMethodWithDomCoreMethod : function() {
    Assert.isTrue(isHostMethod(document, "getElementById"));
    }

    testIsHostMethodWithNonCallableObject : function() {
    Assert.isFalse(isHostMethod(document, "title"));
    }

    The expected outcome could also be dynamic. For example:

    "testIsHostMethod - element.contains()" : function() {
    // First determine if calling something either works or doesn't.
    var expectedCallability = (function(){
    try {
    document.body.contains(document.body);
    return true;
    } catch(ex) {
    return false;
    }
    })();

    Assert.areSame(expectedCallability ,
    isHostMethod(document.body, "contains");
    }

    The only problem with this is that testing a property such as
    `document.forms` or `document.images` will be true, but not always callable.

    [...]
    --
    Garrett
    comp.lang.javascript FAQ: http://jibbering.com/faq/
     
    Garrett Smith, Mar 24, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Richard

    SSL / authentication primer

    Richard, Jul 25, 2003, in forum: Java
    Replies:
    2
    Views:
    488
    Richard
    Jul 25, 2003
  2. Orpheus66
    Replies:
    0
    Views:
    4,503
    Orpheus66
    Jul 30, 2003
  3. Chris
    Replies:
    0
    Views:
    374
    Chris
    Apr 18, 2005
  4. Jerry Qu
    Replies:
    1
    Views:
    523
    lee atkinson
    Feb 20, 2009
  5. Replies:
    2
    Views:
    502
    Thomas 'PointedEars' Lahn
    Mar 11, 2008
Loading...

Share This Page