Odnośniki do siebie w literałach obiektowych / inicjalizatorach

705

Czy jest jakiś sposób, aby uzyskać coś takiego do pracy w JavaScript?

var foo = {
    a: 5,
    b: 6,
    c: this.a + this.b  // Doesn't work
};

W obecnej formie ten kod generuje błąd referencyjny, ponieważ thisnie odnosi się do foo. Ale czy jest jakiś sposób, aby wartości we właściwościach literału obiektu zależały od innych właściwości zadeklarowanych wcześniej?

kpozin
źródło

Odpowiedzi:

744

Cóż, jedyne, o czym mogę ci powiedzieć, to getter :

var foo = {
  a: 5,
  b: 6,
  get c() {
    return this.a + this.b;
  }
}

console.log(foo.c) // 11

Jest to rozszerzenie składniowe wprowadzone przez specyfikację ECMAScript 5. edycji, składnia jest obsługiwana przez większość współczesnych przeglądarek (w tym IE9).

CMS
źródło
32
Bardzo pomocna odpowiedź. Więcej informacji na temat „get” można znaleźć tutaj: developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/…
jake
5
@FaustoR. Tak.
Charlie Martin
48
Uważaj, że w przypadku tego rozwiązania, jeśli wartości foo.alub foo.bzostaną zmienione, wówczas wartość zmiennej foo.crównież zmieni się synchronicznie. To może być lub nie być wymagane.
HBP
8
Zauważ, że thiswiąże się z najgłębiej zagnieżdżonym obiektem. Np .:... x: { get c () { /*this is x, not foo*/ } } ...
Z. Khullah
3
Aby uzupełnić moje powyższe stwierdzenie, ponieważ foojest deklarowane jako zmienna i cbędzie oceniane tylko w momencie jego wywołania, użycie foowewnątrz cbędzie działać, w przeciwieństwie do this(bądź ostrożny)
Z. Khullah
316

Możesz zrobić coś takiego:

var foo = {
   a: 5,
   b: 6,
   init: function() {
       this.c = this.a + this.b;
       return this;
   }
}.init();

Byłaby to pewnego rodzaju jednorazowa inicjalizacja obiektu.

Zauważ, że faktycznie przypisujesz wartość zwracaną init()do foo, dlatego musisz return this.

Felix Kling
źródło
95
możesz też delete this.initwcześniej, return thisaby foonie było zanieczyszczone
Billy Moon
15
@BillyMoon: Tak, choć rzeczywiście wpływa to na wydajność wszystkich późniejszych dostępów do właściwości tego obiektu w wielu silnikach (na przykład V8).
TJ Crowder
8
@MuhammadUmer: Nie jestem pewien, w jaki sposób klasy ES6 są odpowiednie dla pytania.
Felix Kling
8
@MuhammadUmer: klasy są tylko składniowym cukrem dla funkcji konstruktora, więc tak naprawdę nie dostarczają niczego nowego. Tak czy inaczej, głównym celem tego pytania są literały obiektowe.
Felix Kling
3
@akantoword: Świetnie :) ponieważ literały obiektowe są pojedynczym wyrażeniem, init()wywołanie zostało bezpośrednio dołączone do literału, aby zachować jedno wyrażenie. Ale oczywiście możesz wywołać tę funkcję oddzielnie od siebie.
Felix Kling
181

Brakuje oczywistej, prostej odpowiedzi, więc dla kompletności:

Ale czy jest jakiś sposób, aby wartości we właściwościach literału obiektu zależały od innych właściwości zadeklarowanych wcześniej?

Nie. Wszystkie rozwiązania tutaj odraczają go do momentu utworzenia obiektu (na różne sposoby), a następnie przypisują trzecią właściwość. Najprostszym sposobem jest po prostu to zrobić:

var foo = {
    a: 5,
    b: 6
};
foo.c = foo.a + foo.b;

