Сложность с использованием этого «ключевого слова» в JS [duplicate]

Вот почему динамически созданные элементы не реагируют на клики & nbsp;:

var body = $("body");
var btns = $("button");
var btnB = $("<button>B</button>");
// `<button>B</button>` is not yet in the document.
// Thus, `$("button")` gives `[<button>A</button>]`.
// Only `<button>A</button>` gets a click listener.
btns.on("click", function () {
  console.log(this);
});
// Too late for `<button>B</button>`...
body.append(btnB);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>

В качестве обходного пути вы должны прослушивать все клики и проверять исходный элемент & nbsp;:

var body = $("body");
var btnB = $("<button>B</button>");
var btnC = $("<button>C</button>");
// Listen to all clicks and
// check if the source element
// is a `<button></button>`.
body.on("click", function (ev) {
  if ($(ev.target).is("button")) {
    console.log(ev.target);
  }
});
// Now you can add any number
// of `<button></button>`.
body.append(btnB);
body.append(btnC);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>

Это называется «Event Delegation». Хорошие новости, это встроенная функция в jQuery: -)

var i = 11;
var body = $("body");
body.on("click", "button", function () {
  var letter = (i++).toString(36).toUpperCase();
  body.append($("<button>" + letter + "</button>"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>

536
задан Taryn 22 March 2017 в 17:24
поделиться

23 ответа

Ну, единственное, что я могу рассказать вам, это getters:

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

foo.c; // 11

Это синтаксическое расширение, введенное спецификацией ECMAScript 5th Edition, синтаксис поддерживается большинством современных браузеров (в том числе IE9).

506
ответ дан CMS 17 August 2018 в 22:03
поделиться

только ради свойств объекта мыслящего объекта из временной шкалы:

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

console.log(foo.c())

также есть более высокие ответы . Вот как я модифицировал пример кода, с которым вы допросили.

UPDATE:

var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);
7
ответ дан animaacija 17 August 2018 в 22:03
поделиться
  • 1
    В ES6 вы можете сделать этот общий подход более элегантным: var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} }, так что теперь вы можете просто сделать foo.c вместо foo.c() :) (Не стесняйтесь вставлять это в свой ответ, чтобы форматирование было лучше!) – Joe 6 December 2016 в 06:42

Другие ответы, опубликованные здесь, лучше, но вот альтернатива:

  • Устанавливает значение при инициализации (не геттер, или производный и т. д.)
  • t требуется любой тип init() или код вне литерала объекта
  • Является ли литералом объекта, а не фабричной функцией или другим механиком создания объекта.
  • Не должно иметь никакой производительности (кроме инициализации)

Автономные анонимные функции и хранение окон

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

Порядок гарантирован (bar до baz).

Конечно, он загрязняет window, но я не могу представить, чтобы кто-то писал сценарий, который требует window.temp быть постоянным. Может быть, tempMyApp, если вы параноик.

Это также уродливо, но иногда полезно. Например, когда вы используете API с жесткими условиями инициализации и не чувствуете себя рефакторингом, поэтому область обзора верна.

И конечно, конечно.

3
ответ дан Community 17 August 2018 в 22:03
поделиться

Вы могли бы сделать это так

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

Этот метод оказался полезным для меня, когда мне пришлось обратиться к объекту, из которого была объявлена ​​функция. Ниже приведен минимальный пример того, как я его использовал:

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

Определив self как объект, содержащий функцию печати, вы позволяете функции ссылаться на этот объект. Это означает, что вам не нужно «связывать» функцию печати с объектом, если вам нужно передать ее в другое место.

Если бы вы использовали this, как показано ниже

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

, то следующий код будет записывать 0, 1, 2, а затем дать ошибку

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!

Используя метод self, вы гарантируете, что печать всегда будет возвращать один и тот же объект независимо от контекста, в котором выполняется функция. При использовании собственной версии createMyObject() приведенный выше код будет работать только отлично и log 0, 1, 2 и 3.

