I was going through the Array'a find polyfill implementation on MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find?v=control#Polyfill
Copy pasting it below:
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
// 7. Return undefined.
return undefined;
}
});
}
Why is it that we need to do var o = Object(this);?
What does Object(this) achieve?
Thanks for any discussion.
In strict mode, a primitive this will not be coerced to an object.
Therefore, explicit coercion to an object using Object(this) is necessary.
Here is a more detailed example:
const array = Array.prototype;
Object.defineProperty(array, 'foo1', { value() {
return this.length >>> 0; }});
Object.defineProperty(array, 'foo2', { value() {
"use strict";
return this.length >>> 0; }});
console.log(Array.prototype.foo1.call(undefined));
console.log(Array.prototype.foo2.call(undefined));
The first example runs successfully with a result of 0, because the argument undefined is coerced to an object in non-strict mode. The second example fails, because undefined is not coerced in non-strict mode, and thus this.length errors out.
From MDN:
the value passed as this to a function in strict mode is not forced into being an object (a.k.a. "boxed")
However, in this case, there is already an explicit check for null or undefined:
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
so I am tempted to say the explicit casting to an object is not necessary. It is probably used here out of an abundance of caution, or as boilerplate.
This is a fascinating question... Thanks for your post!
To be honest, I am a bit surprised by Object(this) because JavaScript seems to coerce anything to object (using wrappers) in situations where this could potentially be a primitive value.
If we try to change this with Function.prototype.bind(), JavaScript always returns an object (a function is an object):
var foo = function () {
console.log(this, typeof this);
}.bind('foo');
var bar = function () {
console.log(this, typeof this);
}.bind(1337);
var baz = function () {
console.log(this, typeof this);
}.bind(false);
var qux = function () {
console.log(this, typeof this);
}.bind(NaN);
var quux = function () {
console.log(this, typeof this);
}.bind(undefined);
var corge = function () {
console.log(this, typeof this);
}.bind(null);
var grault = function () {
console.log(this, typeof this);
}.bind([]);
var garply = function () {
console.log(this, typeof this);
}.bind({});
var waldo = function () {
console.log(this, typeof this);
}.bind(/regex/);
var fred = function () {
console.log(this, typeof this);
}.bind(function () {});
foo(); // String { 0: "f", 1: "o", 2: "o" } object
bar(); // Number { 1337 } object
baz(); // Boolean { false } object
qux(); // Number { NaN } object
quux(); // Window object
corge(); // Window object
grault(); // Array [ ] object
garply(); // Object { } object
waldo(); // /regex/ object
fred(); // function fred<() function
If we try to change this with Function.prototype.call() or Function.prototype.apply(), once again, JavaScript always returns an object:
Array.prototype.foo = function () {
console.log(this, typeof this);
};
['foo'].foo(); // Array [ "foo" ] object
Array.prototype.foo.call('bar'); // String { 0: "b", 1: "a", 2: "r"} object
Array.prototype.foo.call(42); // Number { 42 } object
Array.prototype.foo.call(true); // Boolean { true } object
Array.prototype.foo.call(NaN); // Number { NaN } object
Array.prototype.foo.call(undefined); // Window object
Array.prototype.foo.call(null); // Window object
Array.prototype.foo.call({}); // Object { } object
Array.prototype.foo.call(/regex/); // /regex/ object
Array.prototype.foo.call(function () {}); // function () function
In JavaScript, we know that native objects may be useful for type conversion when they are not used as constructors but as regular functions. Number, String and Boolean are quite convenient:
var num = 1337,
str = '',
bool = true;
console.log(Number(str), typeof Number(str));
console.log(Number(bool), typeof Number(bool));
console.log(String(num), typeof String(num));
console.log(String(bool), typeof String(bool));
console.log(Boolean(num), typeof Boolean(num))
console.log(Boolean(str), typeof Boolean(str));
For the record, here is what we get with explicit conversions through Object():
console.log(typeof Object(false), Object(false) instanceof Boolean);
console.log(typeof Object('bar'), Object('bar') instanceof String);
console.log(typeof Object(42), Object(42) instanceof Number);
console.log(typeof Object(NaN), Object(NaN) instanceof Number);
console.log(typeof Object(undefined), Object(undefined) instanceof Object);
console.log(typeof Object(null), Object(null) instanceof Object);
console.log(typeof Object(['foo']), Object(['foo']) instanceof Array);
console.log(typeof Object({}), Object({}) instanceof Object);
console.log(typeof Object(/regex/), Object(/regex/) instanceof RegExp);
console.log(typeof Object(function () {}), Object(function () {}) instanceof Function);
Now it is obvious that Object(this) can be used to convert any primitive value for this and get a wrapper object instead. If this is already an object, it has no effect:
var obj1 = {baz: 'Baz'},
obj2 = Object(obj1);
var arr1 = ['foo', 'bar'],
arr2 = Object(arr1);
var reg1 = /regex/,
reg2 = Object(reg1);
var fun1 = function () { return 'Hello!'; },
fun2 = Object(fun1);
console.log(arr1 === arr2);
console.log(obj1 === obj2);
console.log(reg1 === reg2);
console.log(fun1 === fun2);
Moreover, Object is weird because it acts in the same way, whether it is called with new or not:
var foo = Object('foo'),
bar = new Object('bar');
console.log(foo);
console.log(bar);
I may be wrong, but my conclusion is the following: given that this is always coerced to an object, Object(this) is not necessary. However, it indicates explicitly what happens implicitly to avoid ambiguity and improve code comprehension.
What do you think?
EDIT
torazaburo is right: strict mode is the key! When functions are in strict mode, primitive values for this are not coerced! This is probably the most reasonable explanation for explicit conversion with Object(this)...
Function.prototype.bind()
var foo = function () {
'use strict';
console.log(this, typeof this);
}.bind('foo');
var bar = function () {
'use strict';
console.log(this, typeof this);
}.bind(1337);
var baz = function () {
'use strict';
console.log(this, typeof this);
}.bind(false);
var qux = function () {
'use strict';
console.log(this, typeof this);
}.bind(NaN);
var quux = function () {
'use strict';
console.log(this, typeof this);
}.bind(undefined);
var corge = function () {
'use strict';
console.log(this, typeof this);
}.bind(null);
var grault = function () {
'use strict';
console.log(this, typeof this);
}.bind([]);
var garply = function () {
'use strict';
console.log(this, typeof this);
}.bind({});
var waldo = function () {
'use strict';
console.log(this, typeof this);
}.bind(/regex/);
var fred = function () {
'use strict';
console.log(this, typeof this);
}.bind(function () {});
foo(); // foo string
bar(); // 1337 number
baz(); // false boolean
qux(); // NaN number
quux(); // undefined undefined
corge(); // null object
grault(); // Array [ ] object
garply(); // Object { } object
waldo(); // /regex/ object
fred(); // function fred<() function
Function.prototype.call()
Array.prototype.foo = function () {
'use strict';
console.log(this, typeof this);
};
['foo'].foo(); // Array [ "foo" ] object
Array.prototype.foo.call('bar'); // bar string
Array.prototype.foo.call(42); // 42 number
Array.prototype.foo.call(true); // true boolean
Array.prototype.foo.call(NaN); // NaN number
Array.prototype.foo.call(undefined); // undefined undefined
Array.prototype.foo.call(null); // null object
Array.prototype.foo.call({}); // Object { } object
Array.prototype.foo.call(/regex/); // /regex/ object
Array.prototype.foo.call(function () {}); // function () function
Related
I want to ask about call function behavior. I get stuck every time when I try to understand call function.
Can anybody help me to understand what is going on by suggesting implementation of the find method?
Hoge = function (val) {
this.val = val;
//console.log("this.val" + this.val);
};
Hoge.prototype.find = function (callback) {
callback.call(this.val);
};
var h = new Hoge(1);
h.find((o) => {
console.log(o); // expected 1 but undefined
console.log(o === 1); // expected true but its false (caz o is undefined)
});
You're not passing call a thisArg argument. Well, you are, but it's value you want passed to the callback.
Hoge = function(val) {
this.val = val;
//console.log("this.val" + this.val);
};
Hoge.prototype.find = function(callback) {
// callback.call(this.val);
callback.call(this, this.val); // call wants a "this" argument
// callback(this.val); // Could just do this instead
};
var h = new Hoge(1);
h.find((o) => {
console.log(o); // expected 1 but undefined
console.log(o === 1); // expected true but its false (caz o is undefined)
});
Function#call's first parameter is the this value. To directly invoke a function, just use parentheses.
callback(this.val);
Hoge = function (val) {
this.val = val;
};
Hoge.prototype.find = function (callback) {
callback(this.val);
};
var h = new Hoge(1);
h.find((o) => {
console.log(o);
console.log(o === 1);
});
The first param in call will be the new this you want to use. Then onwards are the params you want to pass.
You are basically not making a lot of use .call here, and if you simply want to use o you can pass null and this.val.
Even simpler, simply invoke the callback function
Hoge = function (val) {
this.val = val;
//console.log("this.val" + this.val);
};
Hoge.prototype.find = function (callback) {
//Both work
callback.call(null,this.val);
callback(this.val);
};
var h = new Hoge(1);
h.find((o) => {
console.log(o); // expected 1 but undefined
console.log(o === 1); // expected true but its false (caz o is undefined)
});
Studying the polyfill for the find method written on the MDN web docs, there's a particular line that I'm not following, let me share the code
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) {
if (this == null) {
throw TypeError('"this" is null or not defined');
}
var o = Object(this);
var len = o.length >>> 0;
if (typeof predicate !== 'function') {
throw TypeError('predicate must be a function');
}
var thisArg = arguments[1];
var k = 0;
while (k < len) {
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
k++;
}
return undefined;
},
configurable: true,
writable: true
});
}
My question is with the expression var o = Object(this);. What's the purpose of doing so instead of doing var o = this?. Printing the value in both described cases returns the same object.
Is this an abbreviated way of calling var o = new Object(this);?
I have removed the comments from the method to shorten the text, here's the link to the polyfill implementation.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Polyfill
Thanks!
In strict mode, this isn't always an object. Object(this) makes sure that o is an object, not a primitive.
Here's an example of this being a primitive:
"use strict";
Object.defineProperty(String.prototype, "nishCap", {
writable: true,
configurable: true,
value() {
console.log(typeof this); // "string"
const o = Object(this);
console.log(typeof o); // "object"
return o.substring(0,1).toUpperCase() + o.substring(1);
}
});
const capped = "foo".nishCap();
Note that this even applies to array methods, because you can call them on non-arrays, like Array.prototype.find.call("foo", ch => ch === "o").
Is this an abbreviated way of calling var o = new Object(this);?
No, new Object always creates a new object (and doesn't use the argument you give it). When you call Object as a function, it coerces its argument to object. So a primitive string becomes a String object, a primitive number becomes a Number object, etc.
What's the purpose of doing so instead of doing var o = this?
That polyfill is fairly closely following the spec, which starts out with:
Let O be ? ToObject(this value).
In most cases it wouldn't be important, but I wouldn't be surprised if there were some edge case where leaving it out would cause observable behavior at variance with the spec.
Because Array.prototype.find can be called with a this value which is not an object. See the specification:
When the find method is called, the following steps are taken:
Let O be ? ToObject(this value).
So, in order to be perfectly compliant with the specification, the polyfill needs Object(this). Otherwise, the implementations will not be the same, as you can see by the following two snippets:
'use strict';
const str = 'abc';
Array.prototype.find.call(
str,
(char, i, theThis) => {
// theThis should be an object, even if called on a non-object:
console.log(theThis);
}
);
'use strict';
Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) {
if (this == null) {
throw TypeError('"this" is null or not defined');
}
// Without object wrapping:
var o = this; // <-------------------------------
var len = o.length >>> 0;
if (typeof predicate !== 'function') {
throw TypeError('predicate must be a function');
}
var thisArg = arguments[1];
var k = 0;
while (k < len) {
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
k++;
}
return undefined;
},
configurable: true,
writable: true
});
const str = 'abc';
Array.prototype.find.call(
str,
(char, i, theThis) => {
// The polyfill above had no object wrapping, so this result is not the same:
console.log(theThis);
}
);
How do I splat across objects without using ECMA6 features?
Attempt
function can(arg0, arg1) {
return arg0 + arg1;
}
function foo(bar, haz) {
this.bar = bar;
this.haz = haz;
}
myArgs = [1,2];
With can I can just do:
can.apply(this, myArgs);
When trying with foo:
new foo.apply(this, myArgs);
I get this error (because I'm calling new):
TypeError: function apply() { [native code] } is not a constructor
Using Object.create
function foo(bar, haz) {
this.bar = bar;
this.haz = haz;
}
x = Object.create(foo.prototype);
myArgs = [5,6];
foo.apply(x, myArgs);
console.log(x.bar);
Using Object.create(proto) is the right way to go about this.
Coco and LiveScript (Coffeescript subsets) offer a workaround:
new foo ...args
compiles to
(function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args), t;
return (t = typeof result) == "object" || t == "function" ? result || child : child;
})
(foo, args, function(){});
And in CoffeeScript:
(function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args);
return Object(result) === result ? result : child;
})(foo, args, function(){});
These hacks are ugly, slow, and imperfect; for example, Date relies on its internal [[PrimitiveValue]]. See here.
Will this calc function be defined once (put on the prototype chain for the 'obj' variable)? If not, then how can I get the calc function on the prototype chain so all instantiations of Obj will reference the same calc function?
I tried assigning the calc function to Obj.prototype.calc, but then when 'obj' is created, it can't find it in the creation process.
window.onload = function () {
var Obj = function (obj) {
var calc = function (o) {
for (p in o) {
if (o.hasOwnProperty(p) && typeof o[p] === 'function') {
o[p] = o[p]();
}
}
return o;
};
return calc(obj);
};
function test() {
var obj = new Obj({
a: 1,
b: 2,
c: function () {
return this.a + this.b;
},
d: function () {
return this.b * this.c;
}
});
window.console.log(obj.a); // 1
window.console.log(obj.b); // 2
window.console.log(obj.c); // 3
window.console.log(obj.d); // 6
}
test();
}
The purpose of the Obj constructor is creating an object literal type syntax when I define many versions of 'obj' but allowing the use of the 'this' keyword to calculate properties in terms of other properties in each object.
Here is the version with the prototype definition which doesn't work:
<!DOCTYPE HTML>
<html>
<head>
<script>
window.onload = function () {
var Obj = function (obj) {
return calc(obj);
};
Obj.prototype.calc = function (o) {
for (p in o) {
if (o.hasOwnProperty(p) && typeof o[p] === 'function') {
o[p] = o[p]();
}
}
return o;
};
function test() {
var obj = new Obj({
a: 1,
b: 2,
c: function () {return this.a + this.b;},
d: function () {return this.b * this.c;}
});
window.console.log(obj.a);
window.console.log(obj.b);
window.console.log(obj.c);
window.console.log(obj.d);
}
test();
}
</script>
</head>
<body>
</body>
</html>
Will this calc function be defined once (put on the prototype chain for the 'obj' variable)?
No, it gets re-created every time your Obj function is called. (Also note that as Pointy, er, pointed out, you're falling prey to The Horror of Implicit Globals with your calc symbol.)
If not, then how can I get the calc function on the prototype chain so all instantiations of Obj will reference the same calc function?
By putting it there, and then using it from there:
Obj.prototype.calc = /* ...the function, use `this` rather than an argument... */;
and in Obj:
this.calc(); // No `return` needed
Simplified example:
var Foo = function(x, y) {
this.x = x;
this.y = y;
this.calc();
};
Foo.prototype.calc = function() {
this.z = this.x + this.y;
};
var f = new Foo(2, 3);
console.log(f.z); // "5"
I have a class definition method for create class in javascript:
var Class = function() {
var clazz = null,
pros = {};
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (typeof arg == "function") arg = arg.prototype;
else {
arg.init && (clazz = arg.init, delete arg.init)
}
for (var p in arg) pros[p] = arg[p];
}
clazz.prototype = pros;
return clazz;
};
var Person = Class({
init: function(name) {
this.name = name;
},
say:function(){
console.info(this.name);
}
});
var Man = Class(Person, {
init: function(name) {
Person.apply(this, arguments);
this.gender = 'man'
}
});
var m = new Man('kk');
console.info(m instanceof Man);
console.info(m instanceof Person);
However, it does not support the instanceof operator.
Any idea to fix it?
You should keep track of the prototype chain to make instanceof work. What you're currently doing is merely copying properties into one object, and use that as prototype of the returned function. As a result, the information that Parent is a parent of Man is lost.
You'd need to set the prototype instead of copying. Since you need to modify an existing object to set the underlying prototype of, the deprecated __proto__ property is required. Object.create cannot be used here, because that returns a new object.
Edit: It is possible without __proto__, but you'd need the function F trick: http://jsfiddle.net/p9pvQ/.
var clazz = null,
pros = Object.prototype; // root of chain
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (typeof arg === "function") {
arg = arg.prototype;
} else {
if(arg.init) {
clazz = arg.init;
delete arg.init;
}
var o = arg;
arg = (function() { function F() {}; F.prototype = pros; return new F; })();
for(var key in o) arg[key] = o[key];
}
pros = arg;
}
m will then have the prototype chain as follows:
Class.init // m
gender: "man"
name: "kk"
__proto__: F // Man
__proto__: F // Person
say: function (){
__proto__: Object // Object.prototype
__defineGetter__: function __defineGetter__() { [native code] }
__defineSetter__: function __defineSetter__() { [native code] }
... (Object.prototype functions)