Wszystkie inne są po prostu bardziej pośrednimi sposobami na zrobienie tego samego. (Felix's jest szczególnie sprytny, ale wymaga utworzenia i zniszczenia funkcji tymczasowej, zwiększenia złożoności; albo pozostawia dodatkową właściwość na obiekcie, albo [jeśli deleteta właściwość] wpływa na wydajność dostępu do kolejnych właściwości na tym obiekcie).

Jeśli potrzebujesz, aby wszystkie znajdowały się w jednym wyrażeniu, możesz to zrobić bez właściwości tymczasowej:

var foo = function(o) {
    o.c = o.a + o.b;
    return o;
}({a: 5, b: 6});

Lub oczywiście, jeśli musisz to zrobić więcej niż raz:

function buildFoo(a, b) {
    var o = {a: a, b: b};
    o.c = o.a + o.b;
    return o;
}

następnie, gdzie musisz go użyć:

var foo = buildFoo(5, 6);
TJ Crowder
źródło
Dla własnego zdrowia psychicznego próbuję znaleźć jakąś oficjalną dokumentację, która mówi w zasadzie to samo - że obiekt thisjest dostępny tylko dla metod tego obiektu, a nie innych rodzajów właściwości. Masz pomysł, gdzie mogę to znaleźć? Dzięki!
David Kennell,
1
@DavidKennell: Nie staje się bardziej oficjalny niż specyfikacja . :-) Prawdopodobnie zaczniesz tutaj i będziesz to robić . Jest to dość niezręczny język, ale w zasadzie w różnych podrozdziałach oceny definicji właściwości zobaczysz, że obiekt nie jest dostępny dla operacji określających wartości inicjatorów właściwości.
TJ Crowder
Nie widzę tutaj wyników z zakresu przeglądarki , ale tak już nie jest, prawda? W moim środowisku wersja 8: deletejest o 10% szybsza, a gekon: deletetylko o 1% wolniejsza.
TheMaster
1
@TheMaster - Tak, nie sądzę, że BrowserScope to już coś. Wygląda na to, że usuwanie nie jest tak złe, jak kiedyś, przynajmniej nie w V8 (Chrome itp.) Ani SpiderMonkey. Wciąż wolniej, ale tylko trochę, a te rzeczy są dziś dziwacznie szybkie.
TJ Crowder
63

Po prostu utwórz instancję anonimowej funkcji:

var foo = new function () {
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
};
zzzzBov
źródło
1
@Bergi, dlaczego? Ponieważ ktoś może utworzyć z niego inny obiekt tego samego obiektu? To nie tak, że nie mogą po prostu sklonować literału obiektu. Nie różni się niczym od przekazania takiego argumentu, new Point(x, y)z wyjątkiem tego, że funkcja nie jest nazwana do ponownego użycia.
zzzzBov
1
@zzzzBov: Oczywiście mogą po prostu sklonować obiekt, ale w porównaniu z rozwiązaniem IEFE (jak w odpowiedzi TJCrowdera) twoje rozwiązanie przecieka funkcję konstruktora i tworzy zbędny obiekt prototypowy.
Bergi,
5
@zzzzBov: Po prostu użyj, var foo = function() { this.…; return this; }.call({});który nie różni się składniowo, ale semantycznie rozsądny.
Bergi,
1
@Bergi, jeśli uważasz, że to takie ważne, dlaczego nie dodać własnej odpowiedzi do miksu?
zzzzBov
3
Masz to. Rzeczywiście nie zauważyłem newsłowa kluczowego.
Randy
26

Teraz w ES6 możesz tworzyć leniwe właściwości buforowane. Przy pierwszym użyciu właściwość ocenia raz, aby stać się normalną właściwością statyczną. Wynik: za drugim razem pomijany jest narzut funkcji matematycznych.

Magia jest w getterze.

const foo = {
    a: 5,
    b: 6,
    get c() {
        delete this.c;
        return this.c = this.a + this.b
    }
};

