Note 1. ECMAScript. Bound functions.

Discussion in 'Javascript' started by Dmitry A. Soshnikov, Jun 13, 2010.

  1. Dmitry A. Soshnikov, Jun 13, 2010
    #1
    1. Advertising

  2. Dmitry A. Soshnikov wrote:

    > "Note 1. ECMAScript. Bound functions." -- <URL:http://dmitrysoshnikov.com/notes/note-1-ecmascript-bound-functions/>


    The article is good and useful.

    | Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
    | 15.3.4.5
    | 4. Let F be a new native ECMAScript object .

    That step is described by ECMA-262-5 without any conditions. And the
    following behavior is conformance:

    function F(){}
    var thisValue = {};
    print(F.bind(thisValue) !== F.bind(thisValue)); //true

    I do not see any purposes for that design. The design of `bind' permit
    memory optimizations but unfortunately ECMA-262-5 does not describe
    that.
     
    Asen Bozhilov, Jun 13, 2010
    #2
    1. Advertising

  3. On 13.06.2010 23:50, Asen Bozhilov wrote:
    > Dmitry A. Soshnikov wrote:
    >
    >> "Note 1. ECMAScript. Bound functions." --<URL:http://dmitrysoshnikov.com/notes/note-1-ecmascript-bound-functions/>

    >
    > The article is good and useful.
    >


    Yes, there two main goals which distinguish built-in implementation from
    the JavaScript's `bind` implementations:

    (1) with `new` operator `this` value refers to the newly created object,
    but not to bound one;

    (2) it's not possible to implement the spec's behavior in JavaScript of
    the `new` bound functions (such as e.g. in "Prototype.js"): there if you
    return `this` manually, you'll return bound `this`; if you return
    "nothing" (implicit `this` value logically mention) -- then the result
    is indeterminate and dependent on the return value of a bound function.

    Alternatively, I would propose to separate these two tasks: static bound
    `this` value is for "bind", and currying is for "curry" method (how it's
    called in other languages).

    > | Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
    > | 15.3.4.5
    > | 4. Let F be a new native ECMAScript object .
    >
    > That step is described by ECMA-262-5 without any conditions. And the
    > following behavior is conformance:
    >
    > function F(){}
    > var thisValue = {};
    > print(F.bind(thisValue) !== F.bind(thisValue)); //true
    >
    > I do not see any purposes for that design. The design of `bind' permit
    > memory optimizations but unfortunately ECMA-262-5 does not describe
    > that.
    >


    Yep, they could mention this optimization. If the function is the same
    (with the same lexical environment chain), then, if there are no
    pre-bound partial args, the bound functions should not be different.


    P.S.: for testing I used again BESEN implementation which is (after
    small bug fixes made today) are completely conformant in the question of
    "bind".

    Dmitry.
     
    Dmitry A. Soshnikov, Jun 14, 2010
    #3
  4. On Jun 14, 11:46 am, Dmitry A. Soshnikov wrote:
    > On 13.06.2010 23:50, Asen Bozhilov wrote:

    <snip>
    >> | Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
    >> | 15.3.4.5
    >> | 4. Let F be a new native ECMAScript object .

    >
    >> That step is described by ECMA-262-5 without any conditions.
    >> And the following behavior is conformance:

    >
    >> function F(){}
    >> var thisValue = {};
    >> print(F.bind(thisValue) !== F.bind(thisValue)); //true

    >
    >> I do not see any purposes for that design. The design of `bind'
    >> permit memory optimizations but unfortunately ECMA-262-5 does
    >> not describe that.

    >
    > Yep, they could mention this optimization. If the function is
    > the same (with the same lexical environment chain), then, if
    > there are no pre-bound partial args, the bound functions should
    > not be different.

    <snip>

    Remember that javascript's functions (including functions returned
    from calls to - bind -) are objects and so may, at any future time,
    have properties added and values assigned to those properties.

    var a = F.bind(thisValue);
    var b = F.bind(thisValue);

    a.something = 'test';

    Do you now expect - b - to have a property called 'something' and for
    that property to have the value 'test'? And worse, would you want the
    existence of - b.something - to depend on an optional optimisation
    where it may be there in some environments and not there in others? As
    things stand, ES5 guarantees that each function returned from a call
    to - bind - has unique identity, and so that an implementation behave
    as if it has unique identity. I think that this is a good thing.

    Richard.
     
    Richard Cornford, Jun 14, 2010
    #4
  5. Richard Cornford wrote:

    > Remember that javascript's functions (including functions returned
    > from calls to - bind -) are objects and so may, at any future time,
    > have properties added and values assigned to those properties.
    > var a = F.bind(thisValue);
    > var b = F.bind(thisValue);
    >
    > a.something = 'test';


    It can depend on setter/getter and it is not necessary the assigned
    value to be accessed by:

    b.something;

    > Do you now expect - b - to have a property called 'something' and for
    > that property to have the value 'test'? And worse, would you want the
    > existence of - b.something - to depend on an optional optimisation
    > where it may be there in some environments and not there in others? As
    > things stand, ES5 guarantees that each function returned from a call
    > to - bind - has unique identity, and so that an implementation behave
    > as if it has unique identity. I think that this is a good thing.


    Certainly true, but in the near future we will see the approaches
    like:

    for (var i = 0, len = coll.length; i < len; i++) {
    coll.onclick = function () {
    //....
    }.bind(thisValue);
    }

    And by ECMA-262 should be created `len' * 2 objects. Would you want
    implementations to follow that or they will make optimizations behind
    the scene and behind the ECMA-262 standard?
     
    Asen Bozhilov, Jun 14, 2010
    #5
  6. On 14.06.2010 15:38, Richard Cornford wrote:
    > On Jun 14, 11:46 am, Dmitry A. Soshnikov wrote:
    >> On 13.06.2010 23:50, Asen Bozhilov wrote:

    > <snip>
    >>> | Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
    >>> | 15.3.4.5
    >>> | 4. Let F be a new native ECMAScript object .

    >>
    >>> That step is described by ECMA-262-5 without any conditions.
    >>> And the following behavior is conformance:

    >>
    >>> function F(){}
    >>> var thisValue = {};
    >>> print(F.bind(thisValue) !== F.bind(thisValue)); //true

    >>
    >>> I do not see any purposes for that design. The design of `bind'
    >>> permit memory optimizations but unfortunately ECMA-262-5 does
    >>> not describe that.

    >>
    >> Yep, they could mention this optimization. If the function is
    >> the same (with the same lexical environment chain), then, if
    >> there are no pre-bound partial args, the bound functions should
    >> not be different.

    > <snip>
    >
    > Remember that javascript's functions (including functions returned
    > from calls to - bind -) are objects and so may, at any future time,
    > have properties added and values assigned to those properties.
    >
    > var a = F.bind(thisValue);
    > var b = F.bind(thisValue);
    >
    > a.something = 'test';
    >


    Yeah, really, somehow I completely forgot about it when was replying to
    Asen's question -- although, myself, mentioned in the article (with
    example creating `prototype' property) that function objects created via
    `bind' method are extensible.

    > Do you now expect - b - to have a property called 'something' and for
    > that property to have the value 'test'? And worse, would you want the
    > existence of - b.something - to depend on an optional optimisation
    > where it may be there in some environments and not there in others? As
    > things stand, ES5 guarantees that each function returned from a call
    > to - bind - has unique identity, and so that an implementation behave
    > as if it has unique identity. I think that this is a good thing.
    >


    Yes, of course. Such optimization leads to ambiguities. So the ES5 is
    logical and correct in this question.

    Dmitry.
     
    Dmitry A. Soshnikov, Jun 14, 2010
    #6
  7. On 14.06.2010 17:46, Asen Bozhilov wrote:
    > Richard Cornford wrote:
    >
    >> Remember that javascript's functions (including functions returned
    >> from calls to - bind -) are objects and so may, at any future time,
    >> have properties added and values assigned to those properties.
    >> var a = F.bind(thisValue);
    >> var b = F.bind(thisValue);
    >>
    >> a.something = 'test';

    >
    > It can depend on setter/getter and it is not necessary the assigned
    > value to be accessed by:
    >
    > b.something;
    >


    If it will be the same object (with the same identity), how will you
    distinguish that getting from "some" object should return this property
    and from "other" not? I put "some" and "other" in quotes, because there
    is only one the same object. It could be some virtual table of
    properties, related with index, but, that to complex implementation and
    not worth all that.


    >> Do you now expect - b - to have a property called 'something' and for
    >> that property to have the value 'test'? And worse, would you want the
    >> existence of - b.something - to depend on an optional optimisation
    >> where it may be there in some environments and not there in others? As
    >> things stand, ES5 guarantees that each function returned from a call
    >> to - bind - has unique identity, and so that an implementation behave
    >> as if it has unique identity. I think that this is a good thing.

    >
    > Certainly true, but in the near future we will see the approaches
    > like:
    >
    > for (var i = 0, len = coll.length; i< len; i++) {
    > coll.onclick = function () {
    > //....
    > }.bind(thisValue);
    > }
    >
    > And by ECMA-262 should be created `len' * 2 objects. Would you want
    > implementations to follow that or they will make optimizations behind
    > the scene and behind the ECMA-262 standard?
    >


    By the way, I see that "joined objects" are gone from the ES5 too.

    Dmitry.
     
    Dmitry A. Soshnikov, Jun 14, 2010
    #7
  8. On Jun 14, 2:46 pm, Asen Bozhilov wrote:
    > Richard Cornford wrote:
    >> Remember that javascript's functions (including functions
    >> returned from calls to - bind -) are objects and so may,
    >> at any future time, have properties added and values
    >> assigned to those properties.
    >> var a = F.bind(thisValue);
    >> var b = F.bind(thisValue);

    >
    >> a.something = 'test';

    >
    > It can depend on setter/getter and it is not necessary the
    > assigned value to be accessed by:
    >
    > b.something;


    If the whole behaves as if - a - and - b - are unique objects then how
    that is a achieved doesn't matter much.

    >> Do you now expect - b - to have a property called 'something'
    >> and for that property to have the value 'test'? And worse, would
    >> you want the existence of - b.something - to depend on an optional
    >> optimisation where it may be there in some environments and not
    >> there in others? As things stand, ES5 guarantees that each
    >> function returned from a call to - bind - has unique identity,
    >> and so that an implementation behave as if it has unique identity.
    >> I think that this is a good thing.

    >
    > Certainly true, but in the near future we will see the approaches
    > like:
    >
    > for (var i = 0, len = coll.length; i < len; i++) {
    > coll.onclick = function () {
    > //....
    > }.bind(thisValue);
    >
    > }
    >
    > And by ECMA-262 should be created `len' * 2 objects.


    There is no need to wait for the future, I have already seen code
    exactly like that. Whether it should be seen is another matter given
    that, as it stands, this:-

    var f = (function () {
    //....
    }).bind(thisValue);

    for (var i = 0, len = coll.length; i < len; i++) {
    coll.onclick = f;
    }

    - should do the same with the creation of only two function objects.

    > Would you want implementations to follow that or they will make
    > optimizations behind the scene and behind the ECMA-262 standard?


    Optimisations behind the scenes are never unwelcome, so long as the
    specified behaviour is achieved. Here the functions returned from
    calls to - bind - must behave as if they each have unique identify.

    Richard.
     
    Richard Cornford, Jun 14, 2010
    #8
  9. On Jun 14, 3:03 pm, Dmitry A. Soshnikov wrote:
    > On 14.06.2010 17:46, Asen Bozhilov wrote:

    <snip>
    >> ... . Would you want implementations to follow that or they will
    >> make optimizations behind the scene and behind the ECMA-262
    >> standard?

    >
    > By the way, I see that "joined objects" are gone from the ES5 too.


    Some years ago some of the participants in this group put quite a lot
    of effort into trying to find evidence for "joined objects" in
    javascript implementations, with zero success. So probably the only
    thing that is lost by their being removed from ES5 is the possibility.

    Richard.
     
    Richard Cornford, Jun 14, 2010
    #9
  10. On 6/14/2010 8:19 AM, Richard Cornford wrote:
    > On Jun 14, 2:46 pm, Asen Bozhilov wrote:
    >> Richard Cornford wrote:
    >>> Remember that javascript's functions (including functions


    [...]

    >> Certainly true, but in the near future we will see the approaches
    >> like:
    >>
    >> for (var i = 0, len = coll.length; i< len; i++) {
    >> coll.onclick = function () {
    >> //....
    >> }.bind(thisValue);
    >>
    >> }
    >>
    >> And by ECMA-262 should be created `len' * 2 objects.

    >
    > There is no need to wait for the future, I have already seen code
    > exactly like that.


    I see it too.

    I remember seeing that approach being used in Google Gears code, with
    code comments labeled "aa" (apparently the code reviewer).

    The approach given is inefficient and clumsy. Beginners want to do this
    to fix variable this arg but it's not necessary.

    A better solution for what the above code appears to be doing would be
    to register an event handler -- just one -- on a common ancestor and use
    delegation.

    // Typical approach using delegation.
    container.onclick = function(ev) {
    var target = getTarget(ev);
    if(isPanelActuator(target)) {
    panelActuatorClickHandler(target, ev);
    }
    }

    The initialization is reduced to one assignment and one event handler
    function object creation. There is no need for a bind function. Although
    the approach uses a layer indirection with bubbling, the resulting code
    is actually shorter and simpler.

    Garrett
     
    Garrett Smith, Jun 14, 2010
    #10
  11. Garrett Smith wrote:
    > Richard Cornford wrote:
    > > Asen Bozhilov wrote:


    > >> for (var i = 0, len = coll.length; i<  len; i++) {
    > >>      coll.onclick = function () {
    > >>          //....
    > >>      }.bind(thisValue);

    >
    > >> }

    >
    > >> And by ECMA-262 should be created `len' * 2 objects.

    >
    > > There is no need to wait for the future, I have already seen code
    > > exactly like that.

    >
    > I see it too.
    >
    > The approach given is inefficient and clumsy. Beginners want to do this
    > to fix variable this arg but it's not necessary.
    >
    > A better solution for what the above code appears to be doing would be
    > to register an event handler -- just one -- on a common ancestor and use
    > delegation.
    >
    > // Typical approach using delegation.
    > container.onclick = function(ev) {
    >    var target = getTarget(ev);
    >    if(isPanelActuator(target)) {
    >      panelActuatorClickHandler(target, ev);
    >    }
    >
    > }


    Yes, that approach is better than registration handler for each
    element. For example I use similar code in Firefox extension which
    should handle user clicks on pages in opened tabs. So my code looks:

    var content = document.getElementById('content');
    content.addEventListener('click', handleClick, true);

    May be FAQ should noticed about that approach. Here are many threads
    in which that approach is posted, especially Thomas Lahn has posted
    many times.
     
    Asen Bozhilov, Jun 14, 2010
    #11
  12. On 14.06.2010 19:24, Richard Cornford wrote:
    > On Jun 14, 3:03 pm, Dmitry A. Soshnikov wrote:
    >> On 14.06.2010 17:46, Asen Bozhilov wrote:

    > <snip>
    >>> ... . Would you want implementations to follow that or they will
    >>> make optimizations behind the scene and behind the ECMA-262
    >>> standard?

    >>
    >> By the way, I see that "joined objects" are gone from the ES5 too.

    >
    > Some years ago some of the participants in this group put quite a lot
    > of effort into trying to find evidence for "joined objects" in
    > javascript implementations, with zero success. So probably the only
    > thing that is lost by their being removed from ES5 is the possibility.
    >


    Yep, it's quit strange thing, even if the [[Scope]] property is
    indistinguishable. Because of again -- joined objects should copy
    non-internal properties bidirectionally (similar to the case with
    mentioned Asen's proposal for "bind"):

    function A() {
    function B(x) {return x*x;}
    return B;
    }

    var b1 = A();
    var b2 = A();

    b1.foo = "bar";

    alert(b2.foo); // should be "bar" if objects are joined
    alert(b1 === b2); should be true

    I remember one discussion (but can't find it now, if you'll find, let me
    know) where joined objects are recognized as not so needed, so I guess
    they were removed from ES5 because of that.

    Dmitry.
     
    Dmitry A. Soshnikov, Jun 14, 2010
    #12
  13. On 14.06.2010 14:46, Dmitry A. Soshnikov wrote:

    <snip>

    >
    > (2) it's not possible to implement the spec's behavior in JavaScript of
    > the `new` bound functions


    Yes, it's possible: <URL: http://bit.ly/aboVXU> -- implemented by
    Bozhilov; I've updated the article.

    Dmitry.
     
    Dmitry A. Soshnikov, Jun 14, 2010
    #13
  14. On 6/14/2010 1:14 PM, Asen Bozhilov wrote:
    > Garrett Smith wrote:
    >> Richard Cornford wrote:
    >>> Asen Bozhilov wrote:

    >


    [...]

    > May be FAQ should noticed about that approach. Here are many threads
    > in which that approach is posted, especially Thomas Lahn has posted
    > many times.
    >

    That would be a really good idea. The subject comes up enough.

    An event delegation entry and an execution context entry would both be
    useful. The execution context entry might be worded as: What does the
    "this" keyword refer to in a function call?

    It is mentioned in the code guidelines doc in three places:

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

    | Do not traverse over elements to modify the style or add an event
    | callback to each element.

    and below that:

    | For events, use event delegation. That is, replace a loop that adds a
    | callback to each element in a collection with a callback on a common
    | ancestor.

    Garrett
     
    Garrett Smith, Jun 15, 2010
    #14
  15. Dmitry A. Soshnikov

    pedz Guest

    On Jun 14, 6:49 pm, Garrett Smith <> wrote:
    > It is mentioned in the code guidelines doc in three places:
    >
    > http://jibbering.com/faq/notes/code-guidelines/#design


    I was curious so I poked the link. The first bullet was not clear to
    me.

    Why is:

    > goog.isDef = function(val) {
    > return val !== undefined;
    > };


    a useless function?

    Also, reading a little further, the term "nonstandard" might be
    avoided. The function statement, it says, is "nonstandard" but it is
    in the 3 and 5 standards. The key point is that it is "allowed" and
    not "required" and it is that choice of the implementers that make it
    a bad choice to use. Calling something in the standards a nonstandard
    isn't helping the unenlightened.
     
    pedz, Jun 15, 2010
    #15
  16. Dmitry A. Soshnikov

    David Mark Guest

    On Jun 14, 10:08 pm, pedz <> wrote:
    > On Jun 14, 6:49 pm, Garrett Smith <> wrote:
    >
    > > It is mentioned in the code guidelines doc in three places:

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

    >
    > I was curious so I poked the link.  The first bullet was not clear to
    > me.
    >
    > Why is:
    >
    > > goog.isDef = function(val) {
    > >   return val !== undefined;
    > > };

    >
    > a useless function?


    Because it is nothing but a strict comparison with a performance
    penalty (a function call).

    >
    > Also, reading a little further, the term "nonstandard" might be
    > avoided.  The function statement, it says, is "nonstandard" but it is
    > in the 3 and 5 standards.
    > The key point is that it is "allowed" and
    > not "required" and it is that choice of the implementers that make it
    > a bad choice to use.


    It is best avoided if cross-browser compatibility is desired.

    > Calling something in the standards a nonstandard
    > isn't helping the unenlightened.


    Mentions do not make standards. Requirements do. I agree there is a
    lot of confusion out there as most developers do not read the specs
    carefully (if at all). For example, it seems like every time I tell a
    beginner that there is no standard for the window object, they cite a
    mention of it in the ES3 specifications, despite the fact that the
    document does not define host objects as anything but implementation-
    dependent. It is, after all, a *language* specification (and the
    unrelated DOM recommendations don't shed much light on that object
    either).
     
    David Mark, Jun 15, 2010
    #16
  17. Dmitry A. Soshnikov

    RobG Guest

    On Jun 14, 5:50 am, Asen Bozhilov <> wrote:
    > Dmitry A. Soshnikov wrote:
    > > "Note 1. ECMAScript. Bound functions." -- <URL:http://dmitrysoshnikov.com/notes/note-1-ecmascript-bound-functions/>

    >
    > The article is good and useful.
    >
    > | Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
    > | 15.3.4.5
    > | 4. Let F be a new native ECMAScript object .


    Seems to me "bind" would be better named "setThis" as that is more
    descriptive of what it does. It would also avoid a naming conflict
    with implementations of bind in existing libraries.

    But I guess I'm too late with that suggestion in regard to ECMAScript
    ed 5.


    --
    Rob
     
    RobG, Jun 15, 2010
    #17
  18. "Dmitry A. Soshnikov" <> writes:

    > On 14.06.2010 14:46, Dmitry A. Soshnikov wrote:


    >> (2) it's not possible to implement the spec's behavior in JavaScript of
    >> the `new` bound functions

    >
    > Yes, it's possible: <URL: http://bit.ly/aboVXU> -- implemented by
    > Bozhilov; I've updated the article.


    It's distinguishable from the correct behavior. If you use the bound
    function as a method of an instance created from it, then it will
    believe it to be a construct call, even if it isn't.


    The problem is that you can't identify a construct call
    programmatically. Testing whether "this" is an instance of the
    function being created can be faked.

    /L
    --
    Lasse Reichstein Holst Nielsen
    'Javascript frameworks is a disruptive technology'
     
    Lasse Reichstein Nielsen, Jun 15, 2010
    #18
  19. On 6/14/2010 7:08 PM, pedz wrote:
    > On Jun 14, 6:49 pm, Garrett Smith<> wrote:
    >> It is mentioned in the code guidelines doc in three places:
    >>
    >> http://jibbering.com/faq/notes/code-guidelines/#design

    >
    > I was curious so I poked the link. The first bullet was not clear to
    > me.
    >
    > Why is:
    >
    >> goog.isDef = function(val) {
    >> return val !== undefined;
    >> };

    >
    > a useless function?
    >


    Yes. Not only is it is useless, it can lead to potential misuse.

    Compared to `val !== undefined`, `goog.isDef(val)` is less clear and
    less efficient.

    It could /potentially/ be useful would be in an iteration style pattern
    where a callback was needed however the way `goog.isDef` is organized
    indicates that it is not intended to be used in that manner, but instead
    as a general method to determine if a value is not undefined.

    To see how Google uses goog.isDef, I did a search for goog.isDef and
    came up with the following:
    http://code.google.com/p/doctype/wiki/ArticleCoordinates

    | Updated Nov 15, 2008 by pilgrim
    | Labels: is-article, about-dom
    | ArticleCoordinates
    | HOWTO deal with page coordinates (goog.math.Coordinates)
    | [...]

    | /**
    | * Class for representing coordinates and positions.
    | * @param {Number} opt_x Left
    | * @param {Number} opt_y Top
    | * @constructor
    | */
    | goog.math.Coordinate = function(opt_x, opt_y) {
    | /**
    | * X-value
    | * @type Number
    | */
    | this.x = goog.isDef(opt_x) ? Number(opt_x) : undefined;
    |
    | /**
    | * Y-value
    | * @type Number
    | */
    | this.y = goog.isDef(opt_y) ? Number(opt_y) : undefined;
    |
    | };

    goog.math.Coordinate first calls `goog.isDef(opt_x)`. As we've seen,
    `goog.isDef` checks to see if the value of `opt_x` is not undefined. If
    that is the case, then the value of opt_x is converted to a number,
    otherwise `this.x` is given value undefined.

    It is strange design to be giving `x` a value that could be any of: 1) a
    finite number, 2) NaN, or 3) undefined. If avoiding NaN was wanted, (as
    would happen for Number(undefined)), then the code fails on that
    account. Instead, it could have succeeded by using instead the built-in
    `isFinite` function. Example:

    this.x = isFinite(opt_x) ? Number(opt_x) : undefined;

    - and that could be changed to use the more efficient unary +, which
    uses the same type conversion algorithm ToNumber.

    Eliminating NaN values from being assigned to the object's `x` and `y`
    properties would change Coordinate.equals to return true where two
    Coorinates had both NaN values, which might make sense in what appears
    as an overengineered alternative to {x:0, y:1}.

    Google's goog.math.Coordinate provides a stellar example of why
    goog.isDef is useless. It achieves this by showing an example of how the
    abstraction reduces code clarity and makes the intent less clear.
    Instead, the function isFinite probably should have been used
    `isFinite`. (and ideally it would seem best to just use {x: 0, y: 0} on
    an as-needed basis).

    Although the function is useless, it is also potentially misleading.
    This is because the identifier is "isDef" could be interpreted as "is
    defined". The closest thing to describign "defined" in ECMAScript is
    [[HasProperty]], however this function does not make a determination
    about an object having a property; only that val !== undefined. The
    function is potentially misleading to a beginner who might use the
    function in lieu of the `in` operator to check property existence.

    I actually had a conversation about a year ago with a prominent
    javascript expert and contributor to YUI regarding a bug in YUI. The
    code in question was ObjectAssert.hasProperty.

    The problem came down to making the same false inference about "if
    obj.prop is undefined, then obj does not have a property prop".

    The problem function was calling YAHOO.lang.isUndefined, which does the
    same thing that the goog.isDef function does but in the positive sense
    (or negative sense, depending how you look at it). That is, it returns
    `val === undefined`. Like goog.isDef, YAHOO.lang.isUndefined does not
    check an object for the existence of property (that would require both
    the object and a property to be passed in).

    I noticed the problem when testing a "clone" type of function with an
    object that had a property with the value undefined. Although it may
    seem odd to give a property with value `undefined`, it can happen (as
    the goog.Math.Coordinate does). I wanted to make sure that the property
    had been cloned properly and the clone function was required to be able
    to handle that case.

    Realizing the problem in the YUI function, I filed a bug:

    | ObjectAssert.hasProperty -- provides inaccurate results. Instead of
    | checking for the presence of a property, Assert.hasProperty checks the
    | value.

    The author and his manager both wanted me prove what I'm saying with a
    testcase, should I actually want the bug fixed.

    Much easier, I found, was to just fix the bug myself.

    Using a similar strategy to YAHOO.lang.isUndefined, goog.isDef checks to
    see if the value is not undefined. If the code must determine if an
    object has a property, then goog.isDef(myObj.prop) will not provide that
    information. The reason it won't tell you if the object has the property
    is that the object could have a property, and the value could be undefined.

    That type of abstraction is not useful. It is a useless abstraction that
    requires explanation.

    What is worse is that it can actually be deceptive to those who don't
    know the difference between an object having a property with an
    undefined value and an object not having a property.

    In contrast val !== undefined is instantly recognizable to anyone who
    understands ECMAScript.

    > Also, reading a little further, the term "nonstandard" might be
    > avoided. The function statement, it says, is "nonstandard" but it is
    > in the 3 and 5 standards. The key point is that it is "allowed" and
    > not "required" and it is that choice of the implementers that make it
    > a bad choice to use. Calling something in the standards a nonstandard
    > isn't helping the unenlightened.


    No, a Function statement is not defined by either 3 or 5 editions.
    Function statement is a nonstandard syntax extension.

    Please take a look at the FAQ and see if that doesn't clear things up
    for you.
    http://jibbering.com/faq/#functionStatement

    Asen noted that function declaration appearing where only statements are
    allowed will result in a SyntaxError in BESEN and DMDScript. I plan to
    add that to the FAQ. Currently, we have:

    | Implementations that have the function statement extension process
    | Fze as a Statement, in order, while other known implementations
    | evaluate Fze upon entering the execution context that it appears in.
    | For consistent behavior across implementations, avoid function
    | statement; use either FunctionExpression or FunctionDeclaration
    | instead.

    I'd like to change the FAQ to mention that.

    Proposed:
    | Implementations that have the function statement extension process
    | Fze as a Statement, in order. Others, including JScript, evaluate Fze
    | upon entering the execution context that it appears in. Yet others,
    | notably BESEN and DMDScript, throw a SyntaxError.
    |
    | For consistent behavior across implementations, do not use function
    | statement; use either FunctionExpression or FunctionDeclaration
    | instead.

    Garrett
     
    Garrett Smith, Jun 15, 2010
    #19
  20. On 6/15/2010 12:00 AM, Garrett Smith wrote:
    > On 6/14/2010 7:08 PM, pedz wrote:
    >> On Jun 14, 6:49 pm, Garrett Smith<> wrote:
    >>> It is mentioned in the code guidelines doc in three places:
    >>>
    >>> http://jibbering.com/faq/notes/code-guidelines/#design

    >>
    >> I was curious so I poked the link. The first bullet was not clear to
    >> me.
    >>
    >> Why is:
    >>
    >>> goog.isDef = function(val) {
    >>> return val !== undefined;
    >>> };

    >>
    >> a useless function?
    >>

    >
    > Yes. Not only is it is useless, it can lead to potential misuse.
    >


    Correction: Not only is it useless...

    >
    > It is strange design to be giving `x` a value that could be any of: 1) a
    > finite number, 2) NaN, or 3) undefined. If avoiding NaN was wanted, (as
    > would happen for Number(undefined)), then the code fails on that
    > account. Instead, it could have succeeded by using instead the built-in
    > `isFinite` function. Example:
    >


    Sorry, Number(undefined) results in NaN, but that would not happen
    because that case is covered by goog.isDef.

    Number(NaN) and cases where `opt_x` is not undefined, but converts to
    NaN are not covered. If disallowing NaN values to be assigned to the `x`
    and `y` properties is wanted, the code fails.

    Garrett
     
    Garrett Smith, Jun 15, 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. sunil panda

    Lower bound & Upper bound

    sunil panda, Dec 25, 2003, in forum: Java
    Replies:
    9
    Views:
    7,294
    thushara wijeratna
    Oct 7, 2008
  2. RC
    Replies:
    1
    Views:
    1,650
    Martin Honnen
    Jun 14, 2006
  3. RC
    Replies:
    1
    Views:
    116
    Martin Honnen
    Jun 14, 2006
  4. dhtml
    Replies:
    32
    Views:
    436
    Peter Michaux
    Oct 13, 2008
  5. Dmitry A. Soshnikov

    Note 2. ECMAScript. Equality operators.

    Dmitry A. Soshnikov, Jun 25, 2010, in forum: Javascript
    Replies:
    24
    Views:
    213
    Dmitry A. Soshnikov
    Jun 30, 2010
Loading...

Share This Page