高级Javascript:检测构造函数是否正在调用当前函数 [英] Advanced Javascript: Detecting whether current function is being called by a constructor

查看:64
本文介绍了高级Javascript:检测构造函数是否正在调用当前函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Javascript函数中,它是一个相当简单的检测函数是简单执行还是作为对象实例构造函数执行(使用 new 关键字)。

Within a Javascript function it is a rather simple detection whether the function has been simply executed or being executed as an object instance constructor (using new keyword).

// constructor
function SomeType() {
    if (this instanceof SomeType)
        // called as an object instance constructor
    else
        // the usual function call
}

没关系,这个问题已经在这里至少回答了几次。

That's fine, this has been answered here at SO at least a few times before.

所以我们假设我们的构造函数调用了我定义的另一个函数直接在函数原型上,因此所有函数都可以访问 - 这就是为什么我这样做的主要目的。

So let's suppose now that our constructor function calls another function that I defined directly on Function prototype and is therefore accessible to all functions - the main purpose why I'm doing it this way.

Function.prototype.doSomething = function doSomething() {
    // what code here?
};

// constructor
function SomeType() {
    SomeType.doSomething();
}



主要问题



我们现在如何在 doSomething 内检测到相同的 SomeType 函数?

Main problem

How can we now detect within doSomething the same for SomeType function?

我想检测它的原因是我正在编写一个函数采用 / 注入构造函数参数作为构造对象实例成员名称。当然,这个函数只应在构造函数调用时才执行,而不是由定期调用的函数执行。

The reason why I'd like to detect it is I'm writing a function that adopts/injects constructor parameters as constructed object instance members with the same name. Of course this function should only execute when it's being called by a constructor function and not by a function called regularly.

这是我的答案另一个问题,你可以看到我的 adoptArguments 函数,它将对象构造函数参数作为成员放入构造对象实例中。

This is my answer to another question where you can see my adoptArguments function that puts object constructor arguments into constructed object instance as members.

我有一个可能的解决方法,我不想使用,因为它强制执行正确的用法 - 执行上下文注入。这是可以检测对象实例构造函数执行的代码:

I have a possible workaround that I don't want to use, because it enforces correct usage - execution context injection. This is the code that can detect object instance constructor execution:

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);
}

这个想法可能会激发你自己的一些想法来解决原来的问题

This idea may spark some ideas of your own to solve the original problem

推荐答案

一种可能的解决方案是将构造函数上下文作为参数传递。无需传入arguments对象,因为它可以通过 this.arguments 访问,就像你在 adoptArguments 关于你的链接答案。

One possible solution is passing the constructor context as parameter. There is no need to pass in the arguments object as it can be accessed through this.arguments, as you are doing in adoptArguments on your linked answer.


这个解决方案对我有意义,因为我期待 Function.prototype.someMethod 使用 Function 实例的上下文而不是其他上下文
(即新创建的实例)调用

This solution makes sense for me as I expect Function.prototype.someMethod to be called withing the context of a Function instance rather than other context (i.e., the newly created instance).



Function.prototype.doSomethingWith = function doSomethingWith(instance) {
    if( instance instanceof this ) // proceed
};

// constructor
function SomeType() {
    SomeType.doSomethingWith(this);
}

警告:您的 adoptArguments 函数有一个严重的错误,见下文

WARN: your adoptArguments function has a serious bug, see below

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)

这篇关于高级Javascript:检测构造函数是否正在调用当前函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