Геттеры\сеттеры для чайников

Я пытаюсь разгадать геттеры и сеттеры и не погружаться. Я читал JavaScript Getters and Setters и Определение Getters и Setters и просто не получить его.

Может ли кто-то четко указать:

  • То, что должны делать геттер и сеттер, и
  • Дайте несколько простых примеров?

Ответ 1

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

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 будут обновлены, и наоборот.

n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"

Ответ 2

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

Например:

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)

Ответ 3

Getters and Setters в JavaScript

Обзор

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

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;

Пользовательские получатели и сеттеры

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

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

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

Ответ 4

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

Getter:

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

console.log(settings.fullname);

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

сеттер:

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 в консоль. Как и getters, сеттеры вызываются с тем же синтаксисом, что и установка значения свойства объекта, но являются еще одним причудливым способом вызова функции без().

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

Ответ 5

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.

Ответ 6

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

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

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

Ответ 7

Хотя часто мы привыкли видеть объекты с общедоступными свойствами без какого-либо доступа управление, 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: "[email protected]"
};

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

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

Ответ 9

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

obj.prop = "abc";

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

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

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

Ответ 10

Вы можете определить метод экземпляра для класса 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 для запуска этого кода.

Ответ 11

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

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

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

Ответ 12

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

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

против.

var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.value;

Ответ 13

Почему бы не использовать get и set синтаксис?

Ответ 14

Getters and Setters - это просто общие понятия, которые точно соответствуют имени: Получить переменную/объект и установить переменную/объект.

Вот как я лично "получаю" и "устанавливаю" свои собственные переменные:

var data = "Hello World"

Некоторым людям иногда приходится абстрагироваться, поэтому они делают это:

function get(value){
    [...]
}

function set(name,value){
    [...]
}

set("data","Hello World");
var data = get("data");

Я не очень часто использую Getters и Setters, но для них есть несколько полезных применений, например, когда вам нужно абстрагироваться от способа сохранения/доступа переменной.

Ответ 15

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

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

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