I know that according to ECMAScript specification, non-strict methods will have thisArg transformed to the global object, if null or undefined was passed to them.
That's the reason this code logs the window object (in browsers) instead of null:
function x() {
console.log(this);
}
x.call(null);
What I don't understand, is why doing the same thing with Object.prototype.toString.call(null), doesn't transform null to the global object, but keeps it as null and returns the string [object Null].
Is it because 'use strict' is used in default implementation of toString method?
Is every built-in method run in strict-mode?
I couldn't find anything like that in the specification a https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.prototype.tostring.
Is every built-in method run in strict-mode?
Yes. It says so in ยง10.3 Built-in Function Objects:
"Built-in functions that are ECMAScript function objects must be strict functions."
This not only implies non-sloppy handling of the this argument, but also that these functions have no .arguments, .callee and .caller properties.
Related
MDN says it is "an Array like object" but does not say what it is an instance of.
It is not an HTMLCollection or NodeList.
If I call Object.prototype.toString.call(arguments) it returns "[object Arguments]" but arguments instanceof Arguments is an error.
So what is arguments an instance of?
So what is arguments an instance of?
It's an instance of Object. There does not appear to be any public Arguments constructor that you can use with instanceof to identify it that way.
If you want to uniquely identify it, then:
Object.prototype.toString.call(arguments) === "[object Arguments]"
is a safe way to identify it.
Per section 9.4.4 in the EcmaScript 6 specification, the arguments object is either an ordinary object or an exotic object. Here's what the spec says:
Most ECMAScript functions make an arguments objects available to their
code. Depending upon the characteristics of the function definition,
its argument object is either an ordinary object or an arguments
exotic object.
An arguments exotic
object is an exotic object whose array index properties map to the
formal parameters bindings of an invocation of its associated
ECMAScript function.
Arguments exotic objects have the same internal
slots as ordinary objects. They also have a [[ParameterMap]] internal
slot. Ordinary arguments objects also have a [[ParameterMap]] internal
slot whose value is always undefined. For ordinary argument objects
the [[ParameterMap]] internal slot is only used by
Object.prototype.toString (19.1.3.6) to identify them as such.
Since it is an "exotic" object, that essentially means it doesn't follow all the normal and expected conventions. For example, there is no constructor function from which you can create your own object. And, because there is no public constructor function, that probably also explains why there's no instanceof that you can test on it to uniquely identify it.
You can retrieve the name of the function where arguments returned from using callee.name
function test() {
this.args = arguments;
}
var obj = new test();
console.log(obj.args.callee.name);
function test() {
return arguments
}
console.log(test().callee.name);
See also Why was the arguments.callee.caller property deprecated in JavaScript? , Arguments object
I see in the Mozilla polyfill of fn.bind() like this:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
// other code omitted here...
};
}
I don't understand why we have to check the type of this... because if we say fn.bind() and fn is a function, then it will work, and if fn is not a function, then fn.bind will never reach Function.prototype.bind by prototypal inheritance. So why do we have to check the type of this?
if fn is not a function, then fn.bind will never reach Function.prototype.bind by prototypal inheritance.
True, however this is not the only way this could be set. For example, if we were to use the .call or .apply methods on the bind function itself, or do something really crazy like assign it to other objects, it would behave differently from the native function.
Considering the following code using the native ES5 method:
var notAFunction = {};
var someObject = {};
Function.prototype.bind.call(notAFunction, someObject);
This will throw a TypeError, like the following:
TypeError: Function.prototype.bind called on incompatible Object
This extra check is basically emulating this sanity check from the native function as closely as it can.
So why do we have to check the type of this?
You don't technically have to, as this case would be an edge-case for most sane code, but in order to make the polyfill behave more-closely to the ES5 spec, it is nice. Since ES5 browsers will never even run this code, there is also no performance hit for modern browser.
This behavior is defined in the ECMA-262 5.1 Edition specification and onward:
Let Target be the this value.
If IsCallable(Target) is false, throw a TypeError exception.
Not all callable objects inherit from (or are equal to) Function.prototype. For example:
typeof document.createElement('object') === "function"; // true
document.createElement('object') instanceof Function; // false
And even objects which inherit from Function.prototype could have bind shadowed:
var f = function() {};
f.bind = 123;
f.bind === Function.prototype.bind; // false
However, you may want to be able to call Function.prototype.bind on those callable objects. That's why we have things like Function.prototype.call, Function.prototype.apply or Reflect.apply. You can use those to call bind on any object, whether it's callable or not.
The inverse is also possible. You can have an object which inherits from Function.prototype and is not callable. For example:
Object.create(Function.prototype) instanceof Function; // true
typeof Object.create(Function.prototype) === "function"; // false
Therefore, you can't make any assumption. If you want the polyfill to conform to ES5, you must check whether the object is callable. In ES5, checking whether typeof returns "function" does exactly that (but in ES3 it might not work for host objects).
This question already has answers here:
In JavaScript, why typeof Function.prototype is "function", not "object" like other prototype objects?
(4 answers)
Closed 2 years ago.
When I execute the code:
console.log(Function.prototype);
It returns:
function Empty() {}
(At least in Chrome)
Why exactly is this? I was under the impression that prototypes were almost always straight-up object literals, and that seems to be the case almost everywhere else I've checked. I'm curious as to why Function.prototype resolves to something different.
Because that is what ECMAScript 5 requires.
15.3.4 Properties of the Function Prototype Object
The Function prototype object is itself a Function object (its [[Class]] is "Function") that, when invoked, accepts any arguments and returns undefined.
Most (or all?) other native constructors have prototypes defined as the same type of object that is produced.
Considering that the prototype object holds the methods for that type, it makes sense that those methods should function properly when called on that object.
Firstly note the actual prototype of an object, as in the thing an object inherits behavior from, is stored in its __proto__ property (in most implementations - thx #the system). The Function object's "prototype" property is its own __proto__, which is special inbuilt function literal singleton object function(){} (which Chrome's console.log() must print as function Empty() {} for whatever reason but its the same thing). Since all functions are objects (but not all objects are functions) this object's __proto__ is another special inbuilt literal singleton object [object Object]. [object Object] __proto__ is null. [object Object] is the root of the prototype chain.
Examining the output of this shows how things are arranged (runnable from a command line interpreter).
print( Function.prototype === Function.__proto__ );
var f = new Funtion();
print( f.__proto__ === Function.prototype );
print( f.__proto__ );
print( f.__proto__.__proto__ );
print( f.__proto__.__proto__.proto__ );
Now, built-in JavaScript objects have a property called "class". This property is immutable and set by the JavaScript engine itself. The class is used by JavaScript for special internal purposes. Javascript needs to know this, so it knows Function objects can be invoked for example (as implied in the link from a previous answer given by #thesystem - http://es5.github.com/#x15.3.4). From the spec:
"The value of the [[Class]] internal property is defined by this specification for every kind of built-in object. The value of the [[Class]] internal property of a host object may be any String value except one of "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", and "String". The value of a [[Class]] internal property is used internally to distinguish different kinds of objects. Note that this specification does not provide any means for a program to access that value except through Object.prototype.toString (see 15.2.4.2)." - http://es5.github.com/#x8.6.2
The "class" of the Function object's prototype AKA function(){} is "Function". The class of Function is also "Function". When a new object is created Javascript sets its class property directly, based on the class property of its constructor, and this is immutable for the life of the object.
John Resig wrote:
Finally, a long-standing (and very annoying) bug has been resolved: Cases where null or undefined is coerced into becoming the global object. Strict mode now prevents this from happening and throws an exception instead.
(function(){ ... }).call( null ); // Exception
what bug is he referring to?
Basically, you are using the call() method from Function.prototype, which by default takes scope as the first parameter. If execution scope is undefined or null, it defaults to the global object. In some situations, using the call method with an Immediately Invoked Function Expression(the above code is rather uncommon) doesn't use the global object as the default fallback execution scope.
If this is evaluated within strict mode code, then the this value is not coerced to an object. A this value of null or undefined is not converted to the global object and primitive values are not converted to wrapper objects. The this value passed via a function call (including calls made using Function.prototype.apply and Function.prototype.call) do not coerce the passed this value to an Object (10.4.3, 11.1.1, 15.3.4.3, 15.3.4.4 clauses of the ECMA language specification).
Why does the following work:
function sum(a,b) { return a + b; }
var result = sum.call(null,3,4); // 7
Why is result defined? I am invoking sum as a method of null. But null is not an object and cannot have properties!
What is going on?
The first argument for Function.prototype.call is the context, which defines the this value for the execution context of the invoked function, nothing else.
So basically, you're saying that this is referring to null (at least, in ES5 strict mode), but since you don't access this anyway, it makes no difference.
In non-strict mode, this cannot be null, so it's replaced with the global object instead.
When you use .call or .apply with null or undefined, the default this (usually window) is automatically used instead if not in strict mode.
From MDN (emphasis mine):
thisArg
The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.
If you are in strict mode, it actually will be null or undefined.
(function() {
'use strict';
return this;
}).call(null); // null
(function() {
'use strict';
return this;
})(); // undefined
Its not. NULL in this case specifies to what object the this keyword is bound to. In your method, by setting it to NULL it will either not have a this variable binding or it will be bound to the function itself or the window.
Since you're not using any variables or functions that are accessed via this, then there's no need to use the call method ... you can just use sum(3,4)
As stated in, for example, MDN, the first argument is
The value of this provided for the call to [the method]. Note that
this may not be the actual value seen by the method: if the method is
a function in non-strict mode code, null and undefined will be
replaced with the global object, and primitive values will be boxed.
As the MDN explained.
thisArg
The value of this provided for the call to fun. Note that this may not
be the actual value seen by the method: if the method is a function
in non-strict mode code, null and undefined will be replaced with the
global object, and primitive values will be boxed.
Simply put it by a little code.
<script >
'use strict'
function fun() {
alert(this);
}
fun.call(null);
</script>
In the strict mode ,this is null. But in the not strict mode . this is window or global object.