14
ответ дан davedambonite 17 August 2018 в 22:03
поделиться

, если ваш объект написан как функция, возвращающая объект, и вы используете методы атрибута объекта-объекта ES6, тогда это возможно:

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);
2
ответ дан daviestar 17 August 2018 в 22:03
поделиться

Примечание. Это решение использует TypScript (вы можете использовать vanilla JS, который 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();

Здесь использовались выражения классов для получения вложенного объекта который нам нужен. Это лучшая вещь, с которой ИМХО может ссылаться на свойства объекта во время создания.

Главное, что нужно учитывать при использовании этого решения, у вас есть тот же интерфейс, который у вас был бы с объект литерал. Синтаксис довольно близок к самому объекту (с использованием функции и т. Д.).

Сравните следующее

Решение, которое я предложил

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

Решение, если бы литералы объектов были бы достаточными

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

Другой пример

Здесь, в этом классе, вы можете объединить несколько относительных путей между собой, что невозможно с объектом литерал.

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';
        };
    }
}
-1
ответ дан Dheeraj Bhaskar 17 August 2018 в 22:03
поделиться
  • 1
    Может быть, потому, что ваш ответ абсолютно неактуальен? Я согласен с тем, что downvoters должны объяснить, но ваш ответ ясно не имеет никакого отношения к вопросу ... – Manngo 8 July 2018 в 00:44
  • 2
    @Manngo благодарит за это. Честно говоря, у меня был тот же вопрос, что и у OP, и я использую предлагаемое мной решение. Не уверен, почему это считается неактуальным. Если у вас есть время, объясните, чтобы я мог лучше ответить или по крайней мере знать, где я ошибаюсь. Я, к сожалению, не понимаю, почему это не разумное решение. – Dheeraj Bhaskar 9 July 2018 в 07:18

Вы могли бы сделать что-то вроде:

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

Это была бы какая-то однократная инициализация объекта.

Обратите внимание, что вы фактически назначаете возвращаемое значение init() до foo, поэтому вы должны return this.

277
ответ дан Felix Kling 17 August 2018 в 22:03
поделиться
  • 1
    вы также можете delete this.init до return this, чтобы [f 3] не был загрязнен – Billy Moon 26 July 2011 в 02:12
  • 2
    @BillyMoon: Да, хотя, несмотря на это, влияет на производительность всех последующих доступов свойств на этом объекте на многих устройствах (например, V8). – T.J. Crowder 19 May 2014 в 08:30
  • 3
    @MuhammadUmer: Не знаете, как классы ES6 имеют отношение к вопросу. – Felix Kling 1 June 2015 в 03:02
  • 4
    @MuhammadUmer: классы - это просто синтаксический сахар для функций конструктора, поэтому они не дают ничего нового. В любом случае, основным направлением этого вопроса являются объектные литералы. – Felix Kling 1 June 2015 в 03:45
  • 5
    @akantoword: Великий :), поскольку объектные литералы являются одним выражением, вызов init() был непосредственно добавлен в литерал, чтобы сохранить его в одном выражении. Но, конечно, вы можете вызвать функцию отдельно от вас. – Felix Kling 26 July 2016 в 19:51

Как об этом решении это будет работать и с вложенными объектами с массивом

      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');
1
ответ дан Gaurav 17 August 2018 в 22:03
поделиться

Некоторое закрытие должно иметь дело с этим:

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

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

Все переменные, объявленные в foo, являются закрытыми для foo, как вы ожидали бы с любым объявлением функции и потому, что все они в области , все они имеют доступ друг к другу, не обращаясь к this, как и ожидалось с помощью функции. Разница в том, что эта функция возвращает объект, который предоставляет частные переменные и назначает этот объект foo. В конце вы возвращаете только интерфейс, который хотите выставить в качестве объекта с помощью оператора return {}.