W pobocznym strzale thispobiera otaczający zakres leksykalny .

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  
Voscausa
źródło
1
es5 ma również właściwości, których potrzebujesz, aby Object.defineProperty(foo, 'c', {get:function() {...}})je zdefiniować. Można to łatwo zrobić w dyskretny sposób w fabryce takiej jak ta. Oczywiście, jeśli możesz użyć getcukru, jest on bardziej czytelny, ale istnieje możliwość.
Aluan Haddad,
21

Niektóre zamknięcie powinno sobie z tym poradzić;

var foo = function() {
    var a = 5;
    var b = 6;
    var c = a + b;

    return {
        a: a,
        b: b,
        c: c
    }
}();

Wszystkie zmienne zadeklarowane wewnątrz foosą prywatne foo, jak można się spodziewać w przypadku każdej deklaracji funkcji, a ponieważ wszystkie są w zakresie, wszystkie mają dostęp do siebie bez potrzeby odwoływania się this, tak jak można by się spodziewać po funkcji. Różnica polega na tym, że ta funkcja zwraca obiekt, który ujawnia zmienne prywatne i przypisuje ten obiekt do foo. Na koniec zwracasz tylko interfejs, który chcesz udostępnić jako obiekt z return {}instrukcją.

Funkcja jest następnie wykonywana na końcu, ()co powoduje, że cały obiekt foo jest oceniany, wszystkie zmienne w instancji i zwracany obiekt są dodawane jako właściwości foo().

Henry Wrightson
źródło
14
Nazywanie tego „zamknięciem” jest mylące i mylące. Chociaż opinie różnią się co do dokładnego znaczenia, zwracanie wartości ojbect z funkcji nie stanowi zamknięcia w żadnej książce.
16

Możesz to zrobić w ten sposób

var a, b
var foo = {
    a: a = 5,
    b: b = 6,
    c: a + b
}

Ta metoda okazała się przydatna, gdy musiałem odwoływać się do obiektu, na którym pierwotnie zadeklarowano funkcję. Poniżej znajduje się minimalny przykład tego, jak go użyłem:

function createMyObject() {
    var count = 0, self
    return {
        a: self = {
            log: function() {
                console.log(count++)
                return self
            }
        }
    }
}

Definiując self jako obiekt zawierający funkcję drukowania, pozwalasz funkcji odwoływać się do tego obiektu. Oznacza to, że nie musisz „wiązać” funkcji drukowania z obiektem, jeśli musisz przekazać go gdzie indziej.

Jeśli wolisz, użyj tego, thisjak pokazano poniżej

function createMyObject() {
    var count = 0
    return {
        a: {
            log: function() {
                console.log(count++)
                return this
            }
        }
    }
}

Następnie poniższy kod zarejestruje 0, 1, 2, a następnie wyświetli błąd

var o = createMyObject()
var log = o.a.log
o.a.log().log() // this refers to the o.a object so the chaining works
log().log() // this refers to the window object so the chaining fails!

Korzystając z metody self, gwarantujesz, że druk zawsze zwróci ten sam obiekt, niezależnie od kontekstu, w którym funkcja jest uruchomiona. Powyższy kod będzie działał dobrze i logował się 0, 1, 2 i 3, gdy używasz własnej wersji createMyObject().

davedambonit
źródło
3
Dobre przykłady, tyle że pominąłeś wszystkie średniki.
1
Bez średników - w porządku Naprawdę!
Kerem Baydoğan
9

Na zakończenie w ES6 mamy klasy (obsługiwane w momencie pisania tego tylko w najnowszych przeglądarkach, ale dostępne w Babel, TypeScript i innych transpilerach)

class Foo {
  constructor(){
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
  }  
}

const foo = new Foo();
monzonj
źródło
7

Możesz to zrobić przy użyciu wzorca modułu. Tak jak:

var foo = function() {
  var that = {};

  that.a = 7;
  that.b = 6;

  that.c = function() {
    return that.a + that.b;
  }

  return that;
};
var fooObject = foo();
fooObject.c(); //13

Za pomocą tego wzorca można utworzyć kilka obiektów Foo zgodnie z potrzebami.

http://jsfiddle.net/jPNxY/1/

