Ваше событие сброса вызвано span
, а не содержащим div
. Таким образом, перетаскиваемый элемент добавляется к промежутку, на который он перетаскивается.
Вы можете предотвратить это, изменив строку
ev.target.appendChild(document.getElementById(data));
на ev.target.closest('div').appendChild(document.getElementById(data));
Это может быть уместно, когда сам указатель можно рассматривать как «черный ящик», то есть часть данных, внутреннее представление которых не должно иметь отношения к коду.
По сути, если ваш код никогда не будет разыменовывать указатель, и вы просто передаете его функциям API (иногда по ссылке), то typedef не только уменьшает количество *
s в вашем коде, но также предлагает программисту не вмешиваться в указатель.
Это также упрощает изменение API в будущем, если возникнет такая необходимость. Например, если вы перейдете на использование идентификатора, а не указателя (или наоборот), существующий код не сломается, потому что указатель никогда не должен был быть разыменован в первую очередь.
Некоторое время назад я бы ответил «нет» на этот вопрос. Теперь, с появлением умных указателей, указатели уже не всегда обозначаются звездочкой «*». Так что нет ничего очевидного в том, что тип является указателем или нет.
Итак, теперь я бы сказал: нормально указывать указатели, если ясно, что это «тип указателя». Это означает, что вы должны использовать префикс / суффикс специально для него. Нет, например, "p" не является достаточным префиксом. Я бы, наверное, пошел с "ptr".
Цель с помощью typedef - скрыть детали реализации, но определение типа свойства указателя скрывает слишком много и делает код сложнее читать / понимать. Поэтому, пожалуйста, не делайте этого.
Если вы хотите скрыть детали реализации (что часто бывает полезно), не скрывайте часть указателя. Возьмем, к примеру, прототип для стандартного интерфейса FILE
:
FILE *fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, FILE *stream);
здесь fopen возвращает указатель на некоторую структуру FILE
(реализация которой вам неизвестна) детали для). Может быть, FILE
не очень хороший пример, потому что в этом случае он мог бы работать с некоторым типом pFILE, который скрывал тот факт, что он является указателем.
pFILE fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, pFILE stream);
Однако это сработало бы только потому, что вы никогда не возитесь с содержанием, на которое указывает непосредственно. В тот момент, когда вы набираете указатель на то, что вы в некоторых местах модифицируете код, мне становится очень трудно читать.
Win32 API делает это практически со всеми структурами (если не со всеми)
POINT => *LPPOINT
WNDCLASSEX => *LPWNDCLASSEX
RECT => *LPRECT
PRINT_INFO_2 => *LPPRINT_INFO_2
Хорошо, как это является последовательным, но, на мой взгляд, это не добавляет элегантности.
Typedef используется для того, чтобы сделать код более читабельным, но указатель типа typedef увеличит путаницу. Лучше избегать указателей typedef.
Это вопрос стиля. Этот вид кода очень часто встречается в заголовочных файлах Windows. Хотя они, как правило, предпочитают все заглавные буквы версии вместо префикса строчными буквами p.
Лично я избегаю такого использования typedef. Гораздо понятнее, чтобы пользователь явно сказал, что хочет Foo *, чем PFoo. Typedef лучше всего подходят для того, чтобы сделать STL читабельным:)
typedef stl::map<stl::wstring,CAdapt<CComPtr<IFoo>> NameToFooMap;
Это может помочь вам избежать некоторых ошибок. Например, в следующем коде:
int* pointer1, pointer2;
pointer2 не является int * , это просто int . Но с typedefs этого не произойдет:
typedef int* pInt;
pInt pointer1, pointer2;
Они оба int * сейчас.
Не в моем опыте. Скрытие « *
» затрудняет чтение кода.
Единственный раз, когда я использую указатель внутри typedef, это когда имею дело с указателями на функции:
typedef void (*SigCatcher(int, void (*)(int)))(int);
typedef void (*SigCatcher)(int);
SigCatcher old = signal(SIGINT, SIG_IGN);
В противном случае, я найдите их более запутанными, чем полезными.
signal ()
, а не для ловушки сигналов. Это можно сделать более понятным (используя исправленный тип SigCatcher
выше), написав:
typedef SigCatcher (* SignalFunction) (int, SigCatcher);
Или, чтобы объявить функцию signal ()
:
extern сигнал SigCatcher (int, SigCatcher);
То есть SignalFunction
- это указатель на функцию, которая принимает два аргумента ( int
и SigCatcher
) и возвращает SigCatcher
. А сама функция signal ()
является функцией, которая принимает два аргумента ( int
и SigCatcher
) и возвращает SigCatcher
.
Это (как и многие ответы) зависит.
В Си это очень часто, так как вы пытаетесь скрыть, что объект является указателем. Вы пытаетесь предположить, что это объект, которым манипулируют все ваши функции (мы знаем, что это указатель внизу, но он представляет объект, которым вы манипулируете).
MYDB db = MYDBcreateDB("Plop://djdjdjjdjd");
MYDBDoSomthingWithDB(db,5,6,7);
CallLocalFuc(db); // if db is not a pointer things could be complicated.
MYDBdestroyDB(db);
Под MYDB, вероятно, указатель на какой-то объект.
В C ++ это больше не требуется.
Главным образом потому, что мы можем передавать вещи по ссылке, а методы включаются в объявление класса.
MyDB db("Plop://djdjdjjdjd");
db.DoSomthingWithDB(5,6,7);
CallLocalFuc(db); // This time we can call be reference.
db.destroyDB(); // Or let the destructor handle it.
Если вы это сделаете, вы не сможете создать контейнеры STL Const PsoMeStuct, поскольку компилятор считается:
list<const pSomeStruct> structs;
как
list<SomeStruct * const> structs;
, который не является законным контейнером STL, поскольку Элементы не являются назначаемыми.
См. В этом вопрос .