Cannot make sense of some JavaScript

O

Oltmans

I was looking at hash.js (http://jonathan.tang.name/files/js_hash/
hash.js) source code and I just cannot make sense of the following
lines

-------

if(typeof window.Hash != 'undefined') {
var _Hash = window.Hash;
}

var Hash = window.Hash = function(args) {
if(this instanceof arguments.callee) {
this.init.apply(this, args && args.callee ? args : arguments);


} else {
return new Hash(arguments);
}
};
 
H

Hubert

// When global 'Hash' variable has a value, save it in local '_Hash'
variable.
if(typeof window.Hash != 'undefined') {
    var _Hash = window.Hash;
}

// Define a local and a global function named 'Hash'
var Hash = window.Hash = function(args) {
// Check if 'Hash' is being called with the 'new' operator.
    if(this instanceof arguments.callee) {
// Run the 'init' method (defined elsewhere) on the current
object.
        this.init.apply(this, args && args.callee ? args : arguments);

    } else {
// Make sure the 'new' operator is used and return its
result.
        return new Hash(arguments);
    }
};
Can someone please briefly explain what does above lines do? I will
really appreciate that. Please pardon my ignorance.

Hope it helps,
Hubert
 
R

rf

// When global 'Hash' variable has a value, save it in local '_Hash'
variable.
if(typeof window.Hash != 'undefined') {
var _Hash = window.Hash;
}

// Define a local and a global function named 'Hash'
var Hash = window.Hash = function(args) {
// Check if 'Hash' is being called with the 'new' operator.
if(this instanceof arguments.callee) {
// Run the 'init' method (defined elsewhere) on the current
object.
this.init.apply(this, args && args.callee ? args : arguments);

} else {
// Make sure the 'new' operator is used and return its
result.
return new Hash(arguments);
}
};
Can someone please briefly explain what does above lines do? I will
really appreciate that. Please pardon my ignorance.

Hope it helps,

No, it does not. I could make no sense of your post, even when I referred
back (on another screen) to the OP's post.

Try spacing your replies away from the OP's text a little more. I still
can't tell which bits of the above are your post.
 
M

Martin Rinehart

Oltmans said:
if(typeof window.Hash != 'undefined') {
var _Hash = window.Hash;
}

var Hash = window.Hash = function(args) {
if(this instanceof arguments.callee) {
this.init.apply(this, args && args.callee ? args : arguments);


} else {
return new Hash(arguments);
}
};

Are you sure you want to use this? That's some pretty bad code. The
first lines could be trimmed to:

if ( window.Hash ) { var _Hash = window.Hash; }

That doesn't do anything. window is the global object, so that just
says 'If Hash exists, make a copy in a pseudo-private, '_Hash'.

The next few don't show enough context to make any sense. They do show
some definite issues.

var a = b = c; // Very bad form; should have been two statements

a ? b : c // The ternary means: b if a is true, c if a is false.

If you never write a ternary you will never have buggy ternaries. If
you write ternaries you are writing code that will confuse even
yourself a week later.

Do you know that the JS object is a hash table? foo.bar is the same as
foo[bar].
 
W

William James

Martin said:
Are you sure you want to use this? That's some pretty bad code. The
first lines could be trimmed to:

if ( window.Hash ) { var _Hash = window.Hash; }

Are you really interested in trimming? That line can be trimmed to

if ( window.Hash )
var _Hash = window.Hash
That doesn't do anything. window is the global object, so that just
says 'If Hash exists, make a copy in a pseudo-private, '_Hash'.

The next few don't show enough context to make any sense. They do show
some definite issues.

var a = b = c; // Very bad form; should have been two statements

a ? b : c // The ternary means: b if a is true, c if a is false.

If you never write a ternary you will never have buggy ternaries. If
you write ternaries you are writing code that will confuse even
yourself a week later.

Better yet, if you never write any code, then you will never have
buggy code. Programmers aren't confused by the ternary operator.
I think that people who aren't programmers---people whose role is
to fiddle with html and web browsers---shouldn't write any program
code at all.
Do you know that the JS object is a hash table? foo.bar is the same as
foo[bar].

No, it isn't. It's the same as foo['bar'].
 
