2

我想设置存储在具有特定名称的数组中的 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

链接到 JSFiddle

4

1 回答 1

2

就 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,那么您必须开始使用原型和/或构造函数,具体取决于您想要继承什么以及如何继承。

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

这仅仅是因为我们将原型对象(被每个实例重用)设置为父类的全新实例。我们甚至可以在所有子类之间共享该单一实例。

var shape = new Shape();
Circle.prototype = shape;
Square.prototype = shape;

...只是不要覆盖.getArea,因为原型继承就像继承公共静态方法。

形状,当然,有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修改,以使这些检查工作。

...无论如何...关于#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和覆盖其值为,并使用该对象属性进行查找)。instanceofdata.namenew Function(data.args, data.constructor)

希望任何/所有这些都有帮助。

于 2013-02-18T07:21:40.140 回答