Затем функция выполняется в конце с помощью (), которая заставляет весь объект foo быть оценены, все переменные в экземпляре и объект возврата, добавленный как свойства foo().

18
ответ дан Henry Wrightson 17 August 2018 в 22:03
поделиться
  • 1
    Затруднительно и вводить в заблуждение назвать это «закрытием». Хотя мнения отличаются от точного значения, возвращающего значение ojbect из функции, не являются закрытием в чьей-либо книге. – user 6 September 2014 в 18:17

Я использую следующий код как альтернативу, и он работает. И переменная также может быть массивом. (@ 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]
1
ответ дан Indiana 17 August 2018 в 22:03
поделиться

Существует несколько способов сделать это; это то, что я бы использовал:

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
7
ответ дан ken 17 August 2018 в 22:03
поделиться
  • 1
  • 2
    Правда, извините, что я пропустил объект-литеральный тег изначально. В основном я использую только объектные литералы для структур данных, и в любое время, когда мне нужна дополнительная логика (которая может напоминать класс), я создаю объект в результате функции по этой самой причине. – ken 16 January 2011 в 01:16

Для завершения в ES6 у нас есть классы (поддерживаемые на момент написания этого только в последних браузерах, но доступные в Babel, TypeScript и других транспилерах)

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

const foo = new Foo();
7
ответ дан monzonj 17 August 2018 в 22:03
поделиться

Вы можете сделать это, используя шаблон модуля. Точно так же:

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

С помощью этого шаблона вы можете создать несколько объектов foo в соответствии с вашими потребностями.

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

7
ответ дан Rafael Rocha 17 August 2018 в 22:03
поделиться
  • 1
    Это не пример шаблона модуля, просто функция. Если последняя строка определения foo была }();, она сама выполнит и вернет объект, а не функцию. Кроме того, foo.c - это функция, поэтому запись в нее блокирует эту функцию, а следующий вызов через fooObject.c() завершится с ошибкой. Возможно, эта скрипка ближе к тому, что вы собираетесь делать (это тоже синглтон, не предназначенный для создания экземпляра). – Hollister 26 December 2013 в 03:24
  • 2
    «Первоначально шаблон модуля был определен как способ обеспечения как частной, так и публичной инкапсуляции для классов в обычной разработке программного обеспечения». From: Изучение шаблонов проектирования JavaScript . Этот объект следует описанному выше шаблону модуля, но, возможно, это не лучший способ объяснить это, потому что он не показывает общедоступные и частные свойства / методы. Этот jsfiddle.net/9nnR5/2 - это тот же объект с общедоступными и частными свойствами / методами. Таким образом, оба они следуют этой схеме – Rafael Rocha 16 January 2014 в 21:48
  • 3
    @Rafael, спасибо за ссылку DesignPatterns. – usefulBee 22 July 2015 в 15:45

Создание новой функции в вашем литерале объекта и вызов конструктора кажется радикальным отходом от исходной проблемы, и это не нужно.

Вы не можете ссылаться на свойство sibling во время инициализации литерала объекта.

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

Простейшее решение для вычисляемых свойств (без кучи, без функций, без конструктора):

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

x.c = x.a + x.b; // apply computed property
4
ответ дан Rick O'Shea 17 August 2018 в 22:03
поделиться

Бросок в опцию, так как я не видел этого точного сценария. Если вы не хотите, чтобы c обновлялся при обновлении a или b, тогда ES6 IIFE работает хорошо.

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

Для моих нужд у меня есть объект, относящийся к массиву, который в конечном итоге будет использоваться в цикле, поэтому я хочу только один раз рассчитать некоторую общую настройку, так что это то, что у меня есть :

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

Поскольку мне нужно установить свойство для indexOfSelectedTier, и мне нужно использовать это значение при настройке свойства hasUpperTierSelection, я сначала вычисляю это значение и передаю его как параметр для IIFE

0
ответ дан Snekse 17 August 2018 в 22:03
поделиться

Очевидный простой ответ отсутствует, поэтому для полноты:

