Call ES5 class method from static method

2020-05-24 08:20发布

I want to call an inner function from a static function that was called without an instance, like so:

Foo.Bar = function (options) {

    Autodesk.Viewing.Extension.call(this, options);

    ...

    this.innerFunc = function innerFunc(){
      ...
    }
};

Foo.Bar.prototype.constructor =
    Foo.Bar;

Foo.Bar.SomeStaticFunc = function () {
    innerFunc();
}

Use: Foo.Bar.SomeStaticFunc();.

But I get SomeStaticFunc is not a function.

The example here uses a variable for the class, like var Foo.Bar = function (options) {... but isn't that the same as making an instance of the class like so and calling an inner function?

let x= new Foo.Bar(options);
x.innerFunc();

Is there another way to do this?

PS: I know about ES6 classes but I prefer not to migrate this class to ES6 for now because it isn't totally straight forward.

1条回答
相关推荐>>
2楼-- · 2020-05-24 08:51

Well... It seems that you do not know how JavaScript works internally, so here is a quick recap. :)

  • JavaScript IS an object-oriented language. Object literals are objects, arrays are objects, functions are objects, etc.

  • JavaScript IS NOT a class-based language. You could say: "Hey, I've seen class and extends keywords in ES6!". Yes, but this is just syntactic sugar. JavaScript is not based on classes like Java, it is based on prototypes.

With ES5 syntax, there are two ways to create what you call a "class":

  • An object literal
  • A constructor function

When you use an object literal, your class looks like this:

var myClass = {
  myAttribute: "foo",
  myMethod: function () {
    return "bar";
  }
};

When you use a constructor function, your class looks like this:

function MyClass() {
  this.myAttribute = "foo";
  this.myMethod = function () {
    return "bar";
  };
}

There are of course differences between these two approaches. With the object literal, you have a sort of Singleton where properties are all static to some extent. With the constructor function, you can produce instances whose properties will be introduced by the this keyword. Example:

var myInstance = new MyClass();
console.log(myInstance);

This instance will have "myAttribute" and "myMethod" in its own properties. This means that these properties are tied to the instance. If you want to call this method, you must do this:

myInstance.myMethod();

So far so good... But there is something wrong with what we did previously. this.myMethod will be created again and again for each instance of MyClass and it is always the same. A better way to handle this is to put it in the prototype so that it can be shared by all instances:

function MyClass() {
  this.myAttribute = "foo";
}

MyClass.prototype.myMethod = function () {
  return "bar";
};

This is much better, but myMethod is still tied to MyClass instances...

Now I want to create a static method. By definition, our static method will be tied to the class, not to its instances:

MyClass.myStaticMethod = function () {
  return "baz";
};

Nice. Here, for the sake of experimentation, I want to do something like this:

MyClass.myStaticMethod = function () {
  myMethod();
};

This does not work. Why? In fact, myMethod does not exist in the given scope nor in the outer scope. myMethod has been declared inside another function (the constructor function) and it is not returned, so it is invisible from the outside. Moreover, this function has been put in the prototype of MyClass. This means that it is not available globally, but only on instances of MyClass. When you think about it, it is pretty logical. For instance, when you want to call array methods (methods in Array.prototype), it does not make sense to do that:

push('test');
reverse();
includes('a');

You must call these methods on an array (instance of Array).

[].push('test');
['foo', 'bar', 'baz'].reverse();
['a', 'b'].includes('a');
查看更多
登录 后发表回答