我想设置存储在具有特定名称的数组中的 JavaScript 伪类的名称,例如,非数组版本可以完美运行:
var Working = new Array();
Working = new Function('arg', 'this.Arg = arg;');
Working.prototype.constructor = Working;
var instw = new Working('test');
document.write(instw.Arg);
document.write('<BR />');
document.write((instw instanceof Working).toString());
输出:
test
true
但是这种格式不起作用:
// desired name of pseudoclass
var oname = 'Obj';
var objs = new Array();
objs.push(new Function('arg', 'this.Arg = arg;'));
// set objs[0] name - DOESN'T WORK
objs[0].prototype.constructor = oname;
// create new instance of objs[0] - works
var inst = new objs[0]('test');
document.write(inst.Arg);
document.write('<BR />Redundant: ');
// check inst name - this one doesn't need to work
try { document.write((inst instanceof objs[0]).toString()); } catch (ex) { document.write('false'); }
document.write('<BR />Required: ');
// check inst name - this is the desired use of instanceof
try { document.write((inst instanceof Obj).toString()); } catch (ex) { document.write('false'); }
输出:
test
Redundant: true
Required: false
Link to JSFiddle .
最佳答案
就 JS 的流畅性而言,这里发生了一些事情有点不协调(没关系,一旦我离开 4.0 的基本语言特性,我的 C# 就已经很陈旧了)。
首先,我可以建议避免document.write
吗?不惜一切代价?
这有技术原因,现在浏览器都在努力规避它们,但它仍然和放置 alert()
一样糟糕。无处不在(包括迭代)。
我们都知道 Windows 系统消息弹出窗口有多烦人。
如果您使用的是 Chrome,请点击 CTRL+Shift+J
你会得到一个方便的控制台,你可以console.log()
结果进入(甚至对象/数组/函数),它将返回数据集/DOM对象的可遍历节点和其他类型(如函数)的字符串。
当今 JS 的最佳特性之一是您的 IDE 位于浏览器中。
从头开始编写和保存 .js 文件在控制台中并不是特别简单,但测试/调试再简单不过了。
现在,进入真正的问题。
看看你在用示例 #1 做什么。.prototype.constructor
的改写应该完全没有必要,除非那里有一些边缘案例浏览器/引擎。
在用作构造函数的任何函数内部(即:使用 new
调用),该函数基本上是在创建一个新对象 {}
, 分配给 this
, 设置 this.__proto__ = arguments.callee.prototype
, 并设置 this.__proto__.constructor = arguments.callee
, 其中 arguments.callee === function
.
var Working = function () {};
var working = new Working();
console.log(working instanceof Working); // [log:] true
Working
不是字符串:你已经把它变成了一个函数。实际上,在 JS 中,它也是
window
的属性。 (即在浏览器中)。window.Working === Working; // true
window["Working"] === Working; // true
最后一个确实是解决示例 #2 中的困境的关键。
不过,在查看 #2 之前,请注意:
如果你正在做大量的伪子类化,
var Shape = function () {
this.get_area = function () { };
},
Square = function (w) {
this.w = w;
Shape.call(this);
};
如果你想要你的
instanceof
要同时使用 Square 和 Shape,那么您必须开始使用原型(prototype)和/或构造函数,具体取决于您想要继承什么以及如何继承。var Shape = function () {};
Shape.prototype.getArea = function () { return this.length * this.width; };
var Square = function (l) { this.length = l; this.width = l; };
Square.prototype = new Shape();
var Circle = function (r) { this.radius = r; };
Circle.prototype = new Shape();
Circle.prototype.getArea = function () { return 2 * Math.PI * this.radius; };
var circle = new Circle(4),
square = new Square(4);
circle instanceof Shape; // true
square instanceof Shape; // true
这仅仅是因为我们将原型(prototype)对象(被每个实例重用)设置为父类的全新实例。我们甚至可以在所有子类之间共享该单一实例。
var shape = new Shape();
Circle.prototype = shape;
Square.prototype = shape;
...只是不要覆盖
.getArea
,因为原型(prototype)继承就像继承公共(public)静态方法。形状当然有
shape.__proto__.constructor === Shape
, 和 square.__proto__.constructor === Square
差不多.做一个instanceof
只是通过 __proto__
向上递归链接,检查函数是否与给定的匹配。如果您以上面列出的方式构建函数(
Circle.prototype = new Shape(); Circle.prototype.getArea = function () { /* overriding Shape().getArea() */};
,那么 circle instanceof Circle && circle instanceof Shape
将自行处理。混合继承或伪构造函数(返回不是
this
等的对象)需要 constructor
mangling,让这些检查工作。...无论如何...关于#2:
了解以上所有内容,这应该很快就能解决。
您正在为所需的函数名称创建字符串,而不是创建函数本身,并且没有
Obj
变量定义,所以你得到一个“引用错误”:相反,让你的“期望名称”成为一个对象的属性。var classes = {},
class_name = "Circle",
constructors = [];
classes[class_name] = function (r) { this.radius = r; };
constructors.push(classes.Circle);
var circle = new constructors[0](8);
circle instanceof classes.Circle;
现在一切都很好地定义了,你不会覆盖任何你不需要覆盖的东西,你仍然可以继承和覆盖
.prototype
的成员, 你仍然可以做 instanceof
以程序方式(分配 data.name
作为对象的属性,并将其值设置为 new Function(data.args, data.constructor)
,并使用该对象属性进行查找)。希望任何/所有这些都有帮助。
关于javascript - 如何在 JavaScript 中设置动态生成的伪类名称以与 instanceof 运算符一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14914698/