javascript - Javascript 中的原型(prototype)继承 使用基本但不复杂的程序

标签 javascript oop inheritance

令人困惑的是这个简单的脚本如何正常工作:

function A() {
    this.value = 0;
}
A.prototype.foo = function() {
    console.log(this.value);
};

function B() {
    this.value = 1;
    this.foo();
}
B.prototype = Object.create(A.prototype);
B.prototype.bar = function() {
    console.log(this instanceof A);
}
new B().bar();
// outputs 1, true

但是,这个较大的脚本会出现错误 this.loadDimensions 不是函数: 基本上,有一个 Player 类,它继承自 MovingComponent 类,而 MovingComponent 类又继承于 VisibleComponent 类。它们都有附加的方法。

  const PX_SZ = 4, MAX_HEIGHT = 100, MIN_HEIGHT = 300;
  var resources = {};
  resources.sprites = {};
  resources.sprites.player = new Image();
  resources.sprites.player.src = "resources/sprites/player.png";
  resources.sprites['default'] = new Image();
  resources.sprites['default'].src = "resources/sprites/default.png";
  resources.sprites.items = {};
  resources.sprites.backgroundEntities = {};
  var itemsTemp = ['default', 'coin0'];
  for (var i=0; i<itemsTemp.length; i++) {
      var item = itemsTemp[i];
      resources.sprites.items[item] = new Image();
      resources.sprites.items[item].src = "resources/sprites/items/" + item + ".png";
  }
  var backgroundEntitiesTemp = ['tree0'];
  for (var i=0; i<backgroundEntitiesTemp.length; i++) {
      var ent = backgroundEntitiesTemp[i];
      resources.sprites.backgroundEntities[ent] = new Image();
      resources.sprites.backgroundEntities[ent].src = "resources/sprites/background-entities/" + ent + ".png";
  }

  var canvas, ctx;
  var player = new Player();
  var keys = {};
  var game = new Game(Math.floor(Math.random()*1000000));
  var world = new World();

  /** @class */
  function Game(seed) {
     this.seed = seed;
  }
  /** @class */
  function World() {
     this.gravity = 0.4;
     this.chances = {
         items: {
             coin0: 0.005
         },
         backgroundEntities: {
             tree0: 0.05
         }
     };
     this.itemsFloating = [];
     this.backgroundEntities = [];
     // for spawning
     this.exploredRightBound = 0;
     this.exploredLeftBound = 0;
  }
  World.prototype.generate = function(left, right) {
       if (left >= right) throw "left >= right in World#generate(left,right)";
       for (x = left; x < right; x += PX_SZ) {
           // world generation code here
           // coin0
           var level = getGroundHeightAt(x)
           if (Math.random() <= this.chances.items.coin0) {
              var item = new ItemFloating("coin0", x, level-20);
              this.itemsFloating.push(item);
           }
           if (Math.random() <= this.chances.backgroundEntities.tree0) {
              var ent = new BackgroundEntity("tree0", x, level-resources.sprites.backgroundEntities.tree0.height);
              this.backgroundEntities.push(ent);
           }
       }
 };
  /**
   *    @class
   *    anything that has a sprite attached to it
   */
  function VisibleComponent() {
     this.sprite = resources.sprites['default'];
  }
  VisibleComponent.prototype.loadDimensions = function() {
      console.log('load');
  };
  VisibleComponent.prototype.draw = function() {
     ctx.drawImage(this.sprite, this.x, this.y, this.width, this.height);
  };

  /** @class */
  function Item(name="default") {
   VisibleComponent.call(this);
     this.name = name || "default";
     this.sprite = resources.sprites.items[name];
     this.loadDimensions();
  }
  Item.prototype = Object.create(VisibleComponent.prototype);
  /** @class */
  function ItemFloating(name, x, y) {
   Item.call(this, name);
   this.name = name;
     this.x = x;
     this.y = y;
     this.loadDimensions(); // (when ready of now)
  }
  ItemFloating.prototype = Object.create(Item.prototype);
  /** @class */
  function BackgroundEntity(name="default", x=0, y=0) {
   VisibleComponent.call(this);
     this.name = name;
     this.x = x;
     this.y = y;
     this.width = 1;
     this.height = 1;
     this.sprite = resources.sprites.backgroundEntities[this.name];
     this.loadDimensions();
  }
  BackgroundEntity.prototype = Object.create(VisibleComponent.prototype);
  /** @class */
  function MovingEntity(x=0, y=0) {
   VisibleComponent.call(this);
     this.x = x;
     this.y = y;
     this.width = 1;
     this.height = 1;
  }
  MovingEntity.prototype = Object.create(VisibleComponent.prototype);
  MovingEntity.prototype.collisionWith = function(ent) {
     return ((this.x>=ent.x&&this.x<=ent.x+ent.width) || (ent.x>=this.x&&ent.x<=this.x+this.width))
        &&  ((this.y>=ent.y&&this.y<=ent.y+ent.height) || (ent.y>=this.y&&ent.y<=this.y+this.height));
  };
  /** @class */
  function Player() {
   MovingEntity.call(this);
   this.inventory = {};
   console.log(this instanceof VisibleComponent);
   this.speed = 4;
   this.jumpSpeed = 8;
   this.vspeed = 0;
   this.sprite = resources.sprites.player;
     this.loadDimensions();
     this.direction = "right";
  }
  Player.prototype = Object.create(MovingEntity.prototype);
  Player.prototype.draw = function() {
     ctx.save();
     ctx.translate(this.x, this.y);
     if (this.direction == "left") ctx.scale(-1, 1);    // flip over y-axis
     ctx.translate(-this.sprite.width, 0);
     ctx.drawImage(this.sprite, 0, 0, this.width, this.height);
     ctx.restore();
  }
  Player.prototype.move = function() {
     if (keys['ArrowLeft']) {
        this.x -= this.speed;
        this.direction = "left";
        var leftEdge = this.x-canvas.width/2-this.width/2;
        if (leftEdge < world.exploredLeftBound) {
           world.generate(leftEdge, world.exploredLeftBound);
           world.exploredLeftBound = leftEdge;
        }
     }
     if (keys['ArrowRight']) {
        this.x += this.speed;
        this.direction = "right";
        var rightEdge = this.x+canvas.width/2+this.width/2;
        if (rightEdge > world.exploredRightBound) {
            world.generate(world.exploredRightBound, rightEdge);
            world.exploredRightBound = rightEdge;
        }
     }

     var level = getGroundHeightAt(this.x+this.width/2);

     if (this.y + this.height < level) {
        this.vspeed -= world.gravity;
     } else if (this.y + this.height > level) {
        this.y = level - this.height;
        this.vspeed = 0;
     }
     if (keys[' '] && this.y+this.height == getGroundHeightAt(this.x+this.width/2)) this.vspeed += this.jumpSpeed;

     this.y -= this.vspeed;
     for (var i=0; i<world.itemsFloating.length; i++) {
        var item = world.itemsFloating[i];
        if (this.collisionWith(item)) {
            if (this.inventory.hasOwnProperty(item.name)) this.inventory[item.name]++;
            else this.inventory[item.name] = 1;
            world.itemsFloating.splice(i, 1);
        }
     }
 };