Rafael Rocha
źródło
2
To nie jest przykład wzorca modułu, tylko funkcja. Jeśli ostatnim wierszem definicji foo }();byłby, sam wykonałby i zwrócił obiekt, a nie funkcję. Ponadto, foo.cjest to funkcja, więc pisanie na to clobbers tej funkcji i następnego wywołania poprzez fooObject.c()zawiedzie. Być może to skrzypce jest bliższe temu, do czego dążysz (jest to także singleton, nieprzeznaczony do tworzenia instancji).
Hollister,
2
„Wzorzec modułu został pierwotnie zdefiniowany jako sposób zapewnienia enkapsulacji zarówno prywatnej, jak i publicznej dla klas w konwencjonalnej inżynierii oprogramowania”. Od: Nauka wzorców projektowych JavaScript . Jest to obiekt zgodny ze wzorem modułu opisanym powyżej, ale może nie jest to najlepszy sposób na wyjaśnienie tego, ponieważ nie pokazuje właściwości / metod publicznych i prywatnych. Ten jsfiddle.net/9nnR5/2 to ten sam obiekt z publicznymi i prywatnymi właściwościami / metodami. Obaj postępują według tego schematu
Rafael Rocha,
6

Istnieje kilka sposobów na osiągnięcie tego; właśnie tego użyłbym:

function Obj() {
 this.a = 5;
 this.b = this.a + 1;
 // return this; // commented out because this happens automatically
}

var o = new Obj();
o.b; // === 6
rozpoznać
źródło
2
Działa to, ale eliminuje zalety notacji dosłowności obiektu.
kpozin 15.01.11
Prawda, przepraszam, że oryginalnie brakowało mi znacznika literałowego. Najczęściej używam literałów obiektowych tylko do struktur danych i za każdym razem, gdy potrzebuję jakiejkolwiek dodatkowej logiki (która mogłaby przypominać klasę), tworzę obiekt jako wynik funkcji z tego właśnie powodu.
Ken
6

tylko ze względu na przemyślenie - umieść właściwości obiektu poza osią czasu:

var foo = {
    a: function(){return 5}(),
    b: function(){return 6}(),
    c: function(){return this.a + this.b}
}

console.log(foo.c())

są też lepsze odpowiedzi powyżej . W ten sposób zmodyfikowałem przykładowy kod, który przesłuchałeś.

AKTUALIZACJA:

var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);
animaacija
źródło
2
W ES6 możesz uczynić to ogólne podejście znacznie bardziej eleganckim: var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} }teraz możesz to zrobić foo.czamiast foo.c():) (Możesz wkleić to w swojej odpowiedzi, aby formatowanie było lepsze!)
5

Tworzenie nowej funkcji dosłownie na obiekcie i wywoływanie konstruktora wydaje się radykalnym odejściem od pierwotnego problemu i jest niepotrzebne.

Nie można odwoływać się do właściwości rodzeństwa podczas inicjalizacji dosłowności obiektu.

var x = { a: 1, b: 2, c: a + b } // not defined 
var y = { a: 1, b: 2, c: y.a + y.b } // not defined 

Oto najprostsze rozwiązanie dla obliczonych właściwości (bez stosu, bez funkcji, bez konstruktora):

var x = { a: 1, b: 2 };

x.c = x.a + x.b; // apply computed property
Rick O'Shea
źródło
3

Inne zamieszczone tutaj odpowiedzi są lepsze, ale oto alternatywa:

  • Ustawia wartość przy inicjalizacji (nie pobiera, nie wyprowadza itp.)
  • Nie wymaga żadnego typu init()ani kodu poza literałem obiektu
  • To dosłowny obiekt, a nie funkcja fabryczna lub inna mechanika tworzenia obiektów.
  • Nie powinien mieć żadnego wpływu na wydajność (oprócz inicjalizacji)

Samoczynne anonimowe funkcje i pamięć okien

var foo = {
    bar:(function(){
        window.temp = "qwert";
        return window.temp;
    })(),
    baz: window.temp
};

