使用javascript在浏览器中编程时限制副作用非常棘手。
我可以做一些事情,比如不访问成员变量,就像这个愚蠢的例子:
let number = 0;
const inc = (n) => {
number = number + n;
return number;
};
console.log(inc(1)); //=> 1
console.log(inc(1)); //=> 2
但是我可以做些什么来减少我的javascript中的副作用?
使用javascript在浏览器中编程时限制副作用非常棘手。
我可以做一些事情,比如不访问成员变量,就像这个愚蠢的例子:
let number = 0;
const inc = (n) => {
number = number + n;
return number;
};
console.log(inc(1)); //=> 1
console.log(inc(1)); //=> 2
但是我可以做些什么来减少我的javascript中的副作用?
当然,您可以通过仔细编程来避免副作用。我假设你的问题是关于如何做的 避免 他们。你这样做的能力受到语言本质的严重限制。以下是一些方法:
使用 网络工作者。看到 MDN。 Web worker在另一个与当前窗口不同的全局上下文中运行:
隔离某些逻辑内部 I帧。使用 跨窗口消息传递 与iframe沟通。
不变性库。看到 https://github.com/facebook/immutable-js。也 http://bahmutov.calepin.co/avoid-side-effects-with-immutable-data-structures.html。
锁定你的物体 同 Object.freeze
, Object.seal
, 要么 Object.preventExtensions
。同样,使用创建对象的只读属性 Object.defineProperty
有吸气剂,但没有安装者,或与 writeable
属性设置为 false
。
使用 Object.observe 获取对象及其属性的各种类型更改的异步报告,您可以在其上抛出错误或采取其他操作。
如果可用,请使用 代理 用于完全控制对对象的访问。
有关阻止访问的注意事项 window
,见 javascript沙箱一个模块,以防止引用Window。也 http://dean.edwards.name/weblog/2006/11/sandbox/。最后, 半沙盒Javascript评估。
区分内向副作用和外向副作用是有用的。向内的副作用是一些其他代码侵入我的组件的状态。向外的副作用是我的代码侵入其他组件的状态。通过其他答案中提到的IIFE或ES6模块可以防止内向副作用。但更严重的问题是外部副作用,这需要采用上述方法之一。
想到你的问题,我想到了什么:
“通过将全球足迹减少到一个名称,您可以显着降低与其他应用程序,小部件或库进行错误交互的可能性。” - 道格拉斯·克罗克福德
使用分号
评论部分 这篇文章 为一直使用分号提供了一些好的(现实生活)理由。
不要声明String,Number或Boolean对象
(万一你有诱惑)
var m = new Number(2);
var n = 2;
m === n; // will be false because n is a Number and m is an object
“严格使用”; 是你的朋友。启用严格模式是一个好主意,但是请不要将它添加到现有代码中,因为它可能会破坏某些内容并且您无法仅在词法范围或单个脚本上声明严格 如此处所述
首先声明变量。 一个常见的副作用是人们不了解JavaScript的吊装。提升会在块中搜索变量声明,并将它们一起移动到块的顶部。
function(){
var x = 3;
// visible variables at runtime at this point: x,y,i !
// some code....
var y = 1; // y will be moved to top!
for( var i = 0; i < 10; i++ ){ // i will be moved to top!
// some code...
}
}
这里 讨论了吊装实际意味着什么,以及它可能导致什么样的“意外行为”。
使用'==='而不是'=='。这有很多很好的理由,这是JavaScript中最常见的“副作用”或“错误”之一。 有关详细信息,请参阅此 关于SO的好答案,但是让我给你一个快速演示:
'' == '0' // false
0 == '' // true
// can be avoided by using '==='
'' === '0' // false
0 === '' // false
利用IIFE。 IIFE(立即调用函数表达式)允许您声明将调用自身的匿名函数。这样您就可以创建一个新的词法范围,而不必担心全局命名空间。
小心原型。请记住,同一类的JavaScript对象共享相同的原型。改变原型意味着改变原型的行为 所有 班级的实例。 (甚至那些被其他脚本/框架使用的)就像它发生的那样 这里
Object.prototype.foo = function(){...} // careful!
这些是我脑海中浮现的“副作用”。当然还有更多的方法需要处理(有意义的变量名称,一致的代码风格等......)但我不认为这些东西是“副作用”,因为它们会使代码难以维护,但不会破坏它立刻。
我最喜欢的技巧是使用编译的语言 至 javascript,而不是使用JavaScript。
但是,你可以做两件重要的技巧:
"use strict";
。这将打开您的代码验证并防止使用未声明的变量。是的,这是一个特殊的字符串,浏览器将知道如何处理。(function() { })();
在你的肌肉记忆中。正常的CS基础知识也适用:将代码分成逻辑部分,正确命名变量,在需要时始终显式初始化变量等。