我对 javascript 继承相当陌生,所以我不明白我做错了什么。另外,由于第一个脚本有效,我认为我在第二个脚本中忽略了一些东西。任何帮助将不胜感激。

编辑 在文件的开头,我将 player 声明为 new Player()resources 包含指向各种图像文件的 Image 实例。 ctxcanvas 是非常不言自明的全局变量。

此外,player 不会被识别为 MovingEntityVisibleComponent 的实例,即使 Player' s prototype 设置为 Object.create(MovingEntity.prototype),其 prototype 设置为 Object.create(VisibleComponent.原型(prototype))

另一件事要提到的是,在 VisibleComponentloadDimensions() 的定义中,this 的 onload 属性.sprite 设置为函数,或为 'load' 调用 addEventListener(),具体取决于 this.sprite已加载(width != 0)或未加载。

最佳答案

In the beginning of the file, I declare player as a new Player().

这就是问题所在,您需要在设置类之后调用构造函数。目前,它不会抛出有关 Player 不是函数的错误,因为声明已提升,但原型(prototype)尚未使用您期望的值进行初始化,因此它确实没有 。 loadDimensions() 方法尚未实现。

关于javascript - Javascript 中的原型(prototype)继承 使用基本但不复杂的程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44660172/

相关文章:

javascript - 未捕获的类型错误 : Cannot read properties of null (reading 'style' )

oop - 如何获取 MATLAB 句柄对象的 ID?

java - 如何检查数组是否已满,如果未满则添加到它?

c++ - 接口(interface)实现与私有(private)继承的交互

c++ - 虚运算符重载 C++

javascript - 自动将所有文件下载到计算机上用户首选的位置

javascript - 无法让日期选择器与 Best in place rails 4 一起使用

javascript - 如何从中心开始设置 div 的动画

Python设计题

c++ - 虚函数题