var V8Engine = (function () {
function V8Engine () {}
V8Engine.prototype.toString = function () { return 'V8' }
return V8Engine
}())
var V6Engine = (function () {
function V6Engine () {}
V6Engine.prototype = V8Engine.prototype // <---- side effect
V6Engine.prototype.toString = function () { return 'V6' }
return V6Engine
}())
console.log(new V8Engine().toString())
贡献者: V6Engine虽然没有被使用,但是它修改了V8Engine原型链上的属性,这就产生副作用了。你看 rollup(楼主特意注明截至当时)目前就是这样的策略,直接把V6Engine 给删了,其实是不对的。
楼主以及一些路人甲乙丙丁,纷纷提出自己的建议与方案。最终定下,可以在代码上通过/*@__PURE__*/这样的注释声明此函数无副作用。
这个issue信息量比较大,也挺有意思,其中那位uglify贡献者kzc,当时提出rollup存在的问题后还给rollup提了issue,rollup认为问题不大不紧急,这位贡献者还顺手给rollup提了个PR,解决了问题。。。
我再从这个issue中总结下几点关键信息:
函数的参数若是引用类型,对于它属性的操作,都是有可能会产生副作用的。因为首先它是引用类型,对它属性的任何修改其实都是改变了函数外部的数据。其次获取或修改它的属性,会触发getter或者setter,而getter、setter是不透明的,有可能会产生副作用。
uglify没有完善的程序流分析。它可以简单的判断变量后续是否被引用、修改,但是不能判断一个变量完整的修改过程,不知道它是否已经指向了外部变量,所以很多有可能会产生副作用的代码,都只能保守的不删除。
rollup有程序流分析的功能,可以更好的判断代码是否真正会产生副作用。
有的同学可能会想,连获取对象的属性也会产生副作用导致不能删除代码,这也太过分了吧!事实还真是如此,我再贴个示例演示一下: 传送门
代码如下:
// maths.js
export function square ( x ) {
return x.a
}
square({ a: 123 })
export function cube ( x ) {
return x * x * x;
} //main.js
import { cube } from './maths.js';
console.log( cube( 5 ) ); // 125
打包结果如下:
function square ( x ) {
return x.a
}
square({ a: 123 });
function cube ( x ) {
return x * x * x;
}
console.log( cube( 5 ) ); // 125
而如果将 square方法中的 return x.a改为 return x,则最终打包的结果则不会出现 square方法。当然啦,如果不在 maths.js文件中执行这个 square方法,自然也是不会在打包文件中出现它的。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-59797-4.html
但这可能也是这个运动的魅力
之后才有了现在的军舰建造狂潮