var a = 2
,引擎干了那些活遇见 var a,编译器会询问当前作用域是否存在该变量,存在,忽略;不存在,在当前作用域下,声明该变量,并命名为 a;
运行处理 a=2 时,引擎会询问当前作用域集合是否存在 a 的变量;存在就使用该变量,不存在继续向外层作用域查找该变量;找到了,将 2 赋值给 a,没找到,则抛出异常;
总结: 变量赋值会有两个动作,当前作用域声明该变量,查找变量,找到变量进行赋值;
LHS 和 RHS 查询:LHS 可以简单说是左侧查询,RHS 右侧查询;LHS 查询,没找到变量会创建变量,RHS 查询,没找到变量抛出异常;
function(a){
var b = a;
return a+b
}
var c = foo(2);
LHS:3
RHS:4
var a = 123;
var b = 'b1'
var fn = function () {
var b = 1;
var fn1 = function(){
var c = 'c'
console.log(c) // c
console.log(b) // 1
}
fn1();
console.log(c) // c is not defined
}
fn()
var a = null
;上面将作用域和变量生存周期简单的讲述了一下,接下来将会谈谈闭包,闭包跟这些概念非常紧密。
定义:当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行;
实例:不是闭包的例子
function foo() { var a = 2;
function bar() {
console.log( a ); // 2
}
bar();
}
foo();
实例:闭包效果的实例
function foo() {
var a = 2;
function bar() {
console.log( a ); // 2
}
return bar;
}
var baz = foo();
baz();
分析: 闭包函数外部作用域,可以访问函数内部词法作用域的变量。baz()对该作用域进行引用,这个引用就叫做闭包
为了更好的理解闭包,下面在写两个例子
实例 1:
function fo (){
var a = 2
function ba(){
console.log(a)
}
bg(ba)
}
function bg(fn){
fn() // 闭包
}
fo()
实例 2:
var bg;
function fo (){
var a = 2
function ba(){
console.log(a)
}
bg = ba;
}
function bar(){
bg() //闭包
}
fo();
bar();
分析: 总而言之,闭包能将函数内部的作用域,传递到函数外部作用域,进行引用,都会使用闭包。
var fn4 = (function(){
var cache = {};
return function(){
var args = Array.prototype.join.call(arguments, ',')
if(cache[args]){
return cache[args]
}
var a = 1;
for(var i = 0;i
Array.prototype.sort
,Array.prototype.filter
等等,都属于高阶函数var isType = function(type){
return function(obj){
return Object.prototype.toString.call(obj) === '[object '+type+']'
}
}
var isArray = function(obj){
return isType('Array').call(null, obj);
}
var isNumber = function(obj){
return isType('Number').call(null, obj)
}
AOP就是面向切面编程,把核心功能无关写逻辑抽离出来,通过动态植入方式,掺进逻辑模块中;达到模块的纯净与高内聚。
1. 示例:
Function.prototype.before = function(fn){
var that = this; // function
return function(){
fn.apply(this, arguments);
return that.apply(this,arguments)
}
}
Function.prototype.after = function(fn){
var that = this;
return function(){
var self = that.apply(this, arguments)// 执行原函数,形成链式调用
fn.apply(this, arguments) // 执行掺入函数,修正this
return self
}
}
var fng1 = function(){
console.log(1)
}
var fng2 = fng1.before(function(){
console.log(0)
}).after(function(){
console.log(2)
})
var cont = (function(){
var money = [];
return function(){
if(arguments.length === 0){
var mon = 0;
for(var i = 0; i
Function.prototype.unCurrying = function(){
var that =this;
return function(){
var o = Array.prototype.shift.call(arguments);
return that.apply(o, arguments)
}
}
var push = Array.prototype.push.unCurrying();
var num = (function(){
push(arguments, 4)
console.log(arguments)
})(1,2,3)
分析: 上面的代码是由javascript的之父 Brendan Eich写的一段代码,其实上面的一段代码的效果也可以通过Array.prototype.push.call(arguments, 4)
是一样的结果,关键在这种思维方法。
push方法接受两个参数,num函数的argument和4,Array.prototype.push.unCurrying();
表示unCurrying方法复制了数组的push方法;而unCurrerying方法的返回值就是Function对象中的unCurreying方法并且实现了arguments继承数组的push方法,并且把4中对应argumentsd的值,通过apply的显性绑定,给添加到第一个arguments的值中去。这个时候闭包中nums对应的arguments
的长度就是4,参数就是1234;
1. setTimeout节流
var setThrottle = (function(){
var throFlag = true; //节流判断
return function(fn, time){
var that = this;
if(!throFlag){
return false;
}
throFlag = false;
setTimeout(()=>{
fn.apply(this, arguments)
throFlag = true;
}, time)
}
})();
2. date时间值节流
const setDateThro = (function(){
let old = Date.now();
return function(fn, time){
if(Date.now()- old >= time){
fn.apply(this, arguments);
old = Date.now();
}
}
})()
3. 混合节流,最后一次也需要执行该函数
const componentThro = (function(){
let old = Date.now();
let timeout;
return function(fn, time){
const args = arguments;
clearTimeout(timeout)
if(Date.now()- old > time){
fn.apply(this, args);
old = Date.now();
}else{ // 事件完结后再执行一次
timeout = setTimeout(()=>{
fn.apply(this, args);
}, time)
}
}
})()
div1.onclick = function(){
componentThro(()=>{
console.log('节流')
}, 1000)
}
4. 防抖,第一次执行
var deben = (function(){
let timeout = undefined;
let preFlag = true;
return function(fn, time){
const args = arguments;
if(preFlag){ // 第一次执行一次;
fn.apply(this, args)
}
preFlag = false
clearTimeout(timeout)
timeout = setTimeout(()=>{
preFlag = true;
}, time)
}
})()
div1.onclick = function(){
deben(()=>{
console.log('防抖')
}, 1000)
}
5. 防抖,最后一次点击执行
var deben = (function(){
let timeout = undefined;
return function(fn, time){
const args = arguments;
preFlag = false
clearTimeout(timeout)
timeout = setTimeout(()=>{
fn.apply(this, args)
}, time)
}
})()
div1.onclick = function(){
deben(()=>{
console.log('防抖')
}, 1000)
}
6. 防抖,第一次和最后一次都需要执行
var deben = (function(){
let timeout = undefined;
let preFlag = true;
return function(fn, time){
const args = arguments;
if(preFlag){ // 第一次执行一次;
fn.apply(this, args)
}
preFlag = false
clearTimeout(timeout)
timeout = setTimeout(()=>{
fn.apply(this, args)
preFlag = true;
}, time)
}
})()
div1.onclick = function(){
deben(()=>{
console.log('防抖')
}, 1000)
}