【问题标题】:JavaScript: Changing default functions using subclass?JavaScript:使用子类更改默认函数?
【发布时间】:2018-05-16 23:44:03
【问题描述】:

我正在尝试使用 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

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

任何帮助将不胜感激!

【问题讨论】:

    标签: javascript inheritance subclass


    【解决方案1】:

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

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

    我的方法最重要的一点是,我喜欢我使用的任何解决方案来获得干净的代码,这是我在 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();

    【讨论】:

      【解决方案2】:

      你可以直接用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

      【讨论】:

      • 谢谢,这就是我最初所做的,但是这种方法的问题是我不知道在切换到另一个级别时如何重置所有更改。例如,如果我更改了 game.func 以及一堆其他函数,我如何在加载另一个关卡时将它们全部更改回默认值?新的关卡不一定会改变一切,所以我想保留默认值。
      【解决方案3】:

      If you don't have to support IE 11 或愿意转译,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 很自然的基于原型的继承。

      【讨论】:

      • 谢谢。我很想使用类,但我真的在寻找一种方法来做到这一点,如果可能的话。它不必使用对象,我只需要某种方式来默认为另一个函数。
      猜你喜欢
      • 2017-05-28
      • 2017-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 1970-01-01
      相关资源
      最近更新 更多