gpt4 book ai didi

javascript - 简单的 “Class” 实例化

转载 作者:可可西里 更新时间:2023-11-01 02:31:13 26 4
gpt4 key购买 nike

From John Resig blog :

// makeClass - By John Resig (MIT Licensed)
function makeClass(){
return function(args){
if ( this instanceof arguments.callee ) {
if ( typeof this.init == "function" )
this.init.apply( this, args.callee ? args : arguments );
} else
return new arguments.callee( arguments );
};
}

特别是这条线 this.init.apply( this, args.callee ? args : arguments ); args有什么区别和 arguments ?可以 args.callee曾经 false ?

最佳答案

你写道现有的答案没有足够的细节,但即使在阅读了你的具体问题之后,我也不能完全确定代码的哪些方面让你陷入循环——它有许多棘手的部分——所以我如果这个答案在你已经理解的事情上做得太过分了,请提前道歉!

makeClass总是意味着以相同的方式调用,如果我们删除一层间接,它会更容易推理。这个:

var MyClass = makeClass();

相当于:
function MyClass(args)
{
if ( this instanceof arguments.callee )
{
if ( typeof this.init == "function" )
this.init.apply( this, args.callee ? args : arguments );
}
else
return new arguments.callee( arguments );
}

由于我们不再处理匿名函数,我们不再需要 arguments.callee符号:它必然是指 MyClass ,所以我们可以用 MyClass 替换它的所有实例,给这个:
function MyClass(args)
{
if ( this instanceof MyClass )
{
if ( typeof this.init == "function" )
this.init.apply( this, args.callee ? args : arguments );
}
else
return new MyClass( arguments );
}

哪里 argsMyClass 的标识符的第一个参数,和 arguments和往常一样,是一个类似数组的对象,包含所有 MyClass的论点。

仅当“类”具有名为 init 的函数时,才会到达您要询问的行。在它的原型(prototype)(这将是“构造函数”)中,让我们给它一个:
MyClass.prototype.init =
function (prop)
{
this.prop = prop;
};

一旦我们这样做了,请考虑:
var myInstance1 = new MyClass('value');

内部调用 MyClass , this将引用正在构造的对象,因此 this instanceof MyClass会是真的。和 typeof this.init == "function"会是真的,因为我们做了 MyClass.prototype.init成为一个函数。所以我们到达了这一行:
this.init.apply( this, args.callee ? args : arguments );

这里 args等于 'value' (第一个参数),所以它是一个字符串,所以它没有 callee属性(property);所以 args.callee未定义,这在 bool 上下文中意味着它是假的,所以 args.callee ? args : arguments相当于 arguments .因此,上面的行等效于:
this.init.apply(this, arguments);

这相当于:
this.init('value');

(如果您还不知道 apply 如何工作,以及它与 call 有何不同,请参阅 https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply )。

到目前为止,这有意义吗?

要考虑的另一种情况是:
var myInstance2 = MyClass('value');

内部调用 MyClass , this将引用全局对象(通常是 window ),所以 this instanceof MyClass将是假的,所以我们到达这一行:
return new MyClass( arguments );

哪里 arguments是一个包含单个元素的类数组对象: 'value' .请注意,这与 new MyClass('value') 不同.

术语说明:因此调用 MyClass('value')导致第二次拨打 MyClass ,这次是 new .我将第一个调用(没有 new )称为“外部调用”,第二个调用(使用 new )称为“内部调用”。希望这是直观的。

内部调用 MyClass , args现在指的是外部调用的 arguments对象:而不是 args正在 'value' ,它现在是一个类似数组的对象,包含 'value' .而不是 args.callee未定义,它现在指的是 MyClass ,所以 args.callee ? args : arguments相当于 args .所以内部调用 MyClass正在拨打 this.init.apply(this, args) ,相当于 this.init('value') .

所以在 args.callee上的测试旨在区分内部调用( MyClass('value')new MyClass(arguments) )和正常的直接调用( new MyClass('value') )。理想情况下,我们可以通过替换以下行来消除该测试:
return new MyClass( arguments );

有一些看起来像这样的假设:
return new MyClass.apply( itself, arguments );

但是 JavaScript 不允许这种表示法(也不允许任何等效的表示法)。

顺便说一下,你可以看到 Resig 的代码有一些小问题:
  • 如果我们定义一个构造函数 MyClass.prototype.init ,然后我们通过写 var myInstance3 = new MyClass(); 实例化“类” ,然后 args将在对 MyClass 的调用中未定义,所以测试 args.callee会引发错误。我认为这只是 Resig 的一个错误;无论如何,它很容易通过在 args && args.callee 上测试来修复。反而。
  • 如果我们的构造函数的第一个参数恰好有一个名为 callee 的属性,然后在 args.callee 上进行测试将产生误报,错误的参数将被传递到构造函数中。这意味着,例如,我们不能将构造函数设计为采用 arguments object 作为它的第一个参数。但是这个问题似乎很难解决,而且可能不值得担心。
  • 关于javascript - 简单的 “Class” 实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7892884/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com