Zamówienie jest gwarantowane ( barwcześniej baz).

To windowoczywiście zanieczyszcza , ale nie wyobrażam sobie, żeby ktoś pisał scenariusz wymagający window.tempwytrwałości. Może tempMyAppjeśli jesteś paranoikiem.

Jest to również brzydkie, ale czasami przydatne. Przykładem jest użycie interfejsu API ze sztywnymi warunkami inicjalizacji i nie masz ochoty na refaktoryzację, więc zakres jest poprawny.

I oczywiście jest sucho.

DanielST
źródło
3

Kluczem do tego wszystkiego jest ZAKRES .

Musisz obudować „obiekt nadrzędny” (obiekt nadrzędny) właściwości, którą chcesz zdefiniować jako własny obiekt instancji, a następnie możesz odwoływać się do właściwości rodzeństwa za pomocą słowa kluczowego this

Bardzo, bardzo ważne jest, aby pamiętać, że jeśli odwołujesz się do tego thisbez uprzedniego, to thisodniesiesz się do zewnętrznego zakresu ... który będzie windowobiektem.

var x = 9   //this is really window.x
var bar = {
  x: 1,
  y: 2,
  foo: new function(){
    this.a = 5, //assign value
    this.b = 6,
    this.c = this.a + this.b;  // 11
  },
  z: this.x   // 9 (not 1 as you might expect, b/c *this* refers `window` object)
};
Społeczność
źródło
2
To nawet nie jest prawidłowy JS.
2

jeśli twój obiekt jest zapisany jako funkcja, która zwraca obiekt, ORAZ używasz „metod” atrybut-obiektu ES6, możliwe jest:

const module = (state) => ({
  a: 1,
  oneThing() {
    state.b = state.b + this.a
  },
  anotherThing() {
    this.oneThing();
    state.c = state.b + this.a
  },
});

const store = {b: 10};
const root = module(store);

root.oneThing();
console.log(store);

root.anotherThing();
console.log(store);

console.log(root, Object.keys(root), root.prototype);
daviestar
źródło
2

Używam następującego kodu jako alternatywy i działa. Zmienna może być również tablicą. (@ Fausto R.)

var foo = {
  a: 5,
  b: 6,
  c: function() {
    return this.a + this.b;
  },

  d: [10,20,30],
  e: function(x) {
    this.d.push(x);
    return this.d;
  }
};
foo.c(); // 11
foo.e(40); // foo.d = [10,20,30,40]
Indiana
źródło
2

Oto schludny sposób ES6:

var foo = (o => ({
    ...o,
    c: o.a + o.b
  }))({
    a: 5,
    b: 6
  });
  
console.log(foo);

Używam go do robienia czegoś takiego:

const constants = Object.freeze(
  (_ => ({
    ..._,
    flag_data: {
      [_.a_flag]: 'foo',
      [_.b_flag]: 'bar',
      [_.c_flag]: 'oof'
    }
  }))({
    a_flag: 5,
    b_flag: 6,
    c_flag: 7,
  })
);

console.log(constants.flag_data[constants.b_flag]);

UDrake
źródło
1

Co powiesz na to rozwiązanie, które będzie działać również z zagnieżdżonymi obiektami z tablicą

      Object.prototype.assignOwnProVal
     = function (to,from){ 
            function compose(obj,string){ 
                var parts = string.split('.'); 
                var newObj = obj[parts[0]]; 
                if(parts[1]){ 
                    parts.splice(0,1);
                    var newString = parts.join('.'); 
                    return compose(newObj,newString); 
                } 
                return newObj; 
            } 
            this[to] = compose(this,from);
     } 
     var obj = { name : 'Gaurav', temp : 
                  {id : [10,20], city:
                        {street:'Brunswick'}} } 
     obj.assignOwnProVal('street','temp.city.street'); 
     obj.assignOwnProVal('myid','temp.id.1');
Gauraw
źródło
0

Wrzucam opcję, ponieważ nie widziałem dokładnie tego scenariusza. Jeśli nie chcesz caktualizować aani baktualizować, ES6 IIFE działa dobrze.

