TL;博士:
Q1:它是通过嵌套函数调用的,它本身是由new fNewConstr()
调用调用的。它只是允许将参数列表作为数组传递,而无需修改函数实际使用其参数的方式。
Q2:原型上的任何东西都可以被该构造函数的所有实例访问(并且Function
是 JavaScript 中所有本机函数的构造函数),但是 MyConstructor 本身不是对象实例,这就是为什么它需要在Function.prototype
.
我将我的答案分为两部分,问题 1 和问题 2:
问题 1
Function.prototype.construct 旨在允许传递一个数组作为参数列表,而不使用Function.prototype.bind
. 它在嵌套函数中调用原始函数,并将传递的参数作为数组调用,并将原型设置为原始函数的原型。
在给出的代码中,Function.prototype.construct
方法的作用如下
Function.prototype.construct = function (aArgs) {
var fConstructor = this,
第一行允许我们访问被调用的函数——在那个范围内this
(规范中的ThisBinding)的值就是我们想要调用的函数。
fNewConstr = function () { fConstructor.apply(this, aArgs); };
下一行将使用 调用原始函数Function.prototype.apply
,这允许该函数的参数作为数组传递。之所以this
作为ThisBindingthis
传递,是为了将go 的属性分配给被调用函数的ThisBinding,在这种情况下,它将是由“new”运算符创建的新对象。
fNewConstr.prototype = fConstructor.prototype;
这只是使“new”运算符创建的返回对象的原型与调用函数相同,因为“new”运算符是在新的构造函数上调用的,而不是原来的。
return new fNewConstr();
这几乎是不言自明的——它使用构造函数在属性上创建的关联值创建一个新对象,this
或者返回函数返回的对象(如果有的话)。
返回的内容与new MyConstructor()
直接调用的内容相同,除了参数的给出方式(就像Function.prototype.call()
两者Function.prototype.apply()
的存在方式一样)。例如,这两个代码示例是等价的:
new MyConstructor(4, "Hello world!", false); // { property0: 4, property1: 'Hello world!', property2: false }
MyConstructor.construct([4, "Hello world!", false]); // { property0: 4, property1: 'Hello world!', property2: false }
...就像这些是等效的:
function foo(a, b, c, d, e) { return a + b + c + d + e; }
foo.call(null, 1, 2, 3, 4, 5); // 15
foo.apply(null, [1, 2, 3, 4, 5]); // 15
这是两者之间的唯一区别 - 一个只是使用参数列表调用构造函数,另一个将参数列表表示为数组(构造函数本身仍然将参数作为列表而不是数组获取)。
问题2
函数的所有实例都从原型中借用Function
,因此定义的任何方法(或就此而言,属性)Function.prototype
将可用于所有函数。举个例子:
function foo() { return 1 + 1; }
Function.prototype.bar = function ()
{ var result = this();
if (typeof result === 'number' && isFinite(result)) return result + 0.5;
return NaN;
};
foo.bar(); // 2.5
但是,当你在 上声明一个方法时MyConstructor.prototype
,它只对 的实例可用,而MyConstructor
不是MyConstructor
它本身,如下所示:
function MyConstructor(num) { this.x = 1 + num; }
MyConstructor.prototype.bar = function () { return 2 + 2; };
MyConstructor.bar(); // TypeError: MyConstructor.bar is not a function
MyConstructor.x; // undefined
看看这怎么行不通?您需要在以下实例上使用它MyConstructor
:
var foo = new MyConstructor(4);
foo.x; // 5
foo.bar(); // 4
如果它在原型上,对原型的任何编辑都会影响对象上的所有原型方法/值:
function MyConstructor(num) { this.x = 1 + num; }
MyConstructor.prototype.bar = function () { return 2 + 2; };
var foo1 = new MyConstructor(6);
foo1.bar(); // 4
MyConstructor.prototype.bar = function () { return 3 + 3; };
var foo2 = new MyConstructor(9);
foo2.bar(); // 6
foo1.bar(); // 6
请记住,如果您完全创建一个新的原型对象,则在更改之前创建的实例仍将引用旧对象:
var foo1 = new MyConstructor(6);
foo1.bar(); // 4
MyConstructor.prototype = { bar: function () { return 3 + 3; } };
var foo2 = new MyConstructor(9);
foo2.bar(); // 6
foo1.bar(); // 4?!
请记住,虽然直接声明的属性MyConstructor
不会传递给实例:
MyConstructor.bar2 = function () { return 42; }; // the answer to everything?
MyConstructor.y = 3.141592653589793238462643383279502881197169399; // I only can remember that much
MyConstructor.bar2(); // 42, as you'd expect
var foo = new MyConstructor(99);
foo.bar2(); // TypeError: foo.bar2 is not defined
foo.y; // undefined
基于原型的编程可能非常强大(实际上我更喜欢它而不是类,但这是另一回事),但您需要了解它的作用。如果使用得当,你可以用它做很多很棒的事情——不断学习!:)