![]() | |
![]() |
| | Thread Tools | Display Modes |
#1
| |||
| |||
|
|
J.Walker [...] wrote [...]: Weird question, how can I make the history.back function work from a different window? Another way of saying it is I have two open windows, is it possible to make the history of one window go back from the other window? In this situation the two windows are not in frames. I don't think you can. |
|
| (t == "object" && oWindow.history.back))) { |
#2
| |||
| |||
|
|
if (oWindow && (typeof oWindow.closed == "undefined" || !oWindow.closed) && typeof oWindow.history == "object" && ((t = typeof oWindow.history.back) == "function" || (t == "object" && oWindow.history.back))) { snip |
#3
| |||||
| |||||
|
|
Thomas 'PointedEars' Lahn wrote: snip if (oWindow && (typeof oWindow.closed == "undefined" || !oWindow.closed) && typeof oWindow.history == "object" && ((t = typeof oWindow.history.back) == "function" || (t == "object" && oWindow.history.back))) { snip [...] Unfortunately what is true for hose methods is also true for host objects. Your test has excluded, for example, IceBrowser, from an operation that it fully supports because its - history - object will return "function" from a - typeof - test. There does not appear to be any pattern as to which of the two possible strings will be returned by a - typeof - test on a host object across browsers. |
|
That necessitates - typeof - testing on host object to also be carried out against two strings (or NOT "undefined", |
|
plus maybe the test to exclude the possibility of a - null - reference, |
|
though I am yet to see a browser with a null - history - reference). |
|
It is precisely because of this aspect of - typeof - testing when dealing with host objects and methods, that makes me think that type-converting tests are better suited to the task, as they tell you what you need to know in one operation. |
#4
| |||||||||||
| |||||||||||
|
|
Richard Cornford wrote: Thomas 'PointedEars' Lahn wrote: snip if (oWindow && (typeof oWindow.closed == "undefined" || !oWindow.closed) && typeof oWindow.history == "object" && ((t = typeof oWindow.history.back) == "function" || (t == "object" && oWindow.history.back))) { snip That necessitates - typeof - testing on host object to also be carried out against two strings (or NOT "undefined", Yes, testing against NOT "undefined" would then be better than not testing at all. |
|
On the other hand, why support a host using an engine so badly broken that it neither returns "object" or "function" for an object or method? |
|
plus maybe the test to exclude the possibility of a - null - reference, That issue is already covered by the above code, since `null' evaluates to `false' in a conditional expression. |
|
It is precisely because of this aspect of - typeof - testing when dealing with host objects and methods, that makes me think that type-converting tests are better suited to the task, as they tell you what you need to know in one operation. I tend to avoid type-converting tests where reasonable, since they create warnings in the Mozilla JavaScript Console, |
|
11.4.3 The typeof Operator The production UnaryExpression : typeof UnaryExpression is evaluated as follows: 1. Evaluate UnaryExpression. 2. If Type(Result(1)) is not Reference, go to step 4. 3. If GetBase(Result(1)) is null, return "undefined". 4. Call GetValue(Result(1)). 5. Return a string determined by Type(Result(4)) according to the following table: ... 11.4.9 Logical NOT Operator ( ! ) The production UnaryExpression : ! UnaryExpression is evaluated as follows: 1. Evaluate UnaryExpression. 2. Call GetValue(Result(1)). 3. Call ToBoolean(Result(2)). 4. If Result(3) is true, return false. 5. Return true. |
|
11.2.1 Property Accessors Properties are accessed by name, using either the dot notation: ... The dot notation is explained by the following syntactic conversion: MemberExpression . Identifier is identical in its behaviour to MemberExpression [ <identifier-string> ] ... The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows: 1. Evaluate MemberExpression. 2. Call GetValue(Result(1)). 3. Evaluate Expression. 4. Call GetValue(Result(3)). 5. Call ToObject(Result(2)). 6. Call ToString(Result(4)). 7. Return a value of type Reference whose base object is Result(5) and whose property name is Result(6). ... |
|
10.1.4 Scope Chain and Identifier Resolution ... During execution, the syntactic production PrimaryExpression : Identifier is evaluated using the following algorithm: 1. Get the next object in the scope chain. If there isn't one, go to step 5. 2. Call the [[HasProperty]] method of Result(1), passing the Identifier as the property. 3. If Result(2) is true, return a value of type Reference whose base object is Result(1) and whose property name is the Identifier. 4. Go to step 1. 5. Return a value of type Reference whose base object is null and whose property name is the Identifier. The result of evaluating an identifier is always a value of type Reference with its member name component equal to the identifier string. |
|
8.7.1 GetValue (V) 1. If Type(V) is not Reference, return V. 2. Call GetBase(V). 3. If Result(2) is null, throw a ReferenceError exception. 4. Call the [[Get]] method of Result(2), passing GetPropertyName(V) for the property name. 5. Return Result(4). |
|
8.7 The Reference Type ... GetBase(V). Returns the base object component of the reference V. GetPropertyName(V). Returns the property name component of the reference V. ... |
|
8.6.2.1 [[Get]] (P) When the [[Get]] method of O is called with property name P, the following steps are taken: 1. If O doesn't have a property with name P, go to step 4. 2. Get the value of the property. 3. Return Result(2). 4. If the [[Prototype]] of O is null, return undefined. 5. Call the [[Get]] method of [[Prototype]] with property name P. 6. Return Result(5). |
|
maybe concealing other, more important warnings. snip |
#5
| |||
| |||
|
|
Thomas 'PointedEars' Lahn wrote: Richard Cornford wrote: Thomas 'PointedEars' Lahn wrote: snip if (oWindow && (typeof oWindow.closed == "undefined" || !oWindow.closed) && typeof oWindow.history == "object" && ((t = typeof oWindow.history.back) == "function" || (t == "object" && oWindow.history.back))) { snip That necessitates - typeof - testing on host object to also be carried out against two strings (or NOT "undefined", Yes, testing against NOT "undefined" would then be better than not testing at all. I tend to think of testing in terms of combining efficiency and adequate discrimination. Javascript, as an interpreted language, is not that fast so efficiency is often a consideration, the habitual authoring of efficient code avoids any need for additional thought in authoring code where efficiency is critical. A complex test, involving a series of string comparisons is not that much of a problem if it only needs to be done once, the more the test is repeated the more significant its efficiency becomes. Though above all a test should always tell you what you need to know, but that is usually an object on the one hand and null or undefined on the other, making a type-converting test a one operation process for making the decision. On the other hand, why support a host using an engine so badly broken that it neither returns "object" or "function" for an object or method? There would be no grounds for calling a browser broken if it did not return one of "object" or "function" from a typeof operation on its host objects as ECMA 262 specifically states that the string result of the operation is "Implementation-dependent". Which means you have specified results with null and undefined values but a reliance on a result being one of "object" or "function" with a host object can only be based on a coincidence of implementation, not a specified relationship. plus maybe the test to exclude the possibility of a - null - reference, That issue is already covered by the above code, since `null' evaluates to `false' in a conditional expression. Not directly in the case of - oWindow.history -, though that would be an obvious addition once that property accessor was subject to the same tests as - oWindow.history.back - to cover the - typeof oWindow.history == 'function' - posibility. snip It is precisely because of this aspect of - typeof - testing when dealing with host objects and methods, that makes me think that type-converting tests are better suited to the task, as they tell you what you need to know in one operation. I tend to avoid type-converting tests where reasonable, since they create warnings in the Mozilla JavaScript Console, Should a tool be dictating programming style? Maybe one could be allowed to, but only if its influence was for the better. So it is worth considering the validity (and so value) of Mozilla's warning in this context. The simplest comparison with - typeof - would be another Unary Operation that does type converting to boolean, for which logical NOT is a reasonable choice. The expression - typeof window.fictional - does not cause Mozilla to generate a warning, while - !window.fictional - does. So what is the difference between the two that could justify the warning in the second case but not in the first. The obvious place to look for the differences between two operations is in the language specification (ECMA 262 3rd edition), which specifies the following algorithms for the operations:- | 11.4.3 The typeof Operator | | The production UnaryExpression : typeof UnaryExpression is | evaluated as follows: | | 1. Evaluate UnaryExpression. | 2. If Type(Result(1)) is not Reference, go to step 4. | 3. If GetBase(Result(1)) is null, return "undefined". | 4. Call GetValue(Result(1)). | 5. Return a string determined by Type(Result(4)) according | to the following table: | ... | 11.4.9 Logical NOT Operator ( ! ) | | The production UnaryExpression : ! UnaryExpression is | evaluated as follows: | | 1. Evaluate UnaryExpression. | 2. Call GetValue(Result(1)). | 3. Call ToBoolean(Result(2)). | 4. If Result(3) is true, return false. | 5. Return true. The first item in each algorithm is the evaluation of the UnaryExpression, in this case - window.fictional -, which is a dot notation property accessor, evaluated as:- | 11.2.1 Property Accessors | | Properties are accessed by name, using either the dot notation: | ... | The dot notation is explained by the following syntactic conversion: | MemberExpression . Identifier | is identical in its behaviour to | MemberExpression [ <identifier-string> ] | ... | The production MemberExpression : MemberExpression [ Expression ] | is evaluated as follows: | | 1. Evaluate MemberExpression. | 2. Call GetValue(Result(1)). | 3. Evaluate Expression. | 4. Call GetValue(Result(3)). | 5. Call ToObject(Result(2)). | 6. Call ToString(Result(4)). | 7. Return a value of type Reference whose base object is Result(5) | and whose property name is Result(6). | ... Property accessors item 1 is "Evaluate MemberExpression" and the MemberExpression is the identifier - window - in this case. Identifiers are resolved against the scope chain as described in section 10.1.4:- | 10.1.4 Scope Chain and Identifier Resolution | ... | During execution, the syntactic production | PrimaryExpression : Identifier is evaluated using the following | algorithm: | | 1. Get the next object in the scope chain. If there isn't one, go | to step 5. | 2. Call the [[HasProperty]] method of Result(1), passing the | Identifier as the property. | 3. If Result(2) is true, return a value of type Reference whose base | object is Result(1) and whose property name is the Identifier. | 4. Go to step 1. | 5. Return a value of type Reference whose base object is null and | whose property name is the Identifier. | | The result of evaluating an identifier is always a value of type | Reference with its member name component equal to the identifier | string. The final object in the scope chain is the global object and it has a property with the name "window" so the result of the evaluation of the MemberExpression - window - is a Reference type with a base object set to the global object and a property name set to "window". Property accessors:2. Call GetValue(Result(1)) - uses:- | 8.7.1 GetValue (V) | | 1. If Type(V) is not Reference, return V. | 2. Call GetBase(V). | 3. If Result(2) is null, throw a ReferenceError exception. | 4. Call the [[Get]] method of Result(2), passing GetPropertyName(V) | for the property name. | 5. Return Result(4). - Type(V) is Reference, so:- | 8.7 The Reference Type | ... | GetBase(V). Returns the base object component of the | reference V. | GetPropertyName(V). Returns the property name component of the | reference V. | ... - GetBase(V) returns the global object, which is not null (so no exception is thrown). GetValue 4: calls the [[Get]] method of the global object passing the string "window" as the its argument:- | 8.6.2.1 [[Get]] (P) | | When the [[Get]] method of O is called with property name P, the | following steps are taken: | | 1. If O doesn't have a property with name P, go to step 4. | 2. Get the value of the property. | 3. Return Result(2). | 4. If the [[Prototype]] of O is null, return undefined. | 5. Call the [[Get]] method of [[Prototype]] with property name P. | 6. Return Result(5). The global object does have a property named "window" so that property is returned as the result of GetValue(V), coincidentally the global object. Property Accessors 3. Evaluate Expression and 4. Call GetValue(Result(3)) - result in the string "fictional". Property Accessors 5. Call ToObject(Result(2)) - returns the global object, Property Accessors 6. Call ToString(Result(4)) - returns the string "fictional", and finally Property Accessors 7. Return a value of type Reference whose base object is Result(5) - resolves the property accessor - window.fictional - as a reference type with its base object set to the global object and its property names set to "fictional". So - typeof - and logical NOT have both evaluated their UnaryExpression to the same result in exactly the same way. At this point the typeof algorithm offers an opportunity to diverge from the process that has been parallel between the two operators up until this point. It's Typeof 2. If Type(Result(1)) is not Reference, go to step 4 - and Typof 3. If GetBase(Result(1)) is null, return "undefined". - allow typeof to diverge, but Result(1) is a Reference type and GetBase(Result(1)) is a reference to the global object so it is not null. Typeof takes no action at these two stages so the two algorithms are back in step at the next operation: Typeof 4. Call GetValue(Result(1))- and Logical NOT 2. Call GetValue(Result(1)) -, where result(1) is an identical Reference type so these steps in the algorithm generate the same results. GetValue calls the [[Get]] method on the global object, which does not find a property with the name "fictional" on the global object (or any of it's [[prototype]]s) and so returns the value - undefined. Having acquired the value referred to by the Reference type that resulted from the UnaryExpression the - typeof - operator returns a string based on Type(Result(4)), that string is "undefined" when the value of Result(4) is undefined. On the other hand, logical NOT passes the undefined value to the internal ToBoolean function, returning boolean false from an undefined value as its argument. The it inverts that boolean value and returns it. However, in terms of the sequence of actions in the specified algorithms - typeof - and logical NOT did not diverge in their operation until they were acting exclusively upon a value of undefined. Mozilla wants to generate the warning: "reference to undefined property window.fictional" with the logical NOT operation, so where was that reference to the undefined property? It could have been in the original evaluation of the UnaryExpression into a Reference type, or it could have been the call to GetValue that acted upon that Reference, after that point there are no more references to properties at all. But - typeof - also evaluated the same UnaryExpression to come up with the same result, and it passed that result to GetValue in exactly the same way as logical NOT did. There is no reason for these two unary operators having different statuses. Either referencing an undefined property warrants a warning, in which case - typeof - should also generate that warning, or neither operator should produce a warning. The authors of Mozilla appear to have made an arbitrary and baseless decision about this warning, and scripting in a way that attempts to avoid such a nonsense warning is not a good idea if it results in the creation of non-optimum code. maybe concealing other, more important warnings. snip Yes, it is a pity when nonsense warnings may swamp out other warnings that may contribute something valuable to the code authoring process (instead of getting in the way of it). Probably the solution is to have more resolution in the settings that control the issuing of warnings, beyond - pref("javascript.options.strict", <true|false>); - so that the type of warnings generated can be tailored to the authoring situation. Allowing cross-browser authors not to be bothered by warnings that are only suited to Mozilla specific authoring, without depriving people authoring exclusively for Mozilla of messages that make sense in their context. Richard. |
#6
| ||||
| ||||
|
|
"Richard Cornford"wrote: |
|
... that make sense in their context. Richard. You |
|
may need to have used copyhistory=yes when you opened the new windoww |
|
(assuming you used window.open()) |
![]() |
| Thread Tools | |
| Display Modes | |
| |