Staroświecki wątek, ale istnieją nowe sposoby prowadzenia odpowiednika isset()
.
ESNext (etap 4 grudnia 2019 r.)
Dwie nowe składnie pozwalają nam znacznie uprościć korzystanie z isset()
funkcjonalności:
Przeczytaj dokumenty i pamiętaj o zgodności przeglądarki.
Poprzednia odpowiedź
Wyjaśnienia poniżej. Uwaga Używam składni StandardJS
Przykładowe użycie
// IMPORTANT pass a function to our isset() that returns the value we're
// trying to test(ES6 arrow function)
isset(() => some) // false
// Defining objects
let some = { nested: { value: 'hello' } }
// More tests that never throw an error
isset(() => some) // true
isset(() => some.nested) // true
isset(() => some.nested.value) // true
isset(() => some.nested.deeper.value) // false
// Less compact but still viable except when trying to use `this` context
isset(function () { return some.nested.deeper.value }) // false
Funkcja odpowiedzi
/**
* Checks to see if a value is set.
*
* @param {Function} accessor Function that returns our value
*/
function isset (accessor) {
try {
// Note we're seeing if the returned value of our function is not
// undefined
return typeof accessor() !== 'undefined'
} catch (e) {
// And we're able to catch the Error it would normally throw for
// referencing a property of undefined
return false
}
}
Wyjaśnienie
PHP
Zauważ, że w PHP możesz odwoływać się do dowolnej zmiennej na dowolnej głębokości - nawet próbując uzyskać dostęp do nie-tablicy, ponieważ tablica zwróci prosty true
lub false
:
// Referencing an undeclared variable
isset($some); // false
$some = 'hello';
// Declared but has no depth(not an array)
isset($some); // true
isset($some['nested']); // false
$some = ['nested' => 'hello'];
// Declared as an array but not with the depth we're testing for
isset($some['nested']); // true
isset($some['nested']['deeper']); // false
JS
W JavaScript nie mamy tej swobody, zawsze otrzymamy błąd, jeśli zrobimy to samo, ponieważ JS natychmiast próbuje uzyskać dostęp do wartości, deeper
zanim będziemy mogli zawinąć ją w naszą isset()
funkcję, aby ...
// Common pitfall answer(ES6 arrow function)
const isset = (ref) => typeof ref !== 'undefined'
// Same as above
function isset (ref) { return typeof ref !== 'undefined' }
// Referencing an undeclared variable will throw an error, so no luck here
isset(some) // Error: some is not defined
// Defining a simple object with no properties - so we aren't defining
// the property `nested`
let some = {}
// Simple checking if we have a declared variable
isset(some) // true
// Now trying to see if we have a top level property, still valid
isset(some.nested) // false
// But here is where things fall apart: trying to access a deep property
// of a complex object; it will throw an error
isset(some.nested.deeper) // Error: Cannot read property 'deeper' of undefined
// ^^^^^^ undefined
Więcej nieudanych alternatyw:
// Any way we attempt to access the `deeper` property of `nested` will
// throw an error
some.nested.deeper.hasOwnProperty('value') // Error
// ^^^^^^ undefined
Object.hasOwnProperty('value', some.nested.deeper) // Error
// ^^^^^^ undefined
// Same goes for typeof
typeof some.nested.deeper !== 'undefined' // Error
// ^^^^^^ undefined
I niektóre działające alternatywy, które mogą szybko stać się zbędne:
// Wrap everything in try...catch
try { isset(some.nested.deeper) } catch (e) {}
try { typeof some.nested.deeper !== 'undefined' } catch (e) {}
// Or by chaining all of the isset which can get long
isset(some) && isset(some.nested) && isset(some.nested.deeper) // false
// ^^^^^^ returns false so the next isset() is never run
Wniosek
Wszystkie pozostałe odpowiedzi - choć większość jest wykonalna ...
- Załóżmy, że sprawdzasz tylko, czy zmienna nie jest niezdefiniowana, co jest odpowiednie w niektórych przypadkach użycia, ale nadal może generować błąd
- Załóżmy, że próbujesz uzyskać dostęp tylko do właściwości najwyższego poziomu, co znowu jest w porządku w niektórych przypadkach użycia
- Zmusza cię do zastosowania mniej niż idealnego podejścia w stosunku do PHP
isset()
npisset(some, 'nested.deeper.value')
- Użyj,
eval()
który działa, ale ja osobiście go unikam
Myślę, że dużo tego omówiłem. W mojej odpowiedzi zwracam uwagę na pewne kwestie, których nie dotykam, ponieważ - choć istotne - nie są częścią pytania. W razie potrzeby mogę zaktualizować swoją odpowiedź za pomocą linków do niektórych bardziej technicznych aspektów opartych na zapotrzebowaniu.
Spędziłem nad tym dużo czasu, więc mam nadzieję, że to pomaga ludziom wyjść.
Dziękuję za przeczytanie!