что такое псевдо-свойство в js? [Дубликат]

На сегодняшний день наилучшей ссылкой для этой проблемы остается ответ, опубликованный в трекере проблем для платформы Google.

104
задан Damjan Pavlica 26 April 2016 в 10:45
поделиться

12 ответов

У меня есть один для вас, ребята, который может быть немного уродлив, но он делает это на разных платформах

function myFunc () {

var _myAttribute = "default";

this.myAttribute = function() {
    if (arguments.length > 0) _myAttribute = arguments[0];
    return _myAttribute;
}
}

таким образом, когда вы вызываете

var test = new myFunc();
test.myAttribute(); //-> "default"
test.myAttribute("ok"); //-> "ok"
test.myAttribute(); //-> "ok"

Если вы действительно хотите оживить ситуацию, вы можете вставить проверку типа:

if (arguments.length > 0 && typeof arguments[0] == "boolean") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "number") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "string") _myAttribute = arguments[0];

или пойти еще более сумасшедшим с расширенной проверкой типа: type.of () code at codingforums.com

-1
ответ дан artsy.ca 19 August 2018 в 18:23
поделиться
  • 1
    Дело было в том, чтобы иметь возможность изменить атрибут на что-то странное, не изменяя публичный интерфейс. Добавление тега call () меняет его. – Michael Scott Cuthbert 25 September 2013 в 06:11

Getters and Setters в JavaScript

Обзор

Геттеры и сеттеры в JavaScript используются для определения вычисленных свойств или accessors . Вычисленное свойство - это свойство, которое использует функцию для получения или установки значения объекта. Основная теория делает что-то вроде этого:

var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'

Это полезно для автоматического выполнения вещей за кадром при доступе к ресурсу, например, при хранении чисел в диапазоне, переформатировании строк, срабатывании значения - изменения событий, обновление реляционных данных, предоставление доступа к приватным свойствам и т. д.

В приведенных ниже примерах показан базовый синтаксис, хотя они просто получают и устанавливают значение внутреннего объекта, не делая ничего особенного.

get / set Ключевые слова

ECMAScript 5 поддерживает get и set для определения вычисленных свойств. Они работают со всеми современными браузерами, кроме IE 8 и ниже.

