Замыкания, область видимости

Хей всем) Прошел теоретическую часть по замыканиям на learn.javascript. По теории все кристально чисто понял, но как дело дошло к практическим заданиям я понял что не все так гладко. Только с помощью подсказок смог разобраться и потом через какое-то время самостоятельно повторить скрипты из заданий. Чувствую крайнюю необходимость поработать еще с замыканиями может вы знаете где взять небольших практических задачек? Или просто продолжить изучение основ JS дальше, так как теорию по замыканиям я усвоил. Спасибо)

Привет. Замыкания - это такая тема к которой надо периодически возвращаться. С первого раза мало кто (без опыта программирования) понимает эту тему.

Замыкания - не единственный подход с помощью которого можно решить задачи ниже. Поставь себе цель решить их именно с помощью замыканий.

http://jscourse.com/task/compose
http://jscourse.com/task/incapsulated-counter
http://jscourse.com/task/keeper

это будет чекпоинт) сделаю, значит дальше пойду) спасибо)

function compose(){
	var functions = [], argCount = arguments.length;
	for(var i = 0; i < argCount; i++){
		functions[i] = arguments[i];
	}
	return function(){
		for (var i = 0; i < argCount; i++){
			var run = functions[i];
			run();
		}
	};
}

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

1 лайк
function createSummator(initialValue) {
	var value = (arguments.length) ? initialValue : 0;
	return {
		get: function(){
			return value;
		},
		inc: function(num){
			return (arguments.length) ? value += num : ++value;
		},
			dec: function(num){
		return (arguments.length) ? value -= num : --value;
		}
	};
}
1 лайк
function createKeeper() {
	var keeper = {};
	return {
		put: function(key, value){
			keeper[key] = value;
		},
		
		get: function(key){
			if(Object.keys(key).length != 0)
			{
				return keeper[key];
			}
			else{
				return null;
			}
		}
	};	
}

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

как проверить на примитив? я не понимаю что оно от меня хочет)

Для начала подумай над этой строкой:

if(Object.keys(key).length != 0)

Помню эту задачу, Дима тут классную свинью подложил )

function createKeeper() {
	var keeper = {};
	return {
		put: function(key, value){
			keeper[key] = value;
		},
		
		get: function(key){
			if(typeof key == "object"){
				if(/*проверка пустоту обьекта*/){
					return keeper[key];
				}
				else{
					return null;
				}
			}
			else 
				if(typeof key == "number" || typeof key == "string"){
					return keeper[key];
				}
		}
	};	
}

я уже разными способами пробовал определить что объект кеу пуст но мне кажется что работал только метод Object.keys. Дописал typeof для определения типа аргумента это годится?

Вопрос “как проверить на примитив” некорректный в данном контексте.

Оно хочет чтобы можно было в качестве ключа использовать не только строки и числа, но и любые объекты.

var val = 100500
var key1 = {}
var key2 = {}

keeper.put(key1, val)
console.log(keeper.get(key1)) // 100500
console.log(keeper.get(key2)) // undefined

При этом надо помнить что одинаковые по структуре объекты не равны. В примере выше объекты в переменных key1 и key2 - одинаковые по структуре, но не равные. Поэтому и keeper это учитывает, возвращая для get с key1 прежде сохраненное значение.

function createKeeper() {
	var keeper = {};
	return {
		put: function(key, value){
			keeper[key] = value;
		},
		
		get: function(key){
			
			if(typeof key == "object"){
				return (key in keeper) ? keeper[key] : null;
			}
			else 
				if(typeof key == "number" || typeof key == "string"){
					return keeper[key];
				}
		}
	};	
}

Оно мне говорит мол не обрабатывается несуществующий ключ)) Как же не обрабатывается если я возвращаю null, когда нету таких объектов в keeper. Если объекты-ключи не одинаковые как ты писал то оно и не найдет его в keeper и по сути должна сработать ветка с “return null” но нет, к сожалению “у вас не обрабатываются несуществующие ключи” мать его…

Пройди пошагово дебаггером как выполняется метод get. И как получается что он возвращает не null. В то что возвращается не null можно убедиться если выполнить в консоли браузера твой код с кодом проверки:

function createKeeper() {
	var keeper = {};
	return {
		put: function(key, value){
			keeper[key] = value;
		},
		
		get: function(key){
			
			if(typeof key == "object"){
				return (key in keeper) ? keeper[key] : null;
			}
			else 
				if(typeof key == "number" || typeof key == "string"){
					return keeper[key];
				}
		}
	};	
}

var keeper = createKeeper();
keeper.put({}, 999);
keeper.get({})

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

Вспомним основы: объект является непримитивным типом данных, в котором информация хранится в формате ключ: значение. Раз тип непримитивный, значит его значения передаются по ссылке. Значит {} === {} // false, хотя объекты и идентичны по содержанию. Это критично для понимания.

Подумай как тебе проверить есть ли уже в твоей базе ключ в виде объекта, на который поступил запрос. Статический метод Object.keys и итерация по объекту в цикле for ... in будут возвращать тебе строковые представления объекта. Т.е. если у тебя будет 2 разных объекта ключами, они будут одинаково приведены к строке [object Object].

может создать сразу после объекта кипер, массив и в него записывать ссылки на объекты которые мы передаем в put. А потом уже в get сравнивать значения из этого массива с значением key функции get??

1 лайк

Дим, че внатуре идея толковая?

Да. Стоит чтобы реализовать

1 лайк
function createKeeper() {
	var keeper = {}, links = [];
	return {
		put: function(key, value){
			keeper[key] = value;
			links.push(key);
		},
		
		get: function(key){
			if(typeof key == "object"){
				for(var i = 0; i < links.length; i++){
					if(links[i] == key){
						return keeper[key];
					}
				}
				return null;
			}
			else 
				if(typeof key == "number" || typeof key == "string"){
					return keeper[key];
				}
		}
	};	
}

ну вот к такому пришел, изменений результата не наблюдается) боже дичь я день вгрохал в одну функцию и то не сделал еще…

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

так и сделаем))

Итак продолжим)) Я перелопатил всю функцию, протестил для примитивов все работает, потом посмотрел содержимое массива links где должны храниться ссылки на объекты, там все есть, проверил условие которое определяет объект ли это когда мы передаем объект в функцию get - работает. Ну и в конце внес в кипер три объекта, в итоге все три вывода в консоли мне выводят последний из тех объектов которые я внес. Может подскажете таки где я ошибку допускаю? может неверно где-то записываю в объект элементы, или неправильно сравниваю объекты?

function createKeeper() {
	var keeper = {}, links = [];
	return {
		put: function(key, value){
			keeper[key] = value;
			if(typeof key === "object"){
				links.push(key);
			}
		},

		get: function(key){
			if(typeof key === "object"){
				for(var i = 0; i < links.length; i++){
					if(links[i] == key){
						return keeper[key];
					}
				}
			}
			else 
				return keeper[key];
		}
	};
}

var keeper = createKeeper();
var key1 = 12;
var key2 = "str";
var key3 = true;
var key4 = {};
var key5 = {};
var key6 = {};
keeper.put(key1, 999)
keeper.put(key2, [1,2,3])
keeper.put(key3, "Oleg")
keeper.put(key6, "obj6")
keeper.put(key4, "obj4")
keeper.put(key5, "obj5")
console.log(keeper.get(key1));
console.log(keeper.get(key2));
console.log(keeper.get(key3));
console.log(keeper.get(key6));
console.log(keeper.get(key4));
console.log(keeper.get(key5));