旧线程,但有新的方法来运行等效的isset()。
ESNext(2019年12月第四阶段)
两种新的语法允许我们极大地简化isset()函数的使用:
可选的链接(?)。
空合并运算符(??)
请仔细阅读文档并注意浏览器兼容性。
回答
请看下面的解释。注意我使用的是StandardJS语法
示例使用
// 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
回答函数
/**
* Checks to see if a value is set.
*
* @param {Function} accessor Function that returns our value
* @returns {Boolean} Value is not undefined or null
*/
function isset (accessor) {
try {
// Note we're seeing if the returned value of our function is not
// undefined or null
return accessor() !== undefined && accessor() !== null
} catch (e) {
// And we're able to catch the Error it would normally throw for
// referencing a property of undefined
return false
}
}
NPM的地方
这个回答函数可以在NPM上的isset-php包中找到。这个包包含了一些改进,比如类型检查和支持多参数。
npm install --save isset-php
完整的文档可以在README中找到。
const isset = require('isset-php')
let val = ''
// This will evaluate to true so the text will be printed.
if (isset(() => val)) {
console.log('This val is set so I will print.')
}
解释
PHP
请注意,在PHP中,您可以在任何深度引用任何变量——甚至可以尝试引用
将非数组作为数组访问将返回一个简单的true或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
JavaScript
在JavaScript中,我们没有这样的自由;如果这样做,总是会得到一个错误
同样,因为引擎会立即尝试访问更深的值,然后我们才能将其包装在isset()函数中,所以……
// 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
更多失败的选择:
// Any way we attempt to access the `deeper` property of `nested` will
// throw an error
some.nested.deeper.hasOwnProperty('value') // Error
// ^^^^^^ undefined
// Similar to the above but safe from objects overriding `hasOwnProperty`
Object.prototype.hasOwnProperty.call(some.nested.deeper, 'value') // Error
// ^^^^^^ undefined
// Same goes for typeof
typeof some.nested.deeper !== 'undefined' // Error
// ^^^^^^ undefined
还有一些很快就会变得多余的工作替代方案:
// Wrap everything in try...catch
try {
if (isset(some.nested.deeper)) {
// ...
}
} catch (e) {}
try {
if (some.nested.deeper !== undefined && some.nested.deeper !== null) {
// ...
}
} 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
结论
所有其他的答案——尽管大多数是可行的……
假设你只是在检查变量是否未定义
对于一些用例是好的,但仍然可以抛出一个错误
假设您只是试图访问顶级属性,同样是
对于某些用例来说很好
强制您使用相对于PHP的isset()不太理想的方法
例如isset(some, 'nested.deep .value')
使用eval(),这是有效的,但我个人避免使用
我想我已经讲过很多了。我在回答中提出了一些观点
不要触及,因为他们-虽然相关-不是的一部分
问题(如。短路)。如果需要,我可以更新我的答案与一些链接
基于需求的更多技术方面。
我在这上面花了很多时间,所以希望它能帮助到大家。
感谢您的阅读!