Геттеры \ сеттеры для чайников - PullRequest
123 голосов
/ 01 мая 2009

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

Может кто-то четко заявить:

  1. Для чего предназначены геттер и сеттер, и
  2. Приведите ОЧЕНЬ простые примеры?

Ответы [ 12 ]

92 голосов
/ 02 мая 2009

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

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"
57 голосов
/ 01 мая 2009

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

Например:

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)

53 голосов
/ 18 января 2016

геттеров и сеттеров в JavaScript

Обзор

Методы получения и установки в 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'

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

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

получить / установить ключевые слова

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 против 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 Support

14 голосов
/ 04 октября 2014

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

Getter:

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

console.log(settings.fullname);

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

сеттер:

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

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

11 голосов
/ 02 мая 2009

Методы получения и установки действительно имеют смысл, только если у вас есть частные свойства классов. Поскольку Javascript на самом деле не имеет свойств закрытого класса, как вы обычно думаете из Object Oriented Languages, это может быть трудно понять. Вот один из примеров объекта с частным счетчиком. Приятной особенностью этого объекта является то, что внутренняя переменная "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 голосов
/ 25 октября 2016

Хотя часто мы привыкли видеть объекты с открытыми свойствами без какого-либо доступа контроль, 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
6 голосов
/ 01 мая 2009

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

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

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

2 голосов
/ 16 сентября 2014

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

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

Всегда немного приятнее, чем добавление функции ИМХО.

2 голосов
/ 16 июня 2014

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

2 голосов
/ 28 апреля 2011

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

obj.prop = "abc";

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

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

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

...