var foo = {
    bar : 123,
    get bar(){ return bar; },
    set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;

Пользовательские Getters и Setters

get и set не являются зарезервированными словами, поэтому они могут быть перегружены для создания собственных пользовательских функций, связанных с перекрестными браузерами. Это будет работать в любом браузере.

var foo = {
    _bar : 123,
    get : function( name ){ return this[ '_' + name ]; },
    set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );

Или для более компактного подхода может использоваться одна функция.

var foo = {
    _bar : 123,
    value : function( name /*, value */ ){
        if( arguments.length < 2 ){ return this[ '_' + name ]; }
        this[ '_' + name ] = value;
    }
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );

Избегайте делать что-то вроде этого, что может привести для кодирования bloat.

var foo = {
    _a : 123, _b : 456, _c : 789,
    getA : function(){ return this.bar; },
    getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};

В приведенных выше примерах имена внутренних свойств абстрагируются с помощью подчеркивания, чтобы препятствовать пользователям просто делать foo.bar vs. foo.get( 'bar' ) и получать «сырые», стоимость. Вы можете использовать условный код для выполнения разных действий в зависимости от имени доступного свойства (через параметр name).

Object.defineProperty ()

Используя Object.defineProperty() это еще один способ добавления геттеров и сеттеров и их можно использовать на объектах после их определения. Его также можно использовать для настройки настраиваемого и перечислимого поведения. Этот синтаксис также работает с IE 8, но, к сожалению, только на объектах DOM.

var foo = { bar : 123 };
Object.defineProperty( foo, 'bar', {
    get : function(){ return bar; },
    set : function( value ){ this.bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;

__ defineGetter __ ()

Наконец, __defineGetter__() - это еще один вариант. Он устарел, но все еще широко используется в Интернете и, следовательно, вряд ли исчезнет в ближайшее время. Он работает во всех браузерах, кроме IE 10 и ниже. Хотя другие варианты также хорошо работают на не-IE, поэтому это не так полезно.

var foo = { bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this.bar; } );
foo.__defineSetter__( 'bar', function( value ){ this.bar = value; } );

См. Также

MDN get , set , Object.defineProperty () , __ defineGetter __ () , __ defineSetter __ () MSDN Поддержка IE8 Getter

37
ответ дан Beejor 19 August 2018 в 18:23
поделиться
  • 1
    В более компактном подходе , this[ '_' + name ] = value; может быть this[ '_' + name ] = arguments[1];, и нет необходимости указывать value arg. – Redhart 31 December 2016 в 11:38
  • 2
    Пример: var foo = { bar : 123, get bar(){ return bar; }, set bar( value ){ this.bar = value; } }; foo.bar = 456; Вызывает исключение: Uncaught RangeError: максимальный размер стека вызовов превышен на панели Object.set [как строка] (& lt; анонимный & gt;: 4: 32) на панели Object.set [в виде строки] (& lt; anonymous & gt; ;: 4: 32) на панели Object.set [в виде бара] (& анонимный & gt;: 4: 32) на панели Object.set [в виде строки] (& анонимный & gt;: 4: 32) на панели Object.set [ как bar] (& anonymous & gt;: 4: 32) на панели Object.set [в виде строки] (& lt; анонимный & gt;: 4: 32) – nevf 8 May 2018 в 23:36
  • 3
    Имя set / get должно отличаться от имени свойства. Поэтому вместо bar: 123 и this.bar = value и т. Д. Измените их на _bar , например. Смотрите: hongkiat.com/blog/getters-setters-javascript – nevf 8 May 2018 в 23:43

В дополнение к @ ответ Sii , установщики могут также использоваться для обновления других значений.

function Name(first, last) {
    this.first = first;
    this.last = last;
}

Name.prototype = {
    get fullName() {
        return this.first + " " + this.last;
    },

    set fullName(name) {
        var names = name.split(" ");
        this.first = names[0];
        this.last = names[1];
    }
};

Теперь вы можете установить fullName и first и last будут обновлены и наоборот.

85
ответ дан Community 19 August 2018 в 18:23
поделиться
  • 1
    Это работает в Internet Explorer? – Akash Kava 22 March 2011 в 16:05
  • 2
    @Akash: Нет, хотя Internet Explorer 9 поддерживает новую функцию Object.defineProperty, которая может определять геттеры и сеттеры. – Matthew Crumley 22 March 2011 в 16:46
  • 3
    Разве это не очень больно, что MS не поддерживает JS правильно, и они не делают их Silverlight работать везде, поэтому я должен запрограммировать все дважды, один для SL и один для остального мира :) – Akash Kava 22 March 2011 в 17:19
  • 4
    @Martin: Вы можете сделать их частными, используя ту же технику, что и в ответе Джона . Если вы хотите использовать реальные геттеры / сеттеры, вам нужно будет использовать функцию this.__defineGetter__ или новую функцию Object.defineProperty. – Matthew Crumley 6 July 2011 в 14:35
  • 5
    @Akash - этот пример работает как есть в IE9 (режим стандартов IE9). – Chris Nielsen 5 September 2011 в 19:24

Вы можете определить метод экземпляра для js-класса через прототип конструктора.

Ниже приведен пример кода:

// BaseClass

var BaseClass = function(name) {
    // instance property
    this.name = name;
};

// instance method
BaseClass.prototype.getName = function() {
    return this.name;
};
BaseClass.prototype.setName = function(name) {
    return this.name = name;
};


// test - start
function test() {
    var b1 = new BaseClass("b1");
    var b2 = new BaseClass("b2");
    console.log(b1.getName());
    console.log(b2.getName());

    b1.setName("b1_new");
    console.log(b1.getName());
    console.log(b2.getName());
}

test();
// test - end

И это должно работать для любого браузера, вы также можете просто использовать nodejs для запуска этого кода.

1
ответ дан Eric Wang 19 August 2018 в 18:23
поделиться
  • 1
    Это просто создает новые методы getName и setName. Они не связаны с созданием свойства! – uzay95 16 November 2017 в 14:14

Getters и seters действительно имеют смысл только тогда, когда у вас есть частные свойства классов. Поскольку Javascript действительно не обладает свойствами частного класса, как вы обычно думаете об объектно-ориентированных языках, это может быть трудно понять. Вот один пример частного счетного объекта. Хорошая вещь об этом объекте заключается в том, что внутренняя переменная «count» недоступна из-за пределов объекта.

var counter = function() {
    var count = 0;

    this.inc = function() {
        count++;
    };

    this.getCount = function() {
        return count;
    };
};

var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());

Если вы все еще смущены, посмотрите статью Крокфорда на Частные члены в Javascript .

11
ответ дан John 19 August 2018 в 18:23
поделиться
  • 1
    Я не согласен. Getters и seters также очень полезны для инкапсуляции информации, определение которой может быть не просто простой переменной. Это может быть удобно, если вам нужно изменить поведение системы, которая ранее использовала простые свойства и от которых могут зависеть другие вещи. Кроме того, ваш пример демонстрирует только «псевдопотоки». которые являются просто функциями. Реальные JavaScript-геттеры появляются как простые значения (и к ним обращаются без обозначения функций), следовательно, их действительная мощность. – devios1 14 June 2011 в 00:18
  • 2
    Не уверен, могу ли я назвать это мощным. Что-то появляется как X, но на самом деле Y не обязательно ясно. Я бы абсолютно НЕ ожидал, что var baz = foo.bar будет иметь полный набор скрытого поведения за ним. I будет ожидать, что из foo.getBar(), однако. – AgmLauncher 20 July 2016 в 18:15

Я думаю, что первая статья, на которую вы ссылаетесь, гласит:

Очевидное преимущество написания JavaScript таким образом заключается в том, что вы можете использовать его в неясных значениях, которые вы не хотите

Цель состоит в том, чтобы инкапсулировать и абстрагировать поля, разрешая доступ к ним через метод get () или set (). Таким образом, вы можете хранить поле / данные внутренне в зависимости от того, какой вы хотите, но внешние компоненты находятся только вдали от вашего опубликованного интерфейса. Это позволяет делать внутренние изменения без изменения внешних интерфейсов, выполнять некоторую проверку или проверку ошибок в методе set () и т. Д.

5
ответ дан matt b 19 August 2018 в 18:23
поделиться

Хотя часто мы привыкли видеть объекты с общедоступными свойствами без какого-либо контроля доступа, JavaScript позволяет нам точно описывать свойства. Фактически, мы можем использовать дескрипторы, чтобы контролировать доступ к объекту и какую логику мы можем применить к нему. Рассмотрим следующий пример:

var employee = {
    first: "Boris",
    last: "Sergeev",
    get fullName() {
        return this.first + " " + this.last;
    },
    set fullName(value) {
        var parts = value.toString().split(" ");
        this.first = parts[0] || "";
        this.last = parts[1] || "";
    },
    email: "boris.sergeev@example.com"
};

Конечный результат:

console.log(employee.fullName); //Boris Sergeev
employee.fullName = "Alex Makarenko";

console.log(employee.first);//Alex
console.log(employee.last);//Makarenko
console.log(employee.fullName);//Alex Makarenko
4
ответ дан Michael Horojanski 19 August 2018 в 18:23
поделиться

Вы использовали бы их, например, для реализации вычисленных свойств.

Например:

function Circle(radius) {
    this.radius = radius;
}

Object.defineProperty(Circle.prototype, 'circumference', {
    get: function() { return 2*Math.PI*this.radius; }
});

Object.defineProperty(Circle.prototype, 'area', {
    get: function() { return Math.PI*this.radius*this.radius; }
});

c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832

(CodePen)

50
ответ дан millimoose 19 August 2018 в 18:23
поделиться
  • 1
    Хорошо, я думаю, что я начинаю это делать. Я пытаюсь назначить getter для свойства length объекта массива, но получаю сообщение об ошибке: «Redeclaration of var length & quot; И код выглядит так: obj = []; obj .__ defineGetter __ ('length', function () {return this.length;}); – user 1 May 2009 в 21:31
  • 2
    Это потому, что объекты Array уже имеют свойство встроенной длины. Если разрешено повторное использование, вызов новой длины будет бесконечным. Попробуйте вызвать свойство & my_length & quot; или некоторые такие. – millimoose 1 May 2009 в 21:52
  • 3
    Чтобы определить оба геттера в одном из операторов, используйте Object.defineProperties . – r0estir0bbe 31 March 2016 в 13:39
  • 4
    Разве вы не можете сделать {& quot; area & quot ;: function () {return ...}}? просто назначьте его как свойство объекта – developer 31 July 2018 в 19:36
  • 5
    @developer Это не Javascript getter, как определено языком, это просто функция. Вы должны вызвать его, чтобы получить значение, оно не перегружает доступ к свойству. Также есть специальный круг ада, предназначенный для людей, которые изобретают свои собственные разбитые объектные системы в JS вместо того, чтобы строить на том, что у него уже есть. – millimoose 31 July 2018 в 20:05

Если вы имеете в виду концепцию аксессоров, тогда простая цель - скрыть базовое хранилище от произвольных манипуляций. Самый экстремальный механизм для этого -

function Foo(someValue) {
    this.getValue = function() { return someValue; }
    return this;
}

var myFoo = new Foo(5);
/* We can read someValue through getValue(), but there is no mechanism
 * to modify it -- hurrah, we have achieved encapsulation!
 */
myFoo.getValue();

Если вы имеете в виду фактическую функцию GET-приемника / сеттера, например. defineGetter / defineSetter или { get Foo() { /* code */ } }, то стоит отметить, что в большинстве современных двигателей последующее использование этих свойств будет намного медленнее, чем в противном случае. например. сравнить производительность

var a = { getValue: function(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.getValue();

vs.

var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.value;
0
ответ дан olliej 19 August 2018 в 18:23
поделиться

Извините, что воскресил старый вопрос, но я подумал, что могу внести пару очень простых примеров и объяснений для «манекенов». Ни один из других ответов, опубликованных таким образом, не иллюстрирует синтаксис, как первый пример MDN guide , который примерно такой же простой, как можно получить.

Getter:

var settings = {
    firstname: 'John',
    lastname: 'Smith',
    get fullname() { return this.firstname + ' ' + this.lastname; }
};

console.log(settings.fullname);

..., конечно, будет записывать John Smith. A getter ведет себя как свойство переменной объекта, но предлагает гибкость функции для вычисления возвращаемого значения на лету. Это в основном причудливый способ создания функции, которая не требует () при вызове.

Setter:

var address = {
    set raw(what) {
        var loc = what.split(/\s*;\s*/),
        area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);

        this.street = loc[0];
        this.city = area[0];
        this.state = area[1];
        this.zip = area[2];
    }
};

address.raw = '123 Lexington Ave; New York NY  10001';
console.log(address.city);

... будет записывать New York на консоль. Как и геттеры, сеттеры вызываются с тем же синтаксисом, что и установка значения свойства объекта, но являются еще одним причудливым способом вызова функции без ().

См. this jsfiddle для более тщательного, возможно, более практического примера. Передача значений в установщик объекта запускает создание или совокупность других объектов объекта. В частности, в примере jsfiddle передача массива чисел приводит к тому, что сеттер вычисляет средний, средний, режим и диапазон; затем устанавливает свойства объекта для каждого результата.

11
ответ дан rojo 19 August 2018 в 18:23
поделиться
  • 1
    Я до сих пор не понимаю преимуществ использования get и set против создания getMethod или setMethod. Это единственное преимущество, которое вы можете назвать без ()? Должна быть другая причина, по которой он добавлен в javascript. – Andreas 29 November 2016 в 23:08
  • 2
    @Andreas Getters и сеттеры ведут себя как свойства при вызове, что может помочь сформулировать их цель. Они не разблокируют другие недостающие способности, но их использование может помочь вам организовать ваши мысли. Это реальная выгода. В качестве практического примера я использовал геттер для расширения объекта Google Maps. Мне нужно было вычислить угол наклона камеры, чтобы я мог поворачивать плитки карты на горизонте. Google делает это автоматически на задней части сейчас; но в то время мне было полезно восстановить maps.roll как свойство, а не возвращать val maps.roll(). Это просто предпочтение. – rojo 30 November 2016 в 01:27
  • 3
    так что это просто синтаксический сахар, чтобы код выглядел чище без (). Я не понимаю, почему вы не могли использовать ваш пример с maps.roll() – Andreas 30 November 2016 в 10:24
  • 4
    @Andreas Кто говорит, что я не мог? Как я уже сказал, это всего лишь способ помочь мне организовать мои мысли. Кодирование - это искусство. Вы не спрашиваете Боба Росса, почему он должен был использовать ожесточенную охру, когда он мог использовать оранжевый цвет. Теперь вы можете не увидеть нужды, но в один прекрасный день, когда вы решите, что ваша живопись нуждается в небольшом ожоре, это будет на вашей палитре. – rojo 30 November 2016 в 12:33
  • 5
    :) Одна вещь, которую я вижу, что получить и установить синтаксис, выполняется автоматически, если она используется как свойство свойства. – Andreas 30 November 2016 в 16:10

Что с этим сбивает с толку ... getters - это функции, которые вызывается, когда вы получаете свойство, сеттеры, когда вы его устанавливаете. Например, если вы выполняете

obj.prop = "abc";

Вы устанавливаете свойство prop, если вы используете геттеры / сеттеры, тогда будет вызываться функция setter, в качестве аргумента будет «abc». Определение функции setter внутри объекта идеально выглядело бы примерно так:

set prop(var) {
   // do stuff with var...
}

Я не уверен, насколько хорошо это реализовано в браузерах. Похоже, у Firefox также есть альтернативный синтаксис, с использованием специальных методов («волшебных») с двойным подчеркиванием. Как обычно, Internet Explorer не поддерживает ничего из этого.

1
ответ дан Rolf 19 August 2018 в 18:23
поделиться

Меня также несколько смутило объяснение , которое я прочитал , потому что я пытался добавить свойство к существующему прототипу, который я не писал, поэтому замена прототипа казалась неправильным подходом. Итак, для потомков, вот как я добавил свойство last в Array:

Object.defineProperty(Array.prototype, "last", {
    get: function() { return this[this.length - 1] }
});

Когда-либо настолько приятнее, чем добавление функции IMHO.

1
ответ дан shawkinaw 19 August 2018 в 18:23
поделиться
Другие вопросы по тегам:

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