Javascript 对象组合与分配 & Object.create

Javascript Object Composition with assign & Object.create

尝试使用 assign 围绕 javascript 构图进行思考。我的基础对象上的 属性 意外地在实例之间共享。我究竟做错了什么?我有...

Stat.js:

import assign from 'object-assign';
var Stat = assign({}, {
    _value: undefined,

    get: function() {
        return this._value;
    },

    set: function(n) { 
        var max = this.getMax();

        if(n > max) {
            this._value = max;
        } else {
            this._value = n; 
        }
    },

    getMax: function() {
        return 1;
    }
});
module.exports = Stat;

HitPoints.js:

import assign from 'object-assign'
import Stat from './Stat.js';

var HitPoints = assign({}, Stat, {        
    getMax: function() {
        return 100;
    }
});
module.exports = HitPoints;

Unit.js:

import assign from 'object-assign';
import HitPoints from 'HitPoints.js';

var Unit = assign({}, {
        hp: Object.create(HitPoints)
    }
);
module.exports = Unit; 

用法:

import Unit from 'Unit.js';

var u1 = Object.create(Unit);
console.log( u1.hp.get() ); // undefined - ok
u1.hp.set(11);
console.log( u1.hp.get() ); // 11 - ok

var u2 = Object.create(Unit);
console.log( u2.hp.get() ); // 11 - ???
u2.hp.set(22);
console.log( u1.hp.get() ); // 22 - ???
console.log( u2.hp.get() ); // 22

感谢您的帮助...

好吧,这有效...

Stat.js:

var Stat = {
    get: function() {
        return this._value;
    },

    set: function(n) { 
        var max = this.getMax();

        if(n > max) {
            this._value = max;
        } else {
            this._value = n; 
        }
    },

    getMax: function() {
        return 1;
    }
}

HitPoints.js:

var HitPoints = function() {
    return assign(Object.create(Stat), {    
        getMax: function() {
            return 100;
        }
    });
}

Unit.js:

var Unit = function() {
    return assign({},
        Object.create(XYPiece),
        Object.create(TeamMember),
        {
             hp: HitPoints()     
        }
    );                       
}

用法:

var u1 = Unit();
console.log( u1.hp.get() ); // undefined
u1.hp.set(11);
console.log( u1.hp.get() ); // 11

var u2 = Unit();
console.log( u2.hp.get() ); // undefined
u2.hp.set(22);
console.log( u1.hp.get() ); // 11
console.log( u2.hp.get() ); // 22

This 文章有帮助。万岁!!!

不过,如果这从根本上说是一种愚蠢的方法,请告诉我...

对于初学者,一个简单的例子说明为什么人们不希望你使用 class
我不一定讨厌 class,但使用 class 的 90% 原因是为了继承,虽然它偶尔有用,但经常会非常痛苦。

class Person { }


class ArmedPerson extends Person {
  constructor (details) {
    super(details);
    const gun = new Gun();
    this.equipment = { gun };
  }

  attack (target) {
    this.equipment.gun.fireAt(target);
  }
}


class Civilian extends Person { }


class ArmedCivilian extends ArmedPerson {
  /* ... shouldn't it be extending Civilian?
    Maybe all Civilians should be armed?
    Is this why most games take place in the US?
  */
}


class Soldier extends ArmedPerson {
  constructor (personDetails) {
    super(personDetails);
  }
}


class UnarmedSoldier extends Soldier {
  /* HOW DO I TAKE HIS GUN AWAY? */
  constructor (personDetails) {
    super(personDetails);
  }
  attack () {
    /* I know he has a gun, and anybody hacking the game can use it, but what do I do here? */
  }
}

class 在过去的 30 多年里,继承已被证明是人们严重滥用的东西之一(就像其他所有有用的工具一样)。

除了继承,我们还可以看看组合(通过依赖倒置)。

class Soldier {
  constructor (personDetails, gun) {
    /*...setup...*/
    this.equipment = { gun };
    this.selectedWeapon = gun;
  }

  attack (target) {
    this.selectedWeapon.fireAt(target);
  }
}


const soldier = new Soldier({ /*...details... */ }, new Gun());

就我们想要的最终结果而言,并没有太多改变......我们已经能够简化很多,现在我们甚至可以给他一个交换枪支的方法,如果我们愿意的话,这一切都是因为我们不是将枪固定在他继承的东西上,而是在我们第一次见到他时递给他一把枪。 它可以是我们想要的任何类型的枪,只要它仍然可以以类似的方式发射。

问题来了: 那么,如果继承完全脱离 table?

,是否有更好的方法使事物可重用

我要说的是:继承不应该完全脱离 table... ...它应该离一边太远以至于它应该是一个 "aha" 时刻,当你发现它确实是完成某事的最好和最干净的方法时(而不是试图继承......某物,任何东西,现在!)。

各种语言都有一个称为 Traits 或 Mix-Ins 的概念。
在类似 Java 的情况下,一个接近的近似值是接口。
我不是界面的超级粉丝(结构,而不是概念 - 喜欢这个概念)。
在 Java 中,接口让你做更多的工作,因为它们让你定义函数,函数需要什么,它是什么 returns... ...但是你不能给它任何默认行为(传统上),所以如果你有 14 个对象实现相同的接口,那就是你写出 14 次相同的方法(加上接口的签名)。有时,这些方法在实现细节上会完全不同;没关系... ...有时,它们会与您开始编写界面时的预期完全相同。

这不太好。队列特征;这些是您定义接口、定义行为,然后复制到您的对象上的东西。 在 JS 中,我们甚至可以通过注入它们开始工作的上下文来为它们提供一些闭包安全性,而不是让它们假设它们会弄乱整个 this.

const Movable = (pos) => ({
  up (distance) { pos.y += distance; },
  down (distance) { pos.y -= distance; },
  left (distance) { pos.x -= distance; },
  right (distance) { pos.x += distance; }
});


class Point {
  constructor (x, y) {
    Object.assign(this, { x, y });
  }
}

class Person {
  constructor (position) {
    Object.assign(this, { position }, Movable(position));
  }
}


const person = new Person( new Point(0, 0) );

person.up( 20 );
person.position.y; // 20

如果您注意到,Movable 正在返回一个对象的新实例,其方法会更改 position 上的值。该对象正在将其方法复制到 person 的实例上。

我现在可以根据需要创建任意数量的这些 Traits,并将它们复制到任意数量的对象上,然后以这种方式重复使用。