H

Hubert

No, it does not. I could make no sense of your post...

Begging your pardon.
Here is a clean-up.

// When global 'Hash' variable has a value,
// save it in local '_Hash' variable.
if(typeof window.Hash != 'undefined') {
var _Hash = window.Hash;
}

// Define function and store it both in a local variable
// and in a global variable named 'Hash'
var Hash = window.Hash = function(args) {
// Check if 'Hash' is being called with the 'new' operator.
if(this instanceof arguments.callee) {
// Run the 'init' method on the current object.
// The method should have been defined elsewhere!
this.init.apply(this, args && args.callee ? args : arguments);
} else {
// Make sure the 'new' operator is used
// and return its result.
return new Hash(arguments);
}
};

The meaning of the ternary expression, which supplies the argument to
'init' is very *deep*.

(1) When we are in an original call to 'new Hash(something)', then
args==something, so that 'arguments' is passed, which amounts to
passing 'something', which is ok.

(2) When we are in a redirected call which originally was just 'Hash
(something)'
then 'args' is the original 'arguments', and thus 'args.callee' is
defined,
so that the original arguments are passed to 'init', which is ok
again.

In sum:
the above construction makes sure that 'Hash' can both be called with
the 'new' operator or without,
having the same intended result in both cases.

Example:
Hash.prototype.init = function( a, b ) {
this.a = a;
this.b = b;
};

Hash.prototype.toString = function() {
return "[object Hash: a=" + this.a + ", b=" + this.b + "]";
}

function test() {
alert( new Hash( 1, 2 ) );
alert( Hash( 10, 20 ) );
}
 
D

David Mark

Begging your pardon.
Here is a clean-up.

// When global 'Hash' variable has a value,
// save it in local '_Hash' variable.
if(typeof window.Hash != 'undefined') {
    var _Hash = window.Hash;

}

// Define function and store it both in a local variable
// and in a global variable named 'Hash'
var Hash = window.Hash = function(args) {
    // Check if 'Hash' is being called with the 'new' operator.
    if(this instanceof arguments.callee) {
        // Run the 'init' method on the current object.
        // The method should have been defined elsewhere!
        this.init.apply(this, args && args.callee ? args : arguments);
    } else {
        // Make sure the 'new' operator is used
        // and return its result.
        return new Hash(arguments);
    }

};

The meaning of the ternary expression, which supplies the argument to
'init' is very *deep*.

ISTM, that something like this would be simpler:

var GLOBAL = this;

var Hash = function(args) {
if (this == GLOBAL) { // Called without "new"
return new Hash(arguments);
} else {
this.init.apply(this, typeof args == 'number' ? arguments : args);
}
};

Of course, this assumes you won't call it from another frame.

[snip]
 
H

Hubert

ISTM, that something like this would be simpler:

var GLOBAL = this;

var Hash = function(args) {
  if (this == GLOBAL) { // Called without "new"
    return new Hash(arguments);
  } else {
    this.init.apply(this, typeof args == 'number' ? arguments : args);
  }

};

David,

no, that is only a rather particular solution which is not general
enough.

(1) Checking *typeof args* against 'number' misses all cases where our
function
has different parameter types or no parameters at all.

(2) Checking *this* against *GLOBAL* (which in our case would be
*window*, right?) misses all cases where Hash might have been assigned
as a property to some object, obj.Hash = Hash say, and obj.Hash( ... )
would have been called. Reason: here we have *this* equal to *obj* and
not equal to *GLOBAL*.

(3) As you already said, it prevents using the function from another
window or frame.

Hubert
 
D

David Mark

David,

no, that is only a rather particular solution which is not general
enough.

(1) Checking *typeof args* against 'number' misses all cases where our
function
has different parameter types or no parameters at all.
True.


(2) Checking *this* against *GLOBAL* (which in our case would be
*window*, right?) misses all cases where Hash might have been assigned

In a browser, it would be the same as window.
as a property to some object, obj.Hash = Hash say, and obj.Hash( ... )
would have been called. Reason: here we have *this* equal to *obj* and
not equal to *GLOBAL*.

It is correct that my suggestion would not apply to these cases.

[snip]
 
T

