闭包的形成与变量的作用域和变量的生命周期有关
var func = function () {
var a = 1;
console.log(a);
};
func(); //1
console.log(a); //ReferenceError: a is not defined
作用域的面试题
var func1 = function () {
var b = 2;
var func2 = function () {
var c = 3;
console.log(b); //2
console.log(a); //1
};
func2();
console.log(c); //c is not defined
};
func1();
经典的闭包面试题2
var nodes = document.getElementsByTagName('div');
for (var i = 0, len = nodes.length; i < len; i++) {
(function (i) {
console.log(i, 'i')
nodes[i].onclick = function () {
console.log(i); //0 1 2 3 4
}
})(i)
};
可以看到用了自执行的闭包函数后,我们打印出的就是想要 的效果了
判断数据类型的工具方法
var Type = {};
for (var i = 0, type; (type = ["String", "Array", "Number"][i++]); ) {
(function (type) {
Type["is" + type] = function (obj) {
return Object.prototype.toString.call(obj) == `[object ${type}]`;
};
})(type);
}
console.log(Type.isArray([]));
console.log(Type.isString("str"));
//版本1;声明一个私有变量
var mult = function () {
var a = 1;
for (var i = 0; i < arguments.length; i++) {
a *= arguments[i];
}
return a;
};
console.log(mult(1, 2, 3));
//版本2;避免相同的参数的重复计算,利用对象的key值的唯一性进行判断
var cache = {};
var mult1 = function () {
var args = [].join.call(arguments, "-");
console.log(args);
if (cache[args]) {
return cache[args];
}
var a = 1;
for (var i = 0; i < arguments.length; i++) {
a *= arguments[i];
}
return (cache[args] = a);
};
console.log(mult1(1, 2, 9), "----");
console.log(mult1(1, 2, 9), "----");
//版本3;将cache生命在闭包内部,避免全局污染
var mult3 = (function () {
var cache = {};
return function () {
var args = [].join.call(arguments, "-");
console.log(args);
if (cache[args]) {
return cache[args];
}
var a = 1;
for (var i = 0; i < arguments.length; i++) {
a *= arguments[i];
}
return (cache[args] = a);
};
})();
console.log(mult3(2, 3, 4));
console.log(mult3(2, 3, 4));
//版本4,函数的提炼
var mult4 = (function () {
var cache = {};
var calculate = function () {
var a = 1;
for (var i = 0; i < arguments.length; i++) {
a *= arguments[i];
}
return a;
};
return function () {
var args = [].join.call(arguments, "-");
console.log(args);
if (cache[args]) {
return cache[args];
}
// calculate.call(null, arguments);
return (cache[args] = calculate.apply(null, arguments));
};
})();
console.log(mult4(5, 3, 4));
console.log(mult4(5, 3, 4));
//图片上报的数据丢失,函数执行完成后img会被销毁,而此时的ajax请求可能还未执行
var report = function (src) {
var img = new Image();
img.src = src;
};
report("xxxxxxxxxx");
var report2 = (function () {
var imgs = [];
return function (src) {
var img = new Image();
img.src = src;
imgs.push(img);
};
})();
//过程与数据的结合是形容面向对象的"对象"时经常使用的表达
//对象以方法的形式包含了过程,而闭包则是在过程了以环境的
//形式包含了数据
var extent = function () {
var value = 0;
return {
call1: function () {
value++;
console.log(value, "aaaa");
},
};
};
var e = extent();
e.call1(); //1 aaaa
e.call1(); //2 aaaa
e.call1(); //3 aaaa
//版本1,改成面向对象的形式
var test = {
value: 0,
call1() {
this.value++;
console.log(this.value, "++++");
},
};
test.call1();
test.call1();
test.call1();
//版本2
var Extent = function () {
this.value = 0;
};
Extent.prototype.call1 = function () {
this.value++;
console.log(this.value, "构造函数");
};
let test2 = new Extent();
test2.call1();
test2.call1();
test2.call1();
<div class="btns">
<button id="excute">打开电视机</button>
<button id="undo">关闭电视机</button>
</div>
//面向对象的思想是做什么怎么做,和谁做要分开,进行抽象
var Tv = {
open() {
alert("打开电视机")
},
close() {
alert('关闭电视机')
}
}
//声明了一个命令,包含各种方法,把目标对象传进去
var OpenCommand = function (receiver) {
this.receiver = receiver
}
OpenCommand.prototype.excute = function () {
this.receiver.open()
}
OpenCommand.prototype.close = function () {
this.receiver.close()
}
//在这个命令方法里面,配置好各种对应的执行命令
var setCommand = function (command) {
document.getElementById('excute').onclick = function () {
command.excute()
}
document.getElementById('undo').onclick = function () {
command.close()
}
}
setCommand(new OpenCommand(Tv))
这样就实现了我们的命令模式
//版本2,用闭包的方式实现命令模式
//显然比面向对象的更精简
var createCommand = function (receiver) {
var excute = function () {
receiver.open()
}
var undo = function () {
receiver.close()
}
return {
excute, undo
}
}
var setCommand = function (command) {
document.getElementById('excute').onclick = function () {
command.excute()
}
document.getElementById('undo').onclick = function () {
command.undo()
}
}
setCommand(createCommand(Tv))
//版本1
var appendDiv = function () {
for (var i = 0; i < 100; i++) {
var div = document.createElement('div')
div.innerHTML = i
document.body.appendChild(div)
div.style.display = "none"
}
}
//版本2
var appendDiv = function (cb) {
for (var i = 0; i < 100; i++) {
var div = document.createElement('div')
div.innerHTML = i
document.body.appendChild(div)
if (typeof cb == 'function') {
cb(div)
}
}
}
appendDiv() //div未被隐藏
appendDiv(function (node) { //div被隐藏
node.style.display = 'none'
})
//单例模式
var getSingle = function (fn) {
var ret;
return function () {
return (ret = fn.apply(this, arguments));
};
};
getSingle(function () {
return document.createElement("script");
});
var s1 = getSingle()
var s2 = getSingle()
console.log(s1 == s2, '000');
//AOP面向切面编程,是吧一些与核心业务无关的代码抽离出来
//根据需要再动态的加入
//下面是使用方法
Function.prototype.before = function (fn) {
var _self = this;
return function () {
fn.apply(null, arguments);
return _self.apply(null, arguments);
};
};
Function.prototype.before = function (fn) {
var _self = this;
return function () {
let ret = _self.apply(null, arguments);
fn.apply(null, arguments);
return ret;
};
};
var func = function () {
console.log("我是本来要执行的");
};
func = func
.before(function () {
console.log("我是插入进来的,需要提前执行");
})
.before(function () {
console.log("我是需要在最后执行的");
});
func();
//函数节流 触发的频率太高了 window.resize docment.onmousemove
//函数节流的实现
var throttle = function (fn, interval) {
var _self = fn,
timer,
firstTime = true;
return function () {
var args = arguments,
_me = this;
if (firstTime) {
_self.apply(_me, args);
return (firstTime = false);
}
if (timer) {
return false;
}
timer = setTimeout(() => {
clearTimeout();
timer = null;
_self.apply(_me, args);
}, interval || 500);
};
};
window.onresize = throttle(function () { console.log(1) }, 400)
window.onresize = function () { console.log(1) }
//分批加载数据
var ary = []
for (var i = 0; i < 1000; i++) {
ary.push(i)
}
//版本1 一次性加载1000数据
var renderList = function (data) {
for (var i = 0, l = data; i < l.length; i++) {
var div = document.createElement('div')
div.innerHTML = i
document.body.appendChild(div)
}
}
let r1 = console.time()
// renderList(ary)
let r2 = console.timeEnd()
//版本2 每次只加载8条数据
var timeChunk = function (ary, fn, count = 1) {
var obj, t, len = ary.length
var start = function () {
for (var i = 0; i < Math.min(count, ary.length); i++) {
var obj = ary.shift()
fn(obj)
}
}
return function () {
t = setInterval(() => {
if (ary.length == 0) {
return clearInterval(t)
}
start()
}, 200);
}
}
var renderList2 = timeChunk(ary, function (data) {
var div = document.createElement('div')
div.innerHTML = data
document.body.appendChild(div)
}, 8)
renderList2()
```