Пример из Флэнагана
Всем привет
Продолжаю ковырять Флэнагана, в книге есть такой пример перечисления: var Coin = enumeration({Penny: 1, Nickel:5, Dime:10, Quarter:25}); var dime = Coin.Dime; В переменной dime должен создаваться новый объект, но при запуске скрипта, интерпретатор ругается на функцию enumeration. Подскажите, почему не работает код? |
Цитата:
|
Прошу прощения, мой косяк, чуть ниже было описание функции. Вот весь код:
function enumeration(namesToValues) { // This is the dummy constructor function that will be the return value. var enumeration = function() { throw "Can't Instantiate Enumerations"; }; // Enumerated values inherit from this object. var proto = enumeration.prototype = { constructor: enumeration, // Identify type toString: function() { return this.name; }, // Return name valueOf: function() { return this.value; }, // Return value toJSON: function() { return this.name; } // For serialization }; enumeration.values = []; // An array of the enumerated value objects // Now create the instances of this new type. for(name in namesToValues) { // For each value var e = Object.create(proto); // Create an object to represent it e.name = name; // Give it a name e.value = namesToValues[name]; // And a value enumeration[name] = e; // Make it a property of constructor enumeration.values.push(e); // And store in the values array } // A class method for iterating the instances of the class enumeration.foreach = function(f,c) { for(var i = 0; i < this.values.length; i++) f.call(c,this.values[i]); }; // Return the constructor that identifies the new type return enumeration; } // Create a new Coin class with four values: Coin.Penny, Coin.Nickel, etc. var Coin = enumeration({Penny: 1, Nickel:5, Dime:10, Quarter:25}); var c = Coin.Dime; // This is an instance of the new class Скажите, как часто на практике вообще применяется подобное? |
И еще вопрос, в 24 строке определяется метод foreach, что нужно передавать в аргументы при его вызове?
Например я хочу вызвать его у объекта Coin. Что в (f, c) нужно? |
Цитата:
Цитата:
function enumeration(namesToValues) { // This is the dummy constructor function that will be the return value. var enumeration = function() { throw "Can't Instantiate Enumerations"; }; // Enumerated values inherit from this object. var proto = enumeration.prototype = { constructor: enumeration, // Identify type toString: function() { return this.name; }, // Return name valueOf: function() { return this.value; }, // Return value toJSON: function() { return this.name; } // For serialization }; enumeration.values = []; // An array of the enumerated value objects // Now create the instances of this new type. for(name in namesToValues) { // For each value var e = Object.create(proto); // Create an object to represent it e.name = name; // Give it a name e.value = namesToValues[name]; // And a value enumeration[name] = e; // Make it a property of constructor enumeration.values.push(e); // And store in the values array } // A class method for iterating the instances of the class enumeration.foreach = function(f,c) { for(var i = 0; i < this.values.length; i++) f.call(c,this.values[i]); }; // Return the constructor that identifies the new type return enumeration; } // Create a new Coin class with four values: Coin.Penny, Coin.Nickel, etc. var Coin = enumeration({Penny: 1, Nickel:5, Dime:10, Quarter:25}); var c = Coin.Dime; // This is an instance of the new class var s = {sum : 0}; function fn(a) { this.sum += a.value } Coin.foreach(fn, s); alert(s.sum) |
Подскажите, как понять следующий пример с использованием enumeration:
function enumeration(namesToValues) { // This is the dummy constructor function that will be the return value. var enumeration = function() { throw "Can't Instantiate Enumerations"; }; // Enumerated values inherit from this object. var proto = enumeration.prototype = { constructor: enumeration, // Identify type }; enumeration.values = []; // An array of the enumerated value objects // Now create the instances of this new type. for(name in namesToValues) { // For each value var e = Object.create(proto); // Create an object to represent it e.name = name; // Give it a name e.value = namesToValues[name]; // And a value enumeration[name] = e; // Make it a property of constructor enumeration.values.push(e); // And store in the values array } // A class method for iterating the instances of the class enumeration.foreach = function(f,c) { for(var i = 0; i < this.values.length; i++) f.call(c,this.values[i]); }; enumeration.print = function() { console.log(this.values); } // Return the constructor that identifies the new type return enumeration; } // Define a class to represent a playing card function Card(suit, rank) { this.suit = suit; // Each card has a suit this.rank = rank; // and a rank } // These enumerated types define the suit and rank values Card.Suit = enumeration({Clubs: 1, Diamonds: 2, Hearts:3, Spades:4}); Card.Rank = enumeration({Two: 2, Three: 3, Four: 4, Five: 5, Six: 6, Seven: 7, Eight: 8, Nine: 9, Ten: 10, Jack: 11, Queen: 12, King: 13, Ace: 14}); // Define a class to represent a standard deck of cards function Deck() { var cards = this.cards = []; // A deck is just an array of cards Card.Suit.foreach(function(s) { // Initialize the array Card.Rank.foreach(function(r) { cards.push(new Card(s, r)); }); }); } var deck = new Deck(); Не понятно что происходит при создании var deck. Откуда берутся s и r в параметрах , если они не объявлены никак ранее? И как опять тут срабатывает enumeration.foreach = function(f,c), каким образом там оказывается список Card.Suit и Card.Rank, если он не передается в параметрах. Помогите пожалуйста разобраться, уже и так и сяк пробовал дебагером смотреть, ничего не понятно. |
|
Цитата:
Цитата:
|
Цитата:
|
Цитата:
значит s это f.call(c,this.values[i]); или currentValueТекущий обрабатываемый элемент в массиве. enumeration.foreach не нативный, но он делает тоже самое что forEach в Array. |
Цитата:
Цитата:
Пример 9.7 содержит единственную функцию enumeration(). Однако она не является конструктором: она не определяет класс с именем «enumeration». Но она является фабричной функцией: при каждом вызове она создает и возвращает новый класс. Ниже показано, как ее можно использовать: var Coin = enumeration({Penny: 1, Nickel:5, Dime:10, Quarter:25}); var c = Coin.Dime; // This is an instance of the new class c instanceof Coin // => true: instanceof works c.constructor == Coin // => true: constructor property works Coin.Quarter + 3*Coin.Nickel // => 40: values convert to numbers Coin.Dime == 10 // => true: more conversion to numbers Coin.Dime > Coin.Nickel // => true: relational operators work String(Coin.Dime) + ":" + Coin.Dime // => "Dime:10": coerce to string |
Цитата:
|
Цитата:
|
Вам на самом деле не нужна такая функция для перечисления, поскольку JavaScript предоставляет необходимые возможности для перечисления.
{ const coins = { Penny: 1, Nickel: 5, Dime: 10, Quarter: 25 }; const dime = coins.Dime; let sum = 0; for(const value of Object.values(coins)) { sum += value; } alert(sum); } Или даже так... { const coins = { Penny: 1, Nickel: 5, Dime: 10, Quarter: 25 }; let sum = Object.values(coins).reduce((sum, value) => sum + value); alert(sum); } Цитата:
Вот тот пример с игральными картами, но написанный с учётом возможностей JavaScript... function Card(suit, rank) { this.suit = suit; this.rank = rank; } Card.Suits = { Clubs: 1, Diamonds: 2, Hearts: 3, Spades: 4 }; Card.Rank = { Two: 2, Three: 3, Four: 4, Five: 5, Six: 6, Seven: 7, Eight: 8, Nine: 9, Ten: 10, Jack: 11, Queen: 12, King: 13, Ace: 14 }; function Deck() { this.cards = []; for(const suit of Object.values(Card.Suits)) for(const rank of Object.values(Card.Rank)) this.cards.push(new Card(suit, rank)); } var deck = new Deck(); console.log(deck); Можно сделать объект перечисляемым, добавив в него метод Symbol.iterator, в котором будет указано, каким образом перечислять, например я могу захотеть перечислять достоинства карт так, как они обозначаются на игральных картах... var ranks = { Two: 2, Three: 3, Four: 4, Five: 5, Six: 6, Seven: 7, Eight: 8, Nine: 9, Ten: 10, Jack: 11, Queen: 12, King: 13, Ace: 14, * [Symbol.iterator]() { for(const v in this) { yield this[v] <= 10 ? this[v] : v[0]; } } }; // оператор расширения использует доступный итератор (он определён как Symbol.iterator) console.log([...ranks]); // Или можно использовать цикл for-of без Object.values, // ranks стал перечислимым, поскольку содержит свойство-метод Symbol.iterator for(const rank of ranks) { console.log(rank); } Перечислимость объекта определяется наличием свойства-метода Symbol.iterator Если вам всё-таки нужен тип данных, чьё множество значении представляет собой ограниченный список идентификаторов, то подойдут символьные примитивы. Например, функцию enumeration (давайте я её назову Enum) можно определить так... function Enum([definition]) { return Object.freeze( definition .trim() .split(/\s+/) .reduce((m, p) => ({ ...m, [p]: Symbol(p), __proto__: null }), {}) ); } // Примеры const Color = Enum` RED GREEN BLUE `; const Cardsuits = Enum` CLUBS DIAMONDS HEARTS SPADES `; console.log(Color, Cardsuits); Хотя, такая функция в каком-то смысле лишняя, поскольку можно напрямую работать с символами... const Color = Object.freeze({ RED: Symbol("RED"), GREEN: Symbol("GREEN"), BLUE: Symbol("BLUE") }); console.log(Color); |
Malleys,
:victory: :thanks: |
Часовой пояс GMT +3, время: 00:39. |