Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Требуется помощь (https://javascript.ru/forum/misc/79781-trebuetsya-pomoshh.html)

rexton 23.03.2020 21:13

Требуется помощь
 
Я новичек в программировании под JS. До этого в основном писал на С под микроконтроллеры, и не сразу получается все понять.
Собственно вопрос вот в чем. Приведу абстрактный код который у меня не работает как надо. Это часть скрипта который загружается в браузере.
//*1
function a()
{

    let selectCallback=1;
    let gFileList;

    a.prototype=
    {
        setSelectCallback: function(value)
	    {
	    	selectCallback=value;
	    }
    }

    //некоторый код который загружает ресурсы с диска используя промисы

	getFilesAndFoldersList(gCurentPath).then((res)=>
		{
			gFileList=res;
		},
		function(err)
		{
			let b=err;
		});
}
//*2
window.addEventListener("load",function() {
   let b=new a();
   b.setSelectCallback(function(a)
       {
          //do something
          let c=a;
       });
});


Собственно вопрос в том, что при первом вызове из "*2" в отладчике показывает что у переменной b в прототипе нет метода setSelectсallback. При втором вызове он есть, но когда используется внутри функции a значение selectCallback остается равно 1. Собственно почему? если я проходя по отладке вижу, что значение переменной seleckCallback в функции a меняется на нужный мне обработчик, но когда я пытаюсь использовать значение переменной изнутри функции оно всегда равно 1.

Сильно не пинайте. Возможно я в принципе неправильно все это пытаюсь сделать, но кучу интернета перерыл ответа на вопрос не нашел.

Nexus 23.03.2020 22:07

Цитата:

Сообщение от rexton
Собственно вопрос в том, что при первом вызове из "*2" в отладчике показывает что у переменной b в прототипе нет метода setSelectсallback.

Это все потому, что вы прототип функции изменяете при её вызове.
JavaScript - интерпретируемый ЯП.

Цитата:

Сообщение от rexton
но когда я пытаюсь использовать значение переменной изнутри функции оно всегда равно 1

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

Попробуйте так:
function someClass() {
    this.selectCallback = 1;
    
    if (!this.gFileList && window.gCurentPath) {
        this.__loadFileList(gCurentPath);
    }
};

someClass.prototype.gFileList = null;

someClass.prototype.__loadFileList = function (directoryPath) {
    if (!directoryPath) {
        return Promise.reject();
    }
    
    return getFilesAndFoldersList(directoryPath).then(res => {
        this.gFileList = res;
    });
};

someClass.prototype.setSelectCallback = function (value) {
    this.selectCallback = value;
};

window.addEventListener('load', function () {
    var someClassInstance = new someClass();
    
    someClassInstance.setSelectCallback(function (a) {
        // do something
        
        let c = a;
    });
});


P.S. от прямого изменения прототипа можно избавиться с помощью синтаксического сахара добавленного в ES6, т.е. объявить класс с помощью ключ. слова «class».

rexton 23.03.2020 22:53

Попробовал возникли следующие вопросы:
1. Это общепринятая практика не менять proto функции в ее вызове?
2. Как всегда проблема с this. Он не указывает на someClass. Я хочу использовать переменную selectCallback в обработчике нажатия кнопок, и соответственно this указывает на window а не на someClass. Что делать с этим? bind?

Ну и напоследок, все это я ковыряю на KaiOS (основан на FirefoxOS движок Gecko 48), хотя не думаю, что это имеет принципиальное значение.

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

рони 24.03.2020 00:07

Цитата:

Сообщение от rexton
Что делать с этим?

Цитата:

Сообщение от nerv_
перечислю все известные мне способы решения "детских" проблем с this.

https://javascript.ru/forum/dom-wind...tml#post470583

Nexus 24.03.2020 00:07

Цитата:

Сообщение от rexton
1. Это общепринятая практика не менять proto функции в ее вызове?

Я думаю, что да. Никогда не видел, чтобы прототип класса изменялся в конструкторе. Да и зачем это?

Цитата:

Сообщение от rexton
2. Как всегда проблема с this. Он не указывает на someClass. Я хочу использовать переменную selectCallback в обработчике нажатия кнопок, и соответственно this указывает на window а не на someClass. Что делать с этим? bind?

Покажите, пожалуйста, ваш код.
Скорее всего Вы пытаетесь забить гвоздь отверткой.

Цитата:

Сообщение от rexton
С class у меня не сложилось, если правильно помню, там не получается создавать переменные для экземпляра класса.

Не понял.

rexton 24.03.2020 00:38

2 Nexus
1. Это незачем. Просто привычка от C. В вызванной функции делается все, что должно быть сделано, а не кусок кода который загружен в память, нигде не вызывается, но выполняется).
2. Да смысла нет выкладывать весь говнокод. Я просто тренируюсь. После вашей рекомендации вынести proto вне функции с ним все стало нормально, после первого вызова есть нужный метод. this привязал через bind.
3. пробовал писать так:
class a
{
    let b=1;

    c()
    {
        alarm(b);
    }
}

на let b=1; затык, синтаксическая ошибка, и так и не нашел, как сделать переменную для класса которая была бы доступна всем функциям внутри класса (ну как в c++).
А используя функции это возможно.

Malleys 24.03.2020 03:05

rexton, вы можете объявить все нужные переменные при инициализации класса, например ваш пример выше... Синтаксис ES2020
{

class A {
	b = 1;

	c() {
		alarm(this.b);
	}
}

function alarm(message) {
	alert("⚠️ " + message);
}

const a = new A();
a.c();

}


Если вы хотите использовать более старую спецификацию, то...
{

class A {
	constructor() {
		this.b = 1;
	}

	c() {
		alarm(this.b);
	}
}

function alarm(message) {
	alert("⚠️ " + message);
}

const a = new A();
a.c();

}


Цитата:

Сообщение от rexton
А используя функции это возможно.

Класс — это тоже функция. Т. е. если вы пишете...
class A {
	constructor() {
		let a = 1;
		this.a = 2;
	}
}
то это тоже самое, что...
function A() {
	// if(!new.target) throw new TypeError("Class constructor cannot be invoked without 'new'");
	let a = 1;
	this.a = 2;
}
Отличие в том, что объявление класса при помощи функции-конструктора требует ручной проверки (если практически необходимо; в примере выше закомментировано) на то, что этот конструктор не будет вызываться как функция, а скорей только как конструктор. (А синтаксис класса предполагает такую проверку автоматически)


Часовой пояс GMT +3, время: 03:24.