还是经历的毒打不多,当一个代码执行的用户多起来时,会出现千奇百怪的Bug,比如一段《不可能出现空值》的代码,它就是出现空值了,你找谁说理去,唯一的解释就是离谱的《用户卡顿》,卡掉了一段代码执行,当时组里的人都说这《不可能》,但是错误上报就是出现了啊,没法解释,加上 if (a) 就是好使,就不报错了,明明上一个函数必然会给 a 赋值,但是线上错误就是说 a 是空,没办法!
那我大概说下“!”这约束它的使用方式吧,不可能官方闲的蛋疼专门写这东西,然后特殊说明一下,仅限严格模式环境,不严格模式完全没意义。
附1:首先补充下上面楼层没说到的,对于构造函数中赋值的变量,在声明时是不需要“!”的,也就是说“!”的意义在于“对于非构造初始化变量,标记其在对象有效期内是有值的”。
1、外部系统赋值:
像cocos这个就很常见了:“@property(cc.Node) ndReward: cc.Node = null!”,首先不赋值的话编辑器会警告,所以一般对于对象都是初始化为null,然后在严格模式下这种写法是不安全的,因此需要加个“!”,用来提醒它是一定会在外部赋值的,不会为空,这是它的存在意义之一;
当然也有允许为空的属性,但这不是“!”需要关注的对象;
2、非构造函数赋值:
(1)内置一个初始化函数,由外部来调用(例如UI根节点调用子节点的脚本),本质跟1无区别,只是写法上的不同;
(2)有效的生命周期函数赋值,这种翻开cocos官方的脚本就能见了,其很多内置属性都是在onLoad或onEnable时候才赋值的(实际不一定是这函数哈,只是说到了这个周期时),也就是说处于“活跃”或者说“有效”状态的对象才有值的属性,我们也可以用“!”来标记,当然啦官方源码还是会判断这类对象存不存在的,只是说我们能这么去声明处于活跃周期内的属性加个“!”;
附2:严格模式的意义,更多的是在js这种弱语言环境减少更多的类型错误、空对象错误,虽说写起来是挺复杂挺麻烦的,但有时候你要检验一个稍微复杂点的函数里面代码写的有没有问题时,不妨打开一下,你会发现不一样的东西,所以没有什么东西是没意义的,存在就有它特定的环境去使用。
这种千奇百怪的问题出现后去处理,处理不了就打补丁,所有地方都做兜底确实可以避免突发情况,但也会掩盖很多会报错的地方,导致Bug堆积
这个回答可以说是很到位了
1、不管数据来源,该判空就判空(关键有时候判空也判断不住)。(没有一定不为空的,所以!这个绝大多数情况可以,特殊情况不行。明明不为空,万分肯定不为空,但是就是为空了。比如多次引用后,别的地方已经置空了,指针二次悬挂等等。已经完犊子了,只能靠下面的2兜底了。)
2、需要有容错机制,程序不能崩溃,卡屏,卡顿等。异常上报日志,邮件或者ftp
3、程序上线后,出问题了,半夜给你打电话了,起来解决不?(关机?第二天会挨批。)
4、为了程序高质量,代码健壮性,无可厚非,但要注意方式方法,尽量做到用户无感。我是用bug上传ftp(有相当的代码调用堆栈,变量数据,所处线程,当前环境等等。大错误还会截屏,截图),遇到问题解决问题。
高质量代码是慢慢熬出来的。
我们只是程序员,打工的,偶尔半夜起来拼命可以。出现问题了,可以解决,等有空了,等上班了。吾辈已经落发了,不该再折寿了。
追求不一样,我理解你
其实 ts 存在的意义就是帮助程序能够静态分析代码中存在的潜在问题,ts 的类型系统本身是不会存在于运行时的(除了一些语法糖可能会影响编译结果之外)
严格遵循 ts 的类型规范,不能说解决全部问题,起码能解决 70%-80%
你总是期望问题在运行时去解决,那么 ts 对你来说意义不大,更适合用 js
另外依赖运行时发现问题,我觉得是不可靠的;代码中总会有一些特定条件下,运行才触达的地方,这就严重依赖测试时将所有情况都考虑到,不是很现实
我并没有说什么东西都放在运行时去解决,用ts就是编译前尽量排查掉错误,这些都没问题。
刚才只是讨论无意义的非法判断问题,以及严格模式的优缺点评估。
我遇到的一些情况是这样的,同一个模块,可能维护的人有好几个,你认为是非空不需要判断的变量,换成别人就不一定会知道,除非能做好沟通,那就没问题的
很多时候引入问题的不是你,是另一个不知道具体实现的维护者,因为缺乏代码提示作为约束
最重要的是,老板看到报错了,正好你是模块的维护者,那不得抓你来看看问题 
按这个逻辑严格模式的类型提示也没用,并不能保证不会因为类型报错。说到底就是个代码提示,提示你这个变量可能为空而已,非空断言类似类型断言只是一种简化代码的手段,健壮性肯定不如多加判断或者所谓的控制变量来源的合法性,但是实践中就是有人需要这个代码提示,并且根据提示做对应的处理。
其实说简单点,!只是严格模式的一个逻辑补充,因为有些地方已经是确定了不可能为空,就是你100%确定了不可能为空,但是因为严格模式一定要你判断非空会报错,这个时候就需要一个断言,所谓断言的含义是啥,就是肯定,肯定不为空,所以让编辑器不要报错,其实非空断言的意义就是严格模式智障的补充。
所以严格模式下,非空断言肯定有意义,因为非空断言就是100%不可能为空的时候才用,所以不存在你说的那种有错就让它报错的可能性,只不过很多人用的时候自己都不能100%确定不为空就用了非空断言所以才报错了。
就是因为严格模式会强制做非法判断,所以我才说严格模式没意义啊
因为我的目的就是不做非法判断,这样出现异常数据才会报错,我才能及时纠错。
应该说,是否做非法判断由自己来决定,而不是强制。
因为确实有些地方是需要做非法判断的,但不影响我说严格模式没必要。
那你写感叹号,不就有报错了吗?
可能为空的对象不判断直接用,非要等跑出问题了,再来加个判断?然后觉得自己改了个BUG?
我说的是非法判断,不是非空判断
空 不等于 非法,如果空是允许的,就要处理非空的情况。
为什么我要提这个思路,因为明明数据非法了,你加了判断就不报错了。
但这里只是不报错,产生非法数据的源头依然存在。
我的目的是让他报错,我才能排查为什么这里数据会非法。
那严格模式不是更直接就提示你了有这个“非法数据的源头”?
对非法判断,那就是说明逻辑上就允许这个变量可能是非法的。
编译的时候你就知道可能有错误,然后去改。和你运行时等待这个可能出现的报错,然后去改。那个更好?
把设计语言的人给我找来,我倒希望他能说服我
那你怎么定义 “非法”,本来应该传 number 的,现在传了 string,算不算非法,js 会自动转类型,你能及时纠错吗
本来应该传 number 的,现在传了 undefined 不是一个道理吗
undefined 本身就是类型的一部分,没什么特别的
ts里你定义了number类型,传string本来就会报错啊,当然能及时纠错
本来传number的,如果传undefined,取决于你是否允许这里填undefined
如果允许,你应该要写if(xxx===undefined){相应的处理逻辑;return;},这样undefined就是合法的
如果不允许,这里传入undefined就必须让他报错。
因为这里undefined非法却传入了undefined,你要检查这个undefined是哪里来的,而不是这里加非法判断让他不报错

