In JavaScript, Why Is the "This" Operator Inconsistent

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, while window.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 name
  • getAttribute('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



Leave a reply



Submit