var foo = ((a,b) => ({
    a,
    b,
    c: a + b
}))(a,b);

Na moje potrzeby mam obiekt, który odnosi się do tablicy, która ostatecznie zostanie użyta w pętli, więc chcę tylko raz obliczyć niektóre typowe ustawienia, więc mam to:

  let processingState = ((indexOfSelectedTier) => ({
      selectedTier,
      indexOfSelectedTier,
      hasUpperTierSelection: tiers.slice(0,indexOfSelectedTier)
                             .some(t => pendingSelectedFiltersState[t.name]),
  }))(tiers.indexOf(selectedTier));

Ponieważ muszę ustawić właściwość indexOfSelectedTieri muszę użyć tej wartości podczas ustawiania hasUpperTierSelectionwłaściwości, najpierw obliczam tę wartość i przekazuję ją jako parametr do IIFE

Snekse
źródło
0

Innym podejściem byłoby zadeklarowanie obiektu przed przypisaniem do niego właściwości:

const foo = {};
foo.a = 5;
foo.b = 6;
foo.c = foo.a + foo.b;  // Does work
foo.getSum = () => foo.a + foo.b + foo.c;  // foo.getSum() === 22

Dzięki temu możesz użyć nazwy zmiennej obiektowej, aby uzyskać dostęp do już przypisanych wartości.
Najlepsze do config.jspliku.

5ervant
źródło
To nie jest samodzielne odniesienie, ale raczej odniesienie do deklarowanej zmiennej, fooktóra wskazuje na przedmiotowy obiekt.
Derek Henderson
0
var x = {
    a: (window.secreta = 5),
    b: (window.secretb = 6),
    c: window.secreta + window.secretb
};

Jest to prawie identyczne z odpowiedzią @ slicedtoad, ale nie używa funkcji.

David Newberry
źródło
-1

Uwaga: w tym rozwiązaniu jest używany Typescript (w razie potrzeby można użyć waniliowego JS, do którego kompiluje TS)

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

    // this method is just to check/test this solution 
    check(){
        console.log(this.def.qwe);
    }
}

// these two lines are just to check
let instance = new asd();
instance.check();

Tutaj używaliśmy wyrażeń klas, aby uzyskać interfejs dosłowny zagnieżdżony obiekt, który chcielibyśmy. Jest to kolejna najlepsza rzecz IMHO, aby móc odwoływać się do właściwości obiektu podczas tworzenia.

Najważniejszą rzeczą do odnotowania jest to, że podczas korzystania z tego rozwiązania masz dokładnie taki sam interfejs, jak w przypadku literału obiektu. A składnia jest bardzo zbliżona do samego dosłowności obiektu (vs przy użyciu funkcji itp.).

Porównaj następujące

Rozwiązanie, które zaproponowałem

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

Rozwiązanie, jeśli dosłowne byłyby literały obiektowe

var asd = {
    def : {
        ads:'asd',
        qwe: this.ads + '123';, //ILLEGAL CODE; just to show ideal scenario
    }
}

Inny przykład

Tutaj, w tej klasie, możesz łączyć ze sobą wiele ścieżek względnych, co nie jest możliwe w przypadku literału obiektu.

