Segmento antigo, mas há novas maneiras de executar um equivalente isset()
.
ESNext (Etapa 4 de dezembro de 2019)
Duas novas sintaxes nos permitem simplificar amplamente o uso da isset()
funcionalidade:
Leia os documentos e lembre-se da compatibilidade do navegador.
Resposta Anterior
Veja abaixo a explicação. Nota Eu uso a sintaxe StandardJS
Exemplo de uso
// 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
Função de resposta
/**
* 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
}
}
Explicação
PHP
Observe que no PHP você pode fazer referência a qualquer variável a qualquer profundidade - mesmo tentando acessar um não array, pois um array retornará um simples true
ou 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
Em JavaScript, não temos essa liberdade, sempre obteremos um erro se fizermos o mesmo, porque JS está tentando acessar imediatamente o valor de deeper
antes de podermos envolvê-lo em nossa isset()
função para ...
// 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
Mais alternativas com falha:
// 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
E algumas alternativas de trabalho que podem ser redundantes rapidamente:
// 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
Conclusão
Todas as outras respostas - embora a maioria seja viável ...
- Suponha que você esteja apenas verificando se a variável não está indefinida, o que é bom para alguns casos de uso, mas ainda pode gerar um erro
- Suponha que você esteja apenas tentando acessar uma propriedade de nível superior, o que novamente é bom para alguns casos de uso
- Forçar você a usar uma abordagem abaixo do ideal em relação ao PHP,
isset()
por exemploisset(some, 'nested.deeper.value')
- Uso
eval()
que funciona, mas eu pessoalmente evito
Eu acho que cobri muito disso. Há alguns pontos que afirmo em minha resposta que não menciono, porque eles - embora relevantes - não fazem parte da pergunta. Se necessário, posso atualizar minha resposta com links para alguns dos aspectos mais técnicos com base na demanda.
Passei muito tempo nisso, espero que ajude as pessoas.
Obrigado pela leitura!