沙箱模式又称为沙盒模式或者隔离模式
那么什么是沙箱模式呢?
将代码与外界隔离,不管你在里面做什么,都不会污染到全局变量.
沙箱模式的语法结构:
(function () {
})();
沙箱的应用:
1.模拟块级作用域
2.所有的封装的框架都是在沙箱模式中完成
思考?
1.沙箱模式是一种自调用函数那么为什么一定要是自调用函数?
如果需要让代码既能调用又要隔离,就需要一个函数的调用结构
如果不用自调用函数,会造成全局变量污染
能执行,不污染,隔离
基于这个特点有一个非常重要的应用,模拟块级作用域
2.隔离的效果是什么?
使用沙箱后,在内部定义的代码,访问数据,在沙箱内部是一个完整的生态链,
如果要声明多个数据在沙箱中也不会出现污染全局的问题
案例
定义一个数组,数组里面是对象,然后通过for循环给数组里的每一个对象添加一个sayHello方法,最后打印结果
var arr = [{ name:'jim'},
{ name :'tom'},
{name:'jack'},
{name:'clark'}];
for (var i = 0;i<arr.length;i++){
arr[i].sayHello = function() {
console.log(arr[i].name);
};
}
for (var k in arr){
arr[k].sayHello();
}
for in循环,k是键存放的是索引,
如果是对象的话得到的每一个索引的名字
如果是数组的话得到就是索引
这里等价于
arr[0].sayHello();
arr[1].sayHello();
arr[2].sayHello();
这里调用sayHello方法执行的是sayHello = function() //{ console.log(arr[i].name)};根据词法作用域,i上下文中没有定义,去上一层找,只有函数才有作用域,所以它的上一级在全局范围内,i的值经过循环最大值是4,数组长度是4,索引值最大是3,所以得到的结果是一个undefined,就会报一个错,不能找到undefined的name属性
解决办法1:
把k改成i就可以了
for (var i in arr){
arr[i].sayHello();
}
因为这样等价于
i = 0
arr[0].sayHello();
i =1
arr[1].sayHello();
i = 2
arr[2].sayHello();
因为for in需要把数组里这个所以赋值给变量i
所以用k改成i就能成功了,但是在这里面说明一个问题,这个for循环不具备块级作用域
解决办法2:
如果把这个for循环放到一个沙箱当中
(function (){
for (var i = 0; i< arr.length;i++){
arr[i].sayHello = function() {
console.log(this.name)
}
}
})();
for (var i in arr){
arr[i].sayHello();
}
代码从上往下执行,沙箱是自调用的,当代码走完的时候其实函数的for循环也执行完了,所以对程序的运行程序没有影响
这时候执行问题就解决了,
好处是函数才能访问作用域,外面访问不到i,有了沙箱模式后就可以模拟块级作用域了
利用沙箱隔离,再举一个例子
用面向对象获取标签
var id= function ( idName){
retrun document.getElementById( idName );
};
var cName = function (cName){
retrun document.getElemntsByclassName( cName );
}
这样写会造成全局变量污染
为了解决这个问题可以封装成对象里面
把这个方法变成键值对
var obj = {
id:function ( idName){
retrun document.getElementById( idNa
me );
},
cName:function (cName){
retrun document.getElemntsByclassName( cName );
}
};
但这样只是减少了污染,只污染了一个对象,
还有就是无法复用
如果封装构造函数,又会引起多个污染
(function (){
function test() {};
test.prototype.extend = function () {};
//...
//完成以后
window.$ = window.jQuery = test;
//window是全局变量,给全局变量价格$,加个jQuery
//同时等于test
})();
离开沙箱之后可以直接用$或者jQuery来调用
关于沙箱的复用
复用 体现在两个方面
1.对象->得到一个新对象
2.函数-> 创建新对象,反复调用
var o = {name:'jim',age:19};
(function (window) {
var f = function(name,age){
this._name = name;
this._age = age;
};
f.prototype = new Foo();
function Foo() {}
window.f = f;
})(window);
var o1 = new f('jim',19);
var o2 = new f('tom',119);
1.提高性能
如果不把window作为参数传进来的话,那么它就会在当前作用域找,看有没有,没有就到上面去找,如果框架里需要频繁用到window的话,那么就要用一次找一次,非常影响性能,所以把window传进去就不用到外面找了,到当前作用域里面找,提高性能
2.代码压缩
如果不传参数window,不能进行压缩,穿参之后,就能进行压缩,节省很多字节
(ps:这里的window不是固定的)
沙箱模式的优势:
完全将代码隔离开,在沙箱内部是一个独立的结构,允许根据需要使用各种各样的代码,然后将需要对外公开的代码返回来
不会污染到全局变量,构造函数的复用,添加原型等等都可以在
沙箱内实现