JavaScript: 使用子类更改默认函数?

JavaScript: Changing default functions using subclass?

我正在尝试使用 JavaScript 制作一个简单的游戏。我希望游戏中的每个级别都有稍微不同的行为。但是,我还想要一些默认行为,因为并非游戏的每个部分都会更改。

我想我应该尝试使用子类化和继承,也许使用这样的级别基础:

"use strict";

function LevelBase() {
 this.load = function(level) {
  if (level === 1) {
   new Level1(this); // Can't do this = new Level1(this);
  }
 };
 this.func = function() {
  return 123;
 };
}

function Level1(game) {
 this.prototype = game;
 this.func = function() {
  return 456;
 };
}

var game = new LevelBase();
game.load(1);
console.log(game.func()); // Should print 456

但是,这不起作用。它仍然使用默认行为,我觉得这是一种糟糕的方法,会使一切变得过于复杂。有这样的工作方法吗?

非常感谢任何帮助!

你可以直接用game.func = ...重载。

"use strict";

function LevelBase() {
 this.load = function(level) {
  if (level === 1) {
   new Level1(this);
  }
 };
 this.func = function() {
  return 123;
 };
}

function Level1(game) {
 game.func = function() {
  return 456;
 };
}

var game = new LevelBase();
game.load(1);
console.log(game.func()); // Should print 456

If you don't have to support IE 11 或愿意转译,class 是一种实现继承的便捷方式,类似于基于 class 的语言的实现方式:

class LevelBase {
  load() {
    // ...
  }

  func() {
    return 123;
  }
}

class Level1 extends LevelBase {
  func() {
    return 456;
  }
}

const level = new Level1();
console.log(level.func()); // Prints 456

IMO,这是最干净的继承方式,它应该表现良好,因为它转化为基于原型的继承,这对 JavaScript 来说是自然的。

这是一种适用于 IE11 或任何其他 ES5 环境的方法。

它依赖于几个实用函数来定义您的 类,它支持单继承和重载。您可以将函数保存在先加载的较小脚本中,或者将其保存在文件顶部。

我的方法最重要的是我喜欢我使用的任何解决方案都有干净的代码,这就是我在 'proper' 类 在 JS 之前想到的。

/*
 This function attaches a prototype object
 to a constructor function and returns it
 
 It also adds a super & base properties
 which can be used to infer which class an object came from (It's constructor function)
 
 e.g. var obj = new Class();
 
 Or using base on a class to check what it inherits from.
 
 Class.base = Base or Null if it has none
 
 obj.super = class;
*/
function _class(c,p) {
 p.base = null;
 p.super = c;
 c.prototype = p;
 
 return c;
}

/*
 This function takes a base class, constructor function and prototype object
 
 First the properties of the base prototype are iterated through,
 and any that aren't already on our new prototype are copied
 
 This essentially allows us to overload behaviour on the prototype by
 redefining it in decendants.
 
 Next a new constructor function is created that calls the base constructor first
 and then the derrived constructor afterward.
 
 function.apply() is a javascript function that can be applied to function objects
 in essense it's saying "Call this function as if you were a member of the first argument
 (the 'this' variable which would be the new object when the constructor is used) and
 use the same arguments that this outer function was called with".
 
 Another way to explain this is
 
 var obj = new nc(10);
  -> calls into nc with one argument '10'.
   -> That then calls into the base constructor with the same argument and 'this' set to the new object
   -> That then calls into the derrived constructor with the same argument and 'this' set to the new object
*/
_class.extends = function(b,c,p) {
 for (var pr in b.prototype) {
  if (!p[pr]) {
   p[pr] = b.prototype[pr];
  }
 }
 
 function nc() {
  b.apply(this,arguments);
  c.apply(this,arguments);
 }
 
 p.base = b;
 p.super = nc;
 nc.prototype = p;
 
 return nc;
}


var BaseClass = _class(
 // Base Constructor
 function(v1,v2) {
  this.v1 = v1;
  this.v2 = v2;
 },
 
 // Base prototype (Use for constants or class functions)
 {
  printValues: function() {
   console.log(
    this.v1,
    this.v2
   );
  }
 }
);

var DerrivedClass1 = _class.extends(BaseClass,
 function(v1,v2) {
  
 },
 
 {
  // It isn't defined here but this prototype contains the functions from the parent
 }
);

var DerrivedClass2 = _class.extends(BaseClass,
 function(v1,v2) {
  
 },
 
 {
  // This overloads inherited behaviour
  printValues: function() {
   console.log(
    "V1: " + this.v1,
    "V2: " + this.v2
   );
  }
 }
);

var obj_1 = new DerrivedClass1(10,20);
var obj_2 = new DerrivedClass2(30,40);

// This uses inherited behaviour
obj_1.printValues();

// This uses overloaded behaviour
obj_2.printValues();