// 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 );
};
}
Run Code Online (Sandbox Code Playgroud)
尤其是这条线 this.init.apply( this, args.callee ? args : arguments );
args和之间有什么区别arguments?能args.callee永远false?
rua*_*akh 22
你写的是现有的答案没有足够的细节,但即使在阅读了你的具体问题之后,我也不能完全确定代码的哪些方面会让你陷入循环 - 它有许多棘手的部分 - 所以我如果这个答案过于详细了解你已经理解的事情,请提前道歉!
因为makeClass总是意味着以相同的方式调用,所以如果我们删除一个级别的间接,则更容易推理它.这个:
var MyClass = makeClass();
Run Code Online (Sandbox Code Playgroud)
相当于:
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 );
}
Run Code Online (Sandbox Code Playgroud)
由于我们不再处理匿名函数,我们不再需要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 );
}
Run Code Online (Sandbox Code Playgroud)
其中args为的标识符MyClass的第一参数,并arguments一如既往地是含有类似阵列的对象的所有的MyClass的论点.
只有当"类"具有init在其原型中命名的函数(它将是"构造函数")时,才会询问您要询问的行,所以让我们给它一个:
MyClass.prototype.init =
function (prop)
{
this.prop = prop;
};
Run Code Online (Sandbox Code Playgroud)
一旦我们完成了,请考虑这个:
var myInstance1 = new MyClass('value');
Run Code Online (Sandbox Code Playgroud)
在调用内部MyClass,this将引用正在构造的对象,因此this instanceof MyClass将是真实的.并且typeof this.init == "function"将是真的,因为我们MyClass.prototype.init成为了一个功能.所以我们达到了这条线:
this.init.apply( this, args.callee ? args : arguments );
Run Code Online (Sandbox Code Playgroud)
这args等于'value'(第一个参数),所以它是一个字符串,所以它没有callee属性; 所以args.callee是未定义的,在布尔上下文中意味着它是假的,所以args.callee ? args : arguments相当于arguments.因此,上述行等同于:
this.init.apply(this, arguments);
Run Code Online (Sandbox Code Playgroud)
这相当于:
this.init('value');
Run Code Online (Sandbox Code Playgroud)
(如果您还不知道apply它是如何工作的,以及它有何不同call,请参阅https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply).
这到目前为止有意义吗?
另一个需要考虑的情况是:
var myInstance2 = MyClass('value');
Run Code Online (Sandbox Code Playgroud)
在调用中MyClass,this将引用全局对象(通常window),因此this instanceof MyClass将为false,因此我们到达此行:
return new MyClass( arguments );
Run Code Online (Sandbox Code Playgroud)
where 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 );
Run Code Online (Sandbox Code Playgroud)
假设看起来像这样:
return new MyClass.apply( itself, arguments );
Run Code Online (Sandbox Code Playgroud)
但JavaScript不允许使用该表示法(也不允许使用任何等效表示法).
顺便说一下,你可以看到Resig代码存在一些小问题:
MyClass.prototype.init,然后我们通过编写实例化"类" var myInstance3 = new MyClass();,那么args在调用内部将是未定义的MyClass,因此测试args.callee将引发错误.我认为这只是Resig的一个错误; 无论如何,它可以通过测试轻松修复args && args.callee.callee,那么测试args.callee将产生一个误报,并且错误的参数将被传递给构造函数.这意味着,例如,我们不能将构造函数设计为将arguments对象作为其第一个参数.但是这个问题似乎难以解决,而且可能不值得担心.| 归档时间: |
|
| 查看次数: |
6848 次 |
| 最近记录: |