FYI: Priveleged method gotcha

G

George Jempty

OK, wanted to make a more positive contribution to start than just
plonking somebody. Here's something I've discovered using "priveleged
methods" a la Douglas Crockford
(http://crockford.com/javascript/private.html):

If you want a constructor to utilize priveleged methods the methods must
be defined in the constructor ABOVE where they are called. Consider the
following:

function ExaminableField(element, examCriteria)
{
var formElement = element;
var name = element.name;
var required = true;

//must be defined before used privately
this.isRequired = function()
{
if (arguments.length == 1)
{
required = arguments[0]
}
return required;
}

if (!!examCriteria)
{
this.isRequired(examCriteria.required);
}

}

It had been causing an error when I had my if block above the definition
of this.isRequired. Thought this might help somebody, and/or contribute
to a proper convention.
 
D

Douglas Crockford

OK, wanted to make a more positive contribution to start than just
plonking somebody. Here's something I've discovered using "priveleged
methods" a la Douglas Crockford
(http://crockford.com/javascript/private.html):

If you want a constructor to utilize priveleged methods the methods must
be defined in the constructor ABOVE where they are called.

It is generally a good thing to define things before using them. This is
particularly true in a dynamic language like JavaScript, where the WHEN of a
definition is significant. The critical thing is BEFORE. Often that means ABOVE,
but not always.
if (!!examCriteria)

!! converts its operand to a boolean. If it was falsy, it produces false,
otherwise it produces true. But in an if, falsy values are ok, so the !! is
wasted. It is better to write

if (examCriteria)
 
R

Richard Cornford

Here's something I've discovered using "priveleged
methods" a la Douglas Crockford
(http://crockford.com/javascript/private.html):

If you want a constructor to utilize priveleged methods the
methods must be defined in the constructor ABOVE where they
are called. Consider the following:

function ExaminableField(element, examCriteria)
{
var formElement = element;
var name = element.name;
var required = true;

//must be defined before used privately
this.isRequired = function()
{
if (arguments.length == 1)
{
required = arguments[0]
}
return required;
}

if (!!examCriteria)

This double NOT (- !! -) is a nice construct as it produces a boolean
that represents the type-converted true-ness of its right-most operand.
Useful to flag the existence of a browser feature to avoid having to
have it type-converted for multiple subsequent tests:-

var useGetById = !!document.getElementById;

( compared with clunkier looking alternatives like:-
var useGetById = (document.getelementById)?true:false;
)

- but it is not needed here. The first - ! - will have to type-convert
its operand to a boolean value prior to inverting it, the second - ! -
will then invert that boolean and produce the value used to resolve
the - if - statement. However, if the identifier was used directly
within the if statement it would be type-converted to boolean to resolve
the - if - statement, so - if(examCriteria) - must always produce the
same results as - if(!!examCriteria) - but fractionally quicker.
{
this.isRequired(examCriteria.required);
}

}

It had been causing an error when I had my if block above the
definition of this.isRequired. Thought this might help
somebody, and/or contribute to a proper convention.

Because the function assigned to - this.isRequired - is a function
expression it is evaluated inline as the constructor executes so there
would be no value assigned to - this.isRequired - prior to the execution
of the assignment.

In contrast, inner function definitions (private methods in class based
OO terminology) are evaluated during the creation of the "variable"
object as the script enters the execution context for the function
call[1]. So it should be possible to call such a function in code that
physically precedes its definition and also render that function object
privileged by assigning a reference to it to a public object member:-

function ExaminableField(element, examCriteria){
var formElement = element;
var name = element.name;
var required = true;

if(examCriteria){
_requed(examCriteria.required);
}

this.isRequired = _requed;

function _requed(){
if(arguments.length == 1){
required = arguments[0]
}
return required;
}
}

- Doing so seems unnecessary. I would just put up with having to write
the constructor in the required order if I wanted the method to be
privileged.

[1] The Mozilla/Gecko implementation seems to be a bit off spec (ECMA
262 3rd Edition) in this respect as it handles inner function
definitions contained within blocks, such as - if(x){ function doX(){
.... } } - as if they were inline in some sense. It would be unusual to
be using inner function definitions in that way so there should be no
significant consequences.

Richard.
 
A

Andy Fish

This double NOT (- !! -) is a nice construct as it produces a boolean
that represents the type-converted true-ness of its right-most operand.
Useful to flag the existence of a browser feature to avoid having to
have it type-converted for multiple subsequent tests:-

var useGetById = !!document.getElementById;

( compared with clunkier looking alternatives like:-
var useGetById = (document.getelementById)?true:false;
)

I realise this is a bit OT but I find the double-not it very useful when
validating combinations of values. For instance, if the user can specify
either parameter a or parameter b but not both, we can write

if ( !!a != !!b) {
parameters are valid
}

obviously != transliterates into XOR. more elaborate validation rules are
easily expressed in this way when the longhand logic would be near
impossible to comprehend.

This also technique is also handy in C and java.

Andy
 
R

Richard Cornford

... I find the double-not it very useful when
validating combinations of values. For instance,
if the user can specify either parameter a or
parameter b but not both, we can write
if ( !!a != !!b) {
<snip>

Consider:-
(best viewed with fixed width font)

a | b | a != b |
true | false | true |
false | true | true |
true | true | false |
false | false | false |

!a | !b | !a != !b |
false | true | true |
true | false | true |
false | false | false |
true | true | false |

!!a | !!b | !!a != !!b |
true | false | true |
false | true | true |
true | true | false |
false | false | false |

Obviously - "aString != "anotherString" - is true, while - !"aString" !=
!"anotherString" - is false as both strings will type-convert to boolean
true (and then be inverted to false by the - ! - operator). So at least
one type-conversion to boolean is needed to do the comparison when a and
b are not boolean to start with. But it looks like - !a != !b - will
always produce the same results as - !!a != !!b - as the result of -
!something - is always boolean.

Richard.
 
G

George Jempty

Richard said:
Here's something I've discovered using "priveleged
methods" a la Douglas Crockford
(http://crockford.com/javascript/private.html):

If you want a constructor to utilize priveleged methods the
methods must be defined in the constructor ABOVE where they
are called. Consider the following:

function ExaminableField(element, examCriteria)
{
var formElement = element;
var name = element.name;
var required = true;

//must be defined before used privately
this.isRequired = function()
{
if (arguments.length == 1)
{
required = arguments[0]
}
return required;
}

if (!!examCriteria)


This double NOT (- !! -) is a nice construct as it produces a boolean
that represents the type-converted true-ness of its right-most operand.
Useful to flag the existence of a browser feature to avoid having to
have it type-converted for multiple subsequent tests:-

var useGetById = !!document.getElementById;

( compared with clunkier looking alternatives like:-
var useGetById = (document.getelementById)?true:false;
)

- but it is not needed here. The first - ! - will have to type-convert
its operand to a boolean value prior to inverting it, the second - ! -
will then invert that boolean and produce the value used to resolve
the - if - statement. However, if the identifier was used directly
within the if statement it would be type-converted to boolean to resolve
the - if - statement, so - if(examCriteria) - must always produce the
same results as - if(!!examCriteria) - but fractionally quicker.

I use !! because examCriteria, or any other variable for that matter,
might contain 0 or "", and I don't necessarily want these values to
evaluate as false.

George Jempty
 
G

George Jempty

George said:
I use !! because examCriteria, or any other variable for that matter,
might contain 0 or "", and I don't necessarily want these values to
evaluate as false.

Never mind....major brain fart
 
L

Lasse Reichstein Nielsen

George Jempty said:
I use !! because examCriteria, or any other variable for that matter,
might contain 0 or "", and I don't necessarily want these values to
evaluate as false.

But they do.
!!0 === false
!!"" === false
!!null === false
!!undefined === false
!!NaN === false

The conversion performed by !! is exactly the same as the one
performed by the function Boolean or implicitly by a conditional (if,
while, do/while, ?:).

/L
 
Y

Yep

Richard Cornford said:
[1] The Mozilla/Gecko implementation seems to be a bit off spec (ECMA
262 3rd Edition) in this respect as it handles inner function
definitions contained within blocks, such as - if(x){ function doX(){
... } } - as if they were inline in some sense.

But they are! A function declaration is _illegal_ in a block
statement, therefore a function defined as you describe could be only
a function expression, not a function declaration, and should
therefore be processed as an expression. Guess which browser is a bit
off spec ;-)


Regards,
Yep.
 
R

Richard Cornford

... . it now seems unlikely that the
inner function is not being treated (correctly) ...
<snip>

The - not - in "not being treated" should not have been their. The final
paragraph should have read:-

The accessibility of the inner function by its identifier gave the
impression that Mozilla was treating the inner function as a function
declaration rather than as an expression. It now seems unlikely that
the inner function is being treated (correctly) as an expression but
that still leaves Mozilla a bit off spec on the scope chain ;-)

Richard.
 
Y

Yep

Richard Cornford said:
When the function object is created by the evaluation of the function
expression the (optional) identifier is created as a property on a new
object added to the front of the current scope chain. That scope chain
is passed to the new function and the new Object is then removed from
the current scope chain. That means that the only scope that can resolve
the identifier for the function to a reference to the function object is
the scope within that function.

<snip excellent illustration />

I see what you mean, but ISTM that this is an ECMA inconsistency, and
as such I won't throw the stone to Mozilla guys for making such an
"exception" in not respecting the specs :)

Check also the amusing
var foo = function bar(){ alert("Guess who I am");}
foo(); bar();
which is OK in IE but not in Mozilla and Opera for which "bar" is
undefined (now the behavior you're expecting is correct for Mozilla,
the identifier is really lost).

It's possible to check, however, that the identifier isn't really lost
and is indeed kept in the scope passed to the function. Check the
following in Mozilla:
var dw=function(s){document.write(s+"<br>")}
var foo = function bar(){
//foo.__parent__ is the local scope of foo
dw(foo.__parent__.bar) //now it's found!
dw(foo.__parent__.foo) //not found, foo is in global scope

//foo.__parent__.__parent__ is the global scope
dw(foo.__parent__.__parent__.foo); //found, OK
dw(foo.__parent__.__parent__.bar); //not found, "OK"
}
foo()


Cheers,
Yep.
 
D

Douglas Crockford

Check also the amusing
var foo = function bar(){ alert("Guess who I am");}
foo(); bar();
which is OK in IE but not in Mozilla and Opera for which "bar" is
undefined (now the behavior you're expecting is correct for Mozilla,
the identifier is really lost).

And check this out in IE:

<html><head><script>
var foo = function bar(){ alert(bar.ok);}
foo.ok = 'correct';
foo();
</script></head></html>

IE puts the function name in the wrong scope. It should go in the inner scope,
but instead is put in the outer scope.

http://www.crockford.com/javascript/private.html
 
Y

Yep

Douglas Crockford said:
And check this out in IE:

<html><head><script>
var foo = function bar(){ alert(bar.ok);}
foo.ok = 'correct';
foo();
</script></head></html>

IE puts the function name in the wrong scope. It should go in the inner scope,
but instead is put in the outer scope.

Actually IE seems to evaluate the "function bar" twice, the first time
as a function declaration, the second time as a function expression
(where it doesn't add the identifier to the inner scope chain - it
even does nothing with the identifier); as a result foo and bar aren't
even equal.

Add
bar.ok = "Hello?"
at the beginning of your script to have an illustration.


Regards,
Yep.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,079
Messages
2,570,574
Members
47,206
Latest member
Zenden

Latest Threads

Top