2016-05-18 7 views
4

Я разрабатываю небольшую библиотеку и стараюсь, чтобы API API был как можно меньше, чем , идея использования функции как самого словаря/объекта выглядит привлекательным.Использование функции в качестве словаря

Идея заключается в том, чтобы иметь возможность вызвать функцию обычно нравится:

fn('hello', 'some other extra info to be processed', etc...) 

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

fn['hello'] 
//-> some stuff 

В питона, например, было бы очень легко перегрузить оператор [] , , но AFAIK там нет простого и надежного способа в JS, который работает в большинстве окружений (прокси, похоже, делают трюк, но пока мы еще не так). Getters и seters не являются опцией, так как пользователь может ввести любое значение.

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

  • apply
  • prototype
  • __proto__

Однако многие вещи в JS мир хаки, и мы счастливо делаем их каждый день. Вопрос: это опасно и приведет к гибели тысяч котят?

+0

Я не вижу преимущества использования 'fn ['hello']' over 'fn ('hello')'. Почему бы просто не использовать функцию-вызов? Как вы упомянули, добавление свойств функции может завершиться неудачей. – Thomas

+0

такой подход 'fn ['hello'] <-> fn ('hello')' выглядит запутанным и неоднозначным – RomanPerekhrest

+0

@Thomas, есть две операции. Вызов функции будет обрабатывать и регистрировать некоторые данные, а '[]' access будет возвращать эти данные. Во всяком случае, прецедент не стоит подробно объяснять, вопрос в том, произойдет ли это взорваться или нет. Моим вторым подходом было бы приложить к функции метод '.get'. – bgusach

ответ

4

@Thomas, есть две операции. Вызов функции будет обрабатывать и регистрировать некоторые данные, а доступ [] будет возвращать эти данные. Во всяком случае, прецедент не стоит подробно объяснять, вопрос в том, произойдет ли это взорваться или нет.

Да, он взорвется, а не из-за свойства, которые уже упоминались, но из-за length и name. Эти свойства, скорее всего, будут отображаться в словаре (чем применимо, прототип или proto), и это вызовет у вас проблемы, потому что вы не можете просто перезаписать их на функции. Вы можете переопределить их с помощью defineProperty, но все это просто увеличивает сложность, память-след, yada yada yada ... без уважительной причины.

Лучший подход был бы комбинированный геттер и сеттер, тем более, что эта модель aready используется по Libs, как JQuery, например:

function getterSetter(key, value){ 
    if(arguments.length > 1){ 
     this[key] = value; 
    }else{ 
     return this[key]; 
    } 
} 
//for explicitely telling wether you want to get() or set() 
function getter(key){ return this[key]; } 
function setter(key, value){ this[key] = value; } 

function dict(){ 
    var cache = Object.create(null); 
    var fn = getterSetter.bind(cache); 
    fn.get = getter.bind(cache); 
    fn.set = setter.bind(cache); 
    return fn; 
} 

Использование

var cache = dict(); 
//set 
cache.set("hello", "kitty"); 
//or just 
cache("hello", "kitty"); 

//get 
cache.get("hello"); 
//or 
cache("hello"); 

и даже если вы хотите для отображения по массиву:

var values = ["foo", "bar", "hello"].map(cache.get); 

В этом случае вы не можете использовать ярлык .map(cache), потому что функция-карта передает еще два аргумента, индекс и массив, а cache() интерпретирует индекс как значение для установки.

Или вы можете объяснить, что:

funciton isArrayLike(obj){ 
    return !!obj && typeof obj === "object" && (+obj.length) === (obj.length >>> 0); 
} 

function getterSetter(key, value, arr){ 
    if(arguments.length > 1 && !isArrayLike(arr)){ 
     this[key] = value; 
    }else{ 
     return this[key]; 
    } 
} 

var values = ["foo", "bar", "hello"].map(cache); 

Но это реализация-подробность о вашей библиотеке,. ака. ваше решение.

+0

В первом абзаце есть вся информация, которую я искал. Большое спасибо! Вы спасли жизнь многих котят. – bgusach

5

Вы можете использовать setter и getter.

Недостатком является то, что вы должны заранее знать, какие ключи вы используете.

function fn(s) { 
 
    if (!fn[s]) { 
 
     Object.defineProperty(fn, s, { get: function() { document.write('hello '+s+'!<br>'); }, set: function() { } }); 
 
    } 
 
    document.write('hello ' + s + '<br>'); 
 
} 
 

 
fn('stackoverflow'); 
 
fn['stackoverflow']; 
 
fn('42'); 
 
fn['42']; 
 
fn['stackoverflow'];

+1

[Dynamic Getters and Setters] (http://stackoverflow.com/questions/7891937/is-it-possible-to-implement-dynamic-getters-setters-in-javascript) – noahnu

+0

Это неверный ответ, так как он hardcoded на 'hello'. Я хочу, чтобы пользователь использовал ключ '[]' on _any_. – bgusach

+0

@ bgusach, посмотрите пожалуйста редактирование. –

Смежные вопросы