高级Javascript:检测当前函数是否由构造函数调用
Advanced Javascript: Detecting whether current function is being called by a constructor
在Javascript函数中,这是一个相当简单的检测,该函数是简单地执行还是作为对象实例构造函数执行(使用new
关键字)。
// constructor
function SomeType() {
if (this instanceof SomeType)
// called as an object instance constructor
else
// the usual function call
}
没关系,这在SO之前至少已经回答过几次了。
因此,现在让我们假设我们的构造函数调用我直接在函数原型上定义的另一个函数,因此所有函数都可以访问 - 这是我这样做的主要目的。
Function.prototype.doSomething = function doSomething() {
// what code here?
};
// constructor
function SomeType() {
SomeType.doSomething();
}
主要问题
我们现在如何在doSomething
内检测SomeType
函数的相同情况?
我想检测它的原因是我正在编写一个函数,该函数采用/注入构造函数参数作为具有相同名称的构造对象实例成员。当然,此函数应仅在由构造函数调用时才执行,而不是由定期调用的函数调用。
这是我对另一个问题的回答,您可以在其中看到我的adoptArguments
函数,该函数将对象构造函数参数作为成员放入构造的对象实例中。
强制使用特定用法 = 错误的解决方法
我有一个我不想使用的可能的解决方法,因为它强制执行正确的用法 - 执行上下文注入。以下是可以检测对象实例构造函数执行的代码:
Function.prototype.doSomething = function doSomething() {
if (this instanceof doSomething.caller)
{
// object instance construction
}
else return; // nope, just normal function call
};
// constructor
function SomeType() {
// required use of ".call" or ".apply"
SomeType.doSomething.call(this);
}
这个想法可能会激发你自己的一些想法来解决最初的问题
在 Javascript 函数中,检测函数是简单地执行还是作为对象实例构造函数(使用 new 关键字)执行,这是一个相当简单的检测。
实际上,这是不可能的,在JS中无法知道用户函数是否作为构造函数调用。对于通常的情况,this instanceof
测试就足够了,但只检查上下文是否继承自类的原型。
我们现在如何在
doSomething
内检测到SomeType
函数的相同内容?
出于同样的原因,您不能,并且如果不将this
作为参数传递给doSomething
,则无法进行instanceof
测试。
主要问题:我正在编写一个函数,该函数采用/注入构造函数参数作为具有相同名称的构造对象实例成员。
我建议不要通过构造函数内部的函数调用来执行此操作。相反,请尝试修饰构造函数,以便您可以立即访问所需的所有值:
Function.prototype.adoptArguments = function() {
var init = this;
var args = arguments.length ? arguments : init.toString().replace(comments, "").match(argumentsparser);
if (!args || !args.length) return init;
var constructor = function() {
if (this instanceof constructor) {
for (var i=0; i<args.length; i++)
this[args[i]] = arguments[i];
init.apply(this, arguments);
} else {
// throw new Error("must be invoked with new");
}
};
return constructor;
};
然后代替
function SomeType() {
SomeType.adoptArguments();
}
做
var SomeType = function() {
}.adoptArguments();
一种可能的解决方案是将构造函数上下文作为参数传递。没有必要传入参数对象,因为它可以通过this.arguments
访问,就像您在链接答案adoptArguments
所做的那样。
这个解决方案对我来说很有意义,因为我希望
Function.prototype.someMethod
在Function
实例的上下文中调用,而不是在其他上下文中调用 (即新创建的实例)。
Function.prototype.doSomethingWith = function doSomethingWith(instance) {
if( instance instanceof this ) // proceed
};
// constructor
function SomeType() {
SomeType.doSomethingWith(this);
}
WARN:您的adoptArguments
函数存在严重错误,请参见下文
var comments = /(('/'/.*$)|('/'*['s'S]*?'*'/))/mg;
var parser = /^function[^'(]*'(([^)]*)')/mi;
var splitter = /'s*,'s*/mi;
Function.prototype.adoptArguments = function() {
var args;
// remove code comments
args = this.toString().replace(comments, "");
// parse function string for arguments
args = parser.exec(args)[1];
if (!args) return; // empty => no arguments
// get individual argument names
args = args.split(splitter);
// adopt all as own prototype members
for(var i = 0, len = args.length; i < len; ++i)
{
this.prototype[args[i]] = this.arguments[i];
}
};
console.log('the problem with your implementation:');
console.log('> adopting arguments as prototype members');
console.log('> implies you override values for every instance of YourType');
function YourType(a, b, c) {
YourType.adoptArguments();
}
var foo = new YourType( 1, 2, 3 );
console.log( 'foo', foo.a, foo.b, foo.c ); // foo 1 2 3
var bar = new YourType( 4, 5, 6 );
console.log( 'foo', foo.a, foo.b, foo.c ); // foo 4 5 6
console.log( 'bar', bar.a, bar.b, bar.c ); // bar 4 5 6
console.log();
console.log('also, a trim is need because:');
function OtherType( a, b, c ) { // see where whitespaces are
OtherType.adoptArguments();
}
var baz = new OtherType( 1, 2, 3 );
console.log( 'baz', baz.a, baz.b, baz.c );
// baz undefined 2 undefined
//
// My solution
//
console.log();
console.log('results');
// slighly modified from your adoptArguments function
Function.prototype.injectParamsOn = function injectParamsOn( instance ) {
// you may check `instance` to be instanceof this
if( ! (instance instanceof this) ) return;
// proceed with injection
var args;
// remove code comments
args = this.toString().replace(comments, "");
// parse function string for arguments
args = parser.exec(args)[1];
if (!args) return; // empty => no arguments
// get individual argument names (note the trim)
args = args.trim().split(splitter);
// adopt all as instance members
var n = 0;
while( args.length ) instance[ args.shift() ] = this.arguments[ n++ ];
};
function MyType( a, b, c ){
MyType.injectParamsOn( this );
}
var one = new MyType( 1, 2, 3 );
console.log( 'one', one.a, one.b, one.c ); // one 1 2 3
var two = new MyType( 4, 5, 6 );
console.log( 'one', one.a, one.b, one.c ); // one 1 2 3
console.log( 'two', two.a, two.b, two.c ); // two 4 5 6
var bad = MyType( 7, 8, 8 );
// this will throw as `bad` is undefined
// console.log( 'bad', bad.a, bad.b, bad.c );
console.log( global.a, global.b, global.c );
// all undefined, as expected (the reason for instanceof check)
- 是否可以将一个函数输入连接到另一个函数调用的文本
- 异步函数调用是否可以在两个同步语句之间完成
- 如何验证for循环是否完成了node js中的所有迭代,循环是否包含带回调的函数调用
- 如何在不设置全局变量的情况下确定是否已调用函数
- 是否可以存储javascript函数调用并在设置某些变量时执行它
- 除了对每个元素进行函数调用之外,是否有一种更通用的方法可以在 HTML 元素上调用 JS 函数
- 如果我有一个变量,分配给函数调用的值,如果函数调用的参数更改,是否可以更新该变量
- 高级Javascript:检测当前函数是否由构造函数调用
- 是否可以通过函数调用重绘 DIV 的内容
- 当我为 PHP 变量赋值时,是否可以调用 JavaScript 函数
- 引导表:是否可以调用从代码中按列对行进行排序的函数(无需单击标题)
- 是否可以在Javascript/Coffeescript中的属性访问期间自动调用函数调用
- 检查函数调用是否具有正确的参数类型
- Node sequelize回调承诺期望一个函数,是否有一种方法可以通过函数调用删除已声明的函数
- 如果对函数调用了.bind(),是否无法判断该函数是否为生成器函数
- 当调用返回相同对象的函数时,无论是否作为构造函数调用,我都应该使用“new”吗
- 检查构造函数调用是否来自扩展类
- AngularJs 摘要周期是否在任何函数调用后触发
- 是否有嵌套require函数调用的原因
- 在JavaScript中执行传入的回调函数时,是否可以确定是否可以调用某个函数