Thomas 'PointedEars' Lahn

David said:
In a browser, it would be the same as window.

It *may* *mean* the same as `window'. However, since host objects
should not be augmented, and arbitrary host object's properties should
not be accessed without feature test, there shouldn't be window.Hash
there in the first place.


PointedEars
 
D

David Mark

It *may* *mean* the same as `window'.  However, since host objects

In a browser, yes.
should not be augmented, and arbitrary host object's properties should
not be accessed without feature test, there shouldn't be window.Hash
there in the first place.

And that has to do with what?
 
D

David Mark

You don't know that for sure because you just can't know it for sure.

Happily, there is no need to assume it.
The code posted in this thread.

I think I see your point in the context of the window is not
necessarily the global object argument.
 
T

Thomas 'PointedEars' Lahn

David said:
Hard proof of what?  That you don't have to assume the window is the
global object?

Prove that `window' works like the ECMAScript Global Object in all
browsers that are known to exist.


PointedEars
 
D

David Mark

Prove that `window' works like the ECMAScript Global Object in all
browsers that are known to exist.

References the global object? "Works like" has other implications.

As you know, such a proof is virtually impossible. That's why it's
best not to assume the premise.
 
T

Thomas 'PointedEars' Lahn

David said:
References the global object?  "Works like" has other implications.

Referencing boils down to "works like" in these languages.
As you know, such a proof is virtually impossible.  That's why it's
best not to assume the premise.

No, it rather shows without the shadow of a doubt that your argument
is flawed.

Fallacy of the undistributed middle: X is a browser (or: X and Y and Z
are browsers). `window' seems to refer to/works like the ECMAScript
Global Object (regarding global variables) in X (or: in X and Y and
Z); therefore, window' refers to the ECMAScript Global Object in all
browsers.


PointedEars
 
D

David Mark

Referencing boils down to "works like" in these languages.


No, it rather shows without the shadow of a doubt that your argument
is flawed.

And what argument would that be? I contend it is not a good idea to
assume the window object is the global object.
Fallacy of the undistributed middle: X is a browser (or: X and Y and Z
are browsers). `window' seems to refer to/works like the ECMAScript
Global Object (regarding global variables) in X (or: in X and Y and
Z); therefore, window' refers to the ECMAScript Global Object in all
browsers.

Not mine.

[snip]
 
T

Thomas 'PointedEars' Lahn

David said:
Thomas 'PointedEars' Lahn said:
David said:
:
David Mark wrote:
Thomas 'PointedEars' Lahn wrote:
David Mark wrote:
Thomas 'PointedEars' Lahn wrote:
David Mark wrote:
Thomas 'PointedEars' Lahn wrote:
David Mark wrote:
(2) Checking *this* against *GLOBAL* (which in our case would be
*window*, right?) misses all cases where Hash might have been assigned
In a browser, it would be the same as window.
It *may* *mean* the same as `window'.  [...]
In a browser, yes.
You don't know that for sure because you just can't know it for sure.
Happily, there is no need to assume it.
If so, you have not provided hard proof as of yet.
Hard proof of what?  That you don't have to assume the window is the
global object?
Prove that `window' works like the ECMAScript Global Object in all
browsers that are known to exist.

References the global object?  "Works like" has other implications.

Referencing boils down to "works like" in these languages.
As you know, such a proof is virtually impossible.  That's why it's
best not to assume the premise.
No, it rather shows without the shadow of a doubt that your argument
is flawed.

And what argument would that be?  I contend it is not a good idea to
assume the window object is the global object.
Fallacy of the undistributed middle: X is a browser (or: X and Y and Z
are browsers). `window' seems to refer to/works like the ECMAScript
Global Object (regarding global variables) in X (or: in X and Y and
Z); therefore, window' refers to the ECMAScript Global Object in all
browsers.

Not mine.

Then I would have to remind you that you did reply:

| > (2) Checking *this* against *GLOBAL* (which in our case would be
| > *window*, right?) [...]
|
| In a browser, it would be the same as window.

The code being referred to was (your own):

var GLOBAL = this;

var Hash = function(args) {
if (this == GLOBAL) { // Called without "new"
...


PointedEars
 

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

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top