我正在MDN上进行Array'a find
polyfill实现:
将其粘贴到下面:
// 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;
}
});
}
为什么我们需要var o = Object(this);
?
Object(this)
取得了什么成果?
感谢您的讨论。
答案 0 :(得分:5)
在严格模式下,原始this
将不强制转换为对象。
因此,使用Object(this)
明确强制对象是必要的。
这是一个更详细的例子:
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));
&#13;
第一个示例成功运行,结果为0,因为参数undefined
被强制转换为非严格模式的对象。第二个示例失败,因为undefined
非在非严格模式下强制执行,因此this.length
出错。
来自MDN:
作为
this
传递给严格模式的函数的值不会被强制成为一个对象(a.k.a。&#34; boxed&#34;)
但是,在这种情况下,已经显式检查null或undefined:
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
所以我很想说明一个对象的显式转换是没有必要的。这可能是出于谨慎使用或作为样板而使用的。
答案 1 :(得分:4)
这是一个引人入胜的问题......感谢你的帖子!
老实说,我对Object(this)
感到有些惊讶,因为在this
可能是原始值的情况下,JavaScript似乎强迫任何对象(使用包装器)。
如果我们尝试使用this
更改Function.prototype.bind()
,JavaScript始终会返回一个对象(函数是一个对象):
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
如果我们尝试使用this
或Function.prototype.call()
更改Function.prototype.apply()
,JavaScript将再次返回一个对象:
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
在JavaScript中,我们知道当本机对象不用作构造函数而是用作常规函数时,它们可能对类型转换很有用。 Number
,String
和Boolean
非常方便:
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));
对于记录,以下是我们通过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);
现在显而易见的是Object(this)
可用于转换this
的任何原始值并改为获取包装器对象。如果this
已经是对象,则无效:
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);
此外,Object
很奇怪,因为它的行为方式相同,无论是否使用new
调用:
var foo = Object('foo'),
bar = new Object('bar');
console.log(foo);
console.log(bar);
我可能错了,但我的结论如下:鉴于this
始终强制对象,Object(this)
不是必需的。但是,它明确地指出了为避免歧义和提高代码理解而隐式发生的事情。
您怎么看?
修改强>
torazaburo是对的:严格模式是关键!当函数处于严格模式时,this
的原始值不会被强制执行!这可能是使用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