YUI3的沙箱机制
2010-4-10
YUI2
在YUI2.x里,每一个模块功能的引入都会直接添加在全局的YAHOO里,例如dom.js里:
var Y = YAHOO.util; Y.Dom = {...}
这样在整个页面范围内,YAHOO.util里就多了一个功能Dom。
YUI3-add()
在YUI3里,每一个模块引入时并没有把功能直接添加到全局的YUI里,看看YUI3里的dom.js:
YUI.add('dom-base', function(Y) { //在这里添加dom方法 Y.DOM = { ... } ... }, '3.0.0' );
再看看yui.js里add的源码:
add: function(name, fn, version, details) { YUI.Env.mods[name] = { name: name, fn: fn, version: version, details: details || {} }; return this; // chain support }
所以YUI3里引入每个模块时只是把这个模块的内容储存在YUI.Evn.mods里。
YUI3-use()
需要使用某个模块时,在创建YUI实例以后,用use取出来执行模块里的程序,为这个YUI实例添加相应的方法:
YUI().use('dom-base', function(Y) { //这里可以用到模块dom-base里对YUI添加的方法Y.DOM alert(Y.DOM) //[object object] })
而在同一个页面里,YUI实例里如果没有指明use(‘dom-base’),就没有Y.DOM这个方法
YUI().use('', function(Y) { alert(Y.DOM) //undefined })
沙箱
这里YUI().use(”,function(Y){…})就是一个安全沙箱,可以确保这里面的Y是纯天然无污染的,Y实例里有什么功能完全取决于use里传进的模块名称,function(Y){}里面的程序跟外界是隔离的,在里面创建的变量(除了全局变量)以及对YUI的添加修改都不会影响到同个页面上其他人写的程序。
但是这个纯天然无污染是有点代价的,就是每次都要新建一个YUI实例,消耗内存,但如果不怕Y被污染,可以不每次都创建实例:
var Y = YUI(); Y.use('dom-base', function(Y) { //可以同时使用dom-base和oop模块里添加的方法 }); Y.use('oop', function(Y) { //可以同时使用dom-base和oop模块里添加的方法 });
add()和use()配合一些参数(例如require)和YUI Loader就成了YUI3模块化编程的基础。
最简化的YUI沙箱
去除了YUI Loader以及require等参数,参考自这里
if (typeof YUI === 'undefined' || !YUI) { YUI = function() { var Y = this; if (!(Y instanceof YUI)) { return new YUI(); } else { Y._init(); return Y; } }; } //保存mod列表的静态属性 YUI.Env = { mods: {} }; (function() { var SLICE = Array.prototype.slice; YUI.prototype = { _init: function() { var Y = this, G_Env = YUI.Env, Env = Y.Env; if(!Env) { Y.Env = { mods: {}, _used: {}, _attached: {} }; Env = Y.Env; } Y.constructor = YUI; }, add: function(name, fn, details) { YUI.Env.mods[name] = { name: name, fn: fn, details: details || {} }; return this; // chain support }, _attach: function(r) { var mods = YUI.Env.mods, Y = this, attached = Y.Env._attached, i, l = r.length, name, m, fn, d; for (i = 0; i < l; i = i+1) { name = r[i]; m = mods[name]; if (!attached[name] && m) { attached[name] = true; fn = m.fn; d = m.details; if (fn) { fn(Y); } } } }, use: function() { var Y = this, a = SLICE.call(arguments, 0), mods = YUI.Env.mods, used = Y.Env._used, callback = a[a.length-1], i, l, r = [], process = function(name) { // 添加模块至附加的模块列表 r.push(name); // 一个模块仅附加一次 if (used[name]) { return; } var m = mods[name]; if (m) { used[name] = true; } }, onComplete; if (typeof callback === 'function') { a.pop(); } else { callback = null; } l = a.length; for (i = 0; i < l; i = i + 1) { process(a[i]); } Y._attach(r); if (callback) { callback(Y); } return Y; // chain support } }; })(); YUI().add('test',function(){document.write("<p>test module add() excute</p>")}); YUI().use('test',function(){document.write("<p>test module has executed completely.</p>")});
推特中文圈是不是被墙奸了。无法使用了?