In Javascript, why is the this operator inconsistent?
In JavaScript, this
always refers to the object invoking the function that is being executed. So if the function is being used as an event handler, this
will refer to the node that fired the event. But if you have an object and call a function on it like:
myObject.myFunction();
Then this
inside myFunction
will refer to myObject
. Does it make sense?
To get around it you need to use closures. You can change your code as follows:
function TestObject() {
TestObject.prototype.firstMethod = function(){
this.callback();
YAHOO.util.Connect.asyncRequest(method, uri, callBack);
}
var that = this;
TestObject.prototype.callBack = function(o){
that.secondMethod();
}
TestObject.prototype.secondMethod = function() {
alert('test');
}
}
Inconsistent behaviour of this in JavaScript strict mode
I'm not sure if I'm reading your question right, but it seems as if you are having trouble with the fact that func.apply(context, arguments)
can take context
as a parameter which will be then be reffered by this
inside the function.
I would argue that passing the context is necessary and JavaScript couldn't work properly without it.
Off the top of my head, since there is no super
the only way to use inheritance properly is to use something like BaseClass.prototype.baseFunction.apply(this, arguments)
.
Removing that functionality would create a language that is very different from JavaScript today and that is not what strict
mode is about.
Inconsistency in javascript comparison operator
A very similar case is handled in Why does ('0' ? 'a' : 'b') behave different than ('0' == true ? 'a' : 'b').
In short:
When you have a single value that is evaluated in a boolean context, it is passed to
ToBoolean
to be converted to a boolean value.If you compare values with
==
though, the algorithm in section 11.9.3 of the ECMAScript specification takes place. In this algorithm, both operands are converted to either strings or numbers and these values are compared.
More detailed explanation
a = [] ? 1 : 2
The condition is converted to a boolean by calling ToBoolean(GetValue(lref))
. Now I assume that for objects, GetValue
just returns the object itself and all objects evaluate to true
.
Since arrays are just objects, the result of this expression is 1
.
b = [] == true ? 1 : 2
As already said, quite some type conversion is going on here.
First, true
is converted to a number:
7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
false
is converted to 0
and true
is converted to 1
.
So we have
[] == 1
Then step 9 applies:
9. If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
That means []
is converted to a primitive value (string or number). If you follow the ToPrimitive
function (and section 8.12.8), you'll find out that arrays are converted to strings, by concatenating their elements with ,
. Since an empty array as no elements, the result is an empty string.
So we end up with
"" == 1
Then step 5 applies:
5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
An empty string is converted to 0
, hence 0 == 1
is false
and the conditional operator returns 2
.
Inconsistent behavior of JavaScript's + operator
Prepending a variable with a +
implies type coercion to a number type.
+ 5 => 5
+ '5' => 5
+'a' => NaN
+'/' => NaN
When you do +'/'
the result is NaN
Inconsistent Array.includes() behaviour - identical arrays returning different results
The includes() method determines whether a typed array includes a
certain element, returning true or false as appropriate.
You can't compare arrays contents' against each other using includes()
method you can use any other methods like loops. Read more about it here.
Reduction meta-operator inconsistency
It is not an inconsistency but and example of how operator associativity works in Raku.
Writing :
[<] 1,2,3,4
Is the same as writing :
1 < 2 < 3 < 4
In most languages this wouldn't work but the < operator has chain associativity so it effectively treats this as :
(1 < 2) and (2 < 3) and (3 < 4)
Which is True.
Javascript this keyword and variables pointing to an object method
It's because this
refers to the context that the function is called from. When you do p.sayName()
the context is p
. If you just call a function without context, it will default to the global context (usually window
) or undefined
in strict mode.
If you want to make it work the way you were expecting you can bind this
to p
, so that q()
:
q = p.sayName.bind(p);
q(); // My name is Smith
Why is JavaScript inconsistent across browsers?
The Javascript core language for the most part is consistent ( Referring to ECMAScript version 3 released in 1999. )
It's the DOM implementations that cause headaches. Partly because at one point there was no DOM specification so browsers could do whatever the hell they wanted in terms of making up the rules for which to access and manipulate html elements in a web page.
For example:
window.addEventListener
for DOM supporting browsers, whilewindow.attachEvent
for IE.textContent
for DOM supporting browsers,innerText
for IE.- Memory leakage for attached event handlers in IE so you have to unload them manually
getElementById
is buggy in IE and Opera because it returns elements by namegetAttribute('href')
returns inconsistent values
There are also issues relating to the browser's CSS support.
- IE6 doesn't support native PNGs so you are forced to use the filter library
- Buggy animation in IE dealing with filter opacity
Language core inconsistencies would be things like
- Inconsistencies between regex engines
But yeah, in short the point is that before, there was no standard. Since then, the w3 came up with standards, but every browser vendor has its own way of dealing with implementing it. There's no governing body that forces the vendors to fully apply the spec.
API or JavaScript inconsistencies
As @Jared Smith
said in comments there is no guarantee order of fetch
as it is asynchronous, to control the order use async
and await
to wait for the result of response something like this:
like.addEventListener("click", async () => await likes())
async function likes () {
await fetch(`/likes/${like.value}`, {
method: "PUT"});
if (like.innerHTML.slice(0, 2) != "Un") {
like.innerHTML = "Unlike 💔";
}
else {
like.innerHTML = "Like ❤";
}
await fetch(`/likes/${like.value}`);
const post = await response.json();
quantity.innerHTML = post["liked"].length;
}
Related Topics
Why Can't I Add Properties to a String Object in JavaScript
Event When Window.Location.Href Changes
What Does [].Foreach.Call() Do in JavaScript
Is This an Example of Variable Shadowing in JavaScript
How to Get Image from Canvas Element and Use It in Img Src Tag
How to Find the Width of a Div Using Vanilla JavaScript
Trigger CSS Animations in JavaScript
Google Maps API V3: Infowindow Not Sizing Correctly
How to Get HTML Elements from an Object Tag
Html5 Filereader How to Return Result
Url Hash-Bang (#!/) Prefix Instead of Simple Hash (#/) in Angular 1.6
How to Append <Script></Script> in JavaScript
How to Query Mongodb Objectid by Date
Fetch Request to Local File Not Working
How to Dynamically Create '@-Keyframe' CSS Animations
How to Load Images Dynamically (Or Lazily) When Users Scrolls Them into View