class CONSTANT {
    static readonly PATH = new class {
        /** private visibility because these relative paths don't make sense for direct access, they're only useful to path class
         *
         */
        private readonly RELATIVE = new class {
            readonly AFTER_EFFECTS_TEMPLATE_BINARY_VERSION: fs.PathLike = '\\assets\\aep-template\\src\\video-template.aep';
            readonly AFTER_EFFECTS_TEMPLATE_XML_VERSION: fs.PathLike = '\\assets\\aep-template\\intermediates\\video-template.aepx';
            readonly RELATIVE_PATH_TO_AFTER_EFFECTS: fs.PathLike = '\\Adobe\\Adobe After Effects CC 2018\\Support Files\\AfterFX.exe';
            readonly OUTPUT_DIRECTORY_NAME: fs.PathLike = '\\output';
            readonly INPUT_DIRECTORY_NAME: fs.PathLike = '\\input';
            readonly ASSETS_DIRECTORY_NAME: fs.PathLike = '\\assets';
        };
    }
}
Dheeraj Bhaskar
źródło
2
Czy to możliwe, ponieważ twoja odpowiedź jest całkowicie nieistotna? Zgadzam się, że downvoters powinni wyjaśnić, ale twoja jasna odpowiedź nie ma nic wspólnego z pytaniem…
Manngo,
@Manngo dziękuję za zwrócenie na to uwagi. Szczerze mówiąc, mam takie samo pytanie jak OP i korzystam z rozwiązania, które zasugerowałem. Nie jestem pewien, dlaczego uważa się to za nieistotne. Jeśli masz czas, wyjaśnij mi, abym mógł poprawić odpowiedź lub przynajmniej wiedzieć, gdzie się mylę. Niestety nie rozumiem, dlaczego nie jest to rozsądne rozwiązanie.
Dheeraj Bhaskar
-2

Jeśli chcesz korzystać z natywnego JS, inne odpowiedzi dostarczają dobrych rozwiązań.

Ale jeśli chcesz pisać obiekty z odnośnikami, takie jak:

{ 
  a: ...,
  b: "${this.a + this.a}",
}

Napisałem bibliotekę npm o nazwie self-referenced-object, która obsługuje tę składnię i zwraca obiekt macierzysty.

alex-e-leon
źródło
1
Proszę tylko ogniwo unikać odpowiedzi . Odpowiedzi, które są „zaledwie linkiem do strony zewnętrznej”, mogą zostać usunięte .
Quentin
@Quentin, czy masz jakieś sugestie dotyczące ulepszenia mojej odpowiedzi? Inne odpowiedzi na to pytanie dotyczą tego, jak możesz pisać obiekty z odnośnikami w natywnym języku JavaScript, ale jeśli chcesz pisać obiekty z odnośnikami o składni podobnej do składni w oryginalnym pytaniu dotyczącym plakatów, myślę, że biblioteka Napisałem, że mogą być przydatne dla innych, którzy szukają rozwiązania. Chętnie poznamy Twoją opinię.
alex-e-leon
Kilka rzeczy do poprawy tutaj. Po pierwsze i najbardziej oczywiste, że używasz dosłownej składni szablonu bez cofania. Swojej bwartości nieruchomości powinny być: ${this.a + this.a}. Po drugie, ale mniej ważne, chciałbyś zwrócić liczbę, a nie ciąg znaków, używając czegoś takiego parseInt. Co najważniejsze, kiedy spróbowałem tego przykładu, po prostu nie działa, z tego samego powodu, o który prosi OP. Te thispowroty niezdefiniowany stosowany własną deklarację obiektu. @ alex-e-leon
Alec Donald Mather
@AlecDonaldMather - dzięki za poświęcenie czasu na zapoznanie się i przekazanie opinii! Jeśli interesuje Cię projekt, lepiej przenieść tę dyskusję na github, ale odpowiedz na niektóre z twoich opinii: - Korzystanie z backticks: Jak wspomniano w poprzednich komentarzach, JS nie obsługuje tej składni, więc zamiast tego używa ciągów backticks jest tutaj wymagany, aby uniknąć sytuacji, w której js próbuje rozwiązać „to” przed zdefiniowaniem obj - zwracając liczbę, powinno to działać, jeśli a + b są już liczbami, ponieważ a + b zwróci liczbę, jeśli zarówno a i b są już liczby.
alex-e-leon
Czy to powrót jest niezdefiniowane, czy możesz wyjaśnić, jak próbowałeś korzystać z biblioteki? To nie powinno się zdarzyć, ale może jest przypadek, który pominąłem? To powiedziawszy, ta biblioteka nie rozwiązuje problemu całkowicie i ma swój własny zestaw kompromisów, ale jeśli chcesz pomóc mi go ulepszyć / użyć go, daj mi znać!
alex-e-leon