人们总是被告知“类只是原型的语法糖。”
但是在此示例中,这表明事实并非如此。
function SubArray() {}
SubArray.prototype = new Array( );
console.log(Array.isArray(new SubArray())) // false
和带有类的相同示例。
SubArray = class extends Array{}
console.log(Array.isArray(new SubArray())) // true
有趣的是,instanceof
在new SubArray instanceof Array
上都可以正常工作。
为什么Array.isArray
不在这里返回true
和原型?
答案 0 :(得分:6)
那是因为您没有写出class
实际上是以下内容的语法糖的代码:
function SubArray () {
if (!(new.target)) {
throw new TypeError("Class constructor SubArray cannot be invoked without 'new'")
}
return Reflect.construct(Array, arguments, new.target)
}
Object.setPrototypeOf(SubArray.prototype, Array.prototype)
Object.setPrototypeOf(SubArray, Array)
console.log(Array.isArray(new SubArray())) // true
上面的行为应与您使用class
语法提供的示例相同。不幸的是,如果没有其他new.target
和Reflect.construct()
之类的ES6构造,并非所有这些行为都可以准确地重现,但是为了产生所需的行为,至少不是必需的:
function SubArray () {
if (!(this instanceof SubArray)) {
throw new TypeError("Class constructor SubArray cannot be invoked without 'new'")
}
return Array.apply(this, arguments)
}
SubArray.prototype = Object.create(Array.prototype)
// the line below is not necessary for Array.isArray()
// but accurately reproduces behavior of `class SubArray extends Array {}`
SubArray.__proto__ = Array // implementation hack if Object.setPrototypeOf() is not available
console.log(Array.isArray(new SubArray())) // true
这里的关键是将实例化对象的构造委托给Array
构造函数,以便将该对象初始化为Array外来对象。因此,假设,严格所必需的全部内容如下:
function SubArray () {
return Array.call(this)
}
console.log(Array.isArray(new SubArray())) // true
但是,当然,在这种情况下,您将无法访问Array.prototype
方法,因此如果您必须支持ES5,则应坚持使用class
语法或第二个示例。
我做了一些修改,我个人认为这是一个可怕的主意,但是如果您想在ES5中尽可能模拟class
,则可以选择退出strict mode
以便进行访问到arguments.caller
:
// DON'T ACTUALLY DO THIS
// just for demonstration purposes
function SubArray () {
// this is about as close as you can get to new.target in ES5
if (!(this instanceof SubArray) && !(arguments.caller && this instanceof arguments.caller)) {
throw new TypeError("Class constructor SubArray cannot be invoked without 'new'")
}
return Array.apply(this, arguments)
}
SubArray.prototype.__proto__ = Array.prototype
SubArray.__proto__ = Array
// we want FooBar to extend SubArray sloppily
function FooBar () {
if (!(this instanceof SubArray) && !(arguments.caller && this instanceof arguments.caller)) {
throw new TypeError("Class constructor FooBar cannot be invoked without 'new'")
}
return SubArray.apply(this, arguments)
}
FooBar.prototype.__proto__ = SubArray.prototype
FooBar.__proto__ = SubArray
try {
SubArray()
} catch (e) {
console.log(e.toString())
}
console.log(new SubArray(1, 2, 3))
try {
FooBar()
} catch (e) {
console.log(e.toString())
}
console.log(new FooBar(1, 2, 3))
答案 1 :(得分:0)
请考虑执行Array.isArray()
的步骤:
IsArray(参数)
抽象操作IsArray接受一个实参,然后 执行以下步骤:
If Type(argument) is not Object, return false. If argument is an Array exotic object, return true. If argument is a Proxy exotic object, then If the value of the [[ProxyHandler]] internal slot of argument is null, throw a TypeError exception. Let target be the value of the [[ProxyTarget]] internal slot of argument. Return IsArray(target). Return false.
您的示例在以下步骤失败:“如果参数是Array奇异对象,则返回true。”因为它没有 own length属性。
function SubArray() {}
SubArray.prototype = new Array( );
console.log(Array.isArray(new SubArray())) // false
const sa = new SubArray();
console.log(typeof sa); // object
console.log(Object.getOwnPropertyDescriptor(sa, "length")); // undefined
答案 2 :(得分:0)
由于在聊天中使用rlemon,您可以执行与Patrick在Reflect中所做的相似的操作,并且理论上应该具有IE11支持。
function Foo() {
const arr = new Array(...arguments);
arr.__proto__ = Foo.prototype;
return arr;
}
Foo.prototype.constructor = Foo;
Foo.prototype.__proto__ = Array.prototype;
Array.isArray( new Foo(123) )
答案 3 :(得分:0)
此方法利用iframe,并且如果您选择使用类扩展功能,则可以扩展该类。
var iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
frames[frames.length - 1].document.write(
"<script>parent.SubArray = Array;<\/script>"
);
SubArray.prototype.__proto__ = Array.prototype;
SubArray.__proto__ = Array;
console.log(Array.isArray(new SubArray()));
console.log(new SubArray() instanceof Array);
console.log(new SubArray() instanceof SubArray);
SubArray2 = class extends SubArray {}
console.log(new SubArray2() instanceof SubArray)
答案 4 :(得分:-2)
ES5的处事方式不允许您从15
正确继承。 ES6使它正常工作。