由JavaScript的作用域说开去
首先,以下提到的高级语言,指非脚本,强类型语言。
一般某语言在介绍自己的作用域时,都会有全局变量,局部变量之分。高级语言代码运行域有进程<应用程序域<程序集<对象。js脚本与之类比,则运行空间有浏览器进程>js代码所在页面>对象。当我们通过iframe,或者弹出新窗口,子窗口和父窗口互相操作时,在窗口未关闭的状态下,js的作用域可以扩大到所有激活窗口(不含其他网站(域)的页面)。其他窗口的js对象,这时候,通过引用,就好像是自己本地对象一样。对象的属性,方法均可访问调用。但是,一旦被引用的对象所在窗口被关闭,则属性和方法仅能访问,方法不能执行。若是不小心执行了方法,会有“不能执行已释放Script的代码”的错误报出。这是因为值传递,引用传递的不同引起的。页面关闭,方法所指向的内存地址已被回收。
这里想讨论的是一个设计原则的问题。考虑一个这样的场景:一个复杂交互运用,好几个页面才能完成,一份js对象在各页面跳转。按惯有的高级语言编写习惯,可能是,只要是能访问,就能对其属性修改,方法执行。不幸的情况下,对象的属性也是一个对象,而这个属性,突然在别的页面被赋予一个新new出来的东西,然后,别的页面被关闭,新对象随着属性被带离到另个页面。随之,域的问题就爆发了。
这是一个写惯了高级语言,转而需要在b端写些复杂js交互脚本的人容易掉进的陷阱。只要明白了问题所在,药方应该有千千万。我想提出讨论的是,我们要不要遵循一条这样的原则,页面间在源头上就隔离引用传递。在新开窗口时,就不要输送对象给新窗口,或者在iframe页,遵守不调用父页对象,不给父页调用自己对象。把新窗口,看做一个封闭性很好的对象,只给它值传递,不给引用传递。这个对象只提供放回值的属性,方法,自己方法内,绝不修改外部对象的值。这些也是高级语言里面的规则,一般由于高级语言有很好的封装性,由不得乱来,所以很好遵循这些原则。而js脚本语言,要实现这些封装性,需要很好的技巧,最终也很难达到高级语言的封装性。不过,在写这些脚本的时候,刻意记得去遵循这邪恶原则,还是可以实现的,也并不需要很好的技巧,只需要小心和耐心。
偶有感,欢迎指正。