Но есть , любой способ иметь значения в свойствах объекта литерала зависит от других объявленных свойств раньше?

Нет. Все решения здесь откладывают до тех пор, пока объект не будет создан (по-разному), а затем назначит третье свойство. Простейший способ состоит в том, чтобы просто сделать это:

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

Все остальные - более косвенные способы сделать то же самое. (Felix's особенно умный, но требует создания и уничтожения временной функции, добавления сложности и либо оставляет дополнительное свойство для объекта, либо [если вы delete это свойство] влияет на производительность последующего свойства доступ к этому объекту.)

Если вам нужно, чтобы все были в одном выражении, вы можете сделать это без временного свойства:

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

Или, конечно, если вам нужно для этого более одного раза:

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

, где вам нужно его использовать:

var foo = buildFoo(5, 6);
136
ответ дан T.J. Crowder 17 August 2018 в 22:03
поделиться
  • 1
    Для моего собственного здравого смысла я пытаюсь найти какую-то официальную документацию, которая говорит в основном то же самое, что объект this объекта доступен только для методов указанного объекта, и никаких других видов свойства. Любая идея, где я мог бы это найти? Благодаря! – David Kennell 5 May 2018 в 01:27
  • 2
    @DavidKennell: не становится более официальным, чем спецификация . :-) Вы, вероятно, запустите здесь и проследуете. Это довольно странный язык, но в основном вы увидите в различных подразделах Property Definition Evaluation , что объект недоступен для операций, определяющих значения инициализаторов свойств. – T.J. Crowder 5 May 2018 в 09:24

Вот аккуратный путь ES6:

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

Я использую его, чтобы сделать что-то вроде этого:

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]);

0
ответ дан UDrake 17 August 2018 в 22:03
поделиться

Теперь в ES6 вы можете создавать ленивые кешированные свойства. При первом использовании свойство оценивает один раз, чтобы стать обычным статическим свойством. Результат: во второй раз пропущена служебная служебная функция.

Магия находится в геттере.

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

В стрелочке геттер this поднимает окружающий лексический охват .

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  
14
ответ дан voscausa 17 August 2018 в 22:03
поделиться
  • 1
    У es5 также есть свойства, которые вам нужно использовать Object.defineProperty(foo, 'c', {get:function() {...}}) для их определения. Это легко сделать ненавязчивым способом на заводе, таком как этот. Конечно, если вы можете использовать сахар get, это более читаемо, но возможности там есть. – Aluan Haddad 18 April 2017 в 01:56

Просто создайте анонимную функцию:

var foo = new function () {
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
};
59
ответ дан zzzzBov 17 August 2018 в 22:03
поделиться
  • 1
  • 2
    @ Берги, почему? Потому что кто-то может создать экземпляр другого из этого же объекта? Не похоже, что они не могут просто клонировать объектный литерал. Это ничем не отличается от передачи аргумента, подобного new Point(x, y), за исключением того, что функция не названа для повторного использования. – zzzzBov 1 August 2015 в 16:54
  • 3
    @zzzzBov: Просто используйте var foo = function() { this.…; return this; }.call({});, который синтаксически не сильно отличается, но семантически разумен. – Bergi 1 August 2015 в 19:13
  • 4
    @randy, вы, очевидно, пропустили, что ключевое слово new использовалось для создания экземпляра функции как экземпляра. foo будет объектом после назначения, а не функцией. Повторите оценку ваших комментариев и голосов. – zzzzBov 11 March 2016 в 15:55
  • 5
    У тебя это есть. Я действительно не заметил ключевое слово new. – Randy 11 March 2016 в 15:58
-1
ответ дан c-chavez 6 September 2018 в 14:08
поделиться
3
ответ дан Community 6 September 2018 в 14:08
поделиться
0
ответ дан c-chavez 29 October 2018 в 20:31
поделиться
3
ответ дан Community 29 October 2018 в 20:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: