使用javascript在浏览器中编程时限制副作用非常棘手。
我可以做一些事情,比如不要像在这个愚蠢的例子中那样访问成员变量:
let number = 0;
const inc = (n) => {
number = number + n;
return number;
};
console.log(inc(1)); //=> 1
console.log(inc(1)); //=> 2
但是我可以做些什么来减少我的javascript中的副作用?
答案 0 :(得分:9)
当然,您可以通过仔细编程来避免副作用。我假设你的问题是如何阻止他们。你这样做的能力受到语言本质的严重限制。以下是一些方法:
使用网络工作者。见MDN。 Web worker在另一个与当前窗口不同的全局上下文中运行。:
隔离 iframe 中的某些逻辑。使用cross-window messaging与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
锁定对象。同样,使用带有getter但没有setter的Object.defineProperty
创建对象的只读属性,或者将writeable
属性设置为false
。
使用 Object.observe 获取有关对象及其属性的各种类型更改的异步报告,您可以在其上抛出错误或采取其他操作。
如果可以,请使用 Proxy 来完全控制对对象的访问。
有关阻止访问window
的注意事项,请参阅javascript sandbox a module to prevent reference to Window。 http://dean.edwards.name/weblog/2006/11/sandbox/也是Semi-sandboxing Javascript eval。最后,django-storages。
区分内向副作用和外向副作用是有用的。向内的副作用是其他一些代码侵入我的组件状态的地方。向外的副作用是我的代码侵入其他组件的状态。通过其他答案中提到的IIFE或ES6模块可以防止内向副作用。但更严重的问题是外部副作用,这需要采用上述方法之一。
答案 1 :(得分:4)
在我的脑海里想到你的问题是什么:
“通过将全局覆盖面减少到一个名称,可以显着降低与其他应用程序,小部件或库进行错误交互的可能性。” - 道格拉斯·克罗克福德
使用分号
评论部分of this article为使用分号提供了一些好的(现实生活)理由。
不要声明字符串,数字或布尔对象
(如果你曾经想过的话)
var m = new Number(2);
var n = 2;
m === n; // will be false because n is a Number and m is an object
“使用严格”; 是您的朋友。启用严格模式是一个好主意,但请不要将其添加到现有代码中,因为它可能会破坏某些内容而您无法仅在词法范围或单个脚本上声明严格as stated here
首先声明变量。一个常见的副作用是人们不了解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...
}
}
Here讨论了提升实际意味着什么,以及它可能带来什么样的“意外行为”。
使用'==='代替'=='。这有很多很好的理由,这是JavaScript中最常见的“副作用”或“错误”之一。 有关详细信息,请参阅此great answer on SO,但让我快速演示一下:
'' == '0' // false
0 == '' // true
// can be avoided by using '==='
'' === '0' // false
0 === '' // false
使用IIFE 。 IIFE(立即调用函数表达式)允许您声明一个将调用自身的匿名函数。这样您就可以创建一个新的词法范围,而不必担心全局命名空间。
小心原型。请记住,同一类的JavaScript对象共享相同的原型。更改原型意味着更改类的所有实例的行为。 (即使是其他脚本/框架使用的那些)也发生了here
Object.prototype.foo = function(){...} // careful!
这些是我想到的“副作用”。当然还有更多需要处理的方法(有意义的变量名称,一致的代码风格等......)但我并不认为这些东西是“副作用”,因为它们会使代码难以维护,但不会破坏它立即。
答案 2 :(得分:2)
我最喜欢的技巧是使用一种语言来编译到 javascript,而不是使用javascript。
但是,你可以做两件重要的技巧:
"use strict";
启动您的文件。这将启用代码验证并防止使用未声明的变量。是的,这是一个特殊的字符串,浏览器将知道如何处理。(function() { })();
。正常的CS基础知识也适用:将代码分成逻辑部分,正确命名变量,在需要时始终显式初始化变量等等。