您的位置:首页 > Web前端 > JavaScript

10招打通你的js任督二脉

2015-11-19 11:46 651 查看
这段时间一直在看 亚里士朱德的文章,有一篇是我感触颇多,我跟着演示了几遍,也顺便 炒一下冷饭 ^_^

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>十招打通js任督二脉</title>
</head>
<body>
打开控制台,咱们直接上代码。
<script type="text/javascript">

/*第一招:简单回调*/
//this指针指向当前函数对象
var simpleCallBack=(function(){
console.log('这是第一招:');
this.a="I'm an a";
function foo(){
console.log(this.a);
}
function doFoo(fn){
fn();
}
function doFoo2(o){
o.foo();
}
this.obj={
a:2,
foo:foo
};
doFoo(obj.foo);
doFoo2(obj);
})();

/*第二招:用apply改变函数作用域*/
//apply,call,bind都有个作用就是改变作用域,这里的apply将foo函数的作用域指向obj对象,同时传入参数。
//再简单分析一下bind函数内部的嵌套,执行bind函数的时候返回的是一个匿名函数,所以执行bar(3)的时候实际上是执行的bind内部的匿名函数,返回的是之前传入的foo函数的执行结果。
//函数没有返回值的情况下默认返回undefined。
var applyChangeScope=(function(){
console.log('这是第二招:');
function foo(something) {
console.log(this.a,something);
}
function bind(fn,obj){
return function(){
return fn.apply(obj,arguments);
}
}
this.obj={
a:2
}
this.bar=bind(foo,obj);
this.b=bar(3);
console.log(b);
})();

/*第三招:new关键字*/
//bind函数的一个参数为null代表作用域不变,后面的不定参数将会和函数本身的参数按次序绑定,绑定之后执行函数只能从未绑定的参数开始传值。
var theKeywordNew=(function(){
console.log('这是第三招:');
function foo(a,b){
this.val=a+b;
}
this.bar=foo.bind(null,'p1');
this.baz=new bar('p2');
console.log(baz.val);
})();

/*第四招:自执行函数*/
//立即执行匿名函数可以避免污染全局空间,但很少有人去关注赋值语句执行之后会返回什么结果,其实就是返回当前值。
//也就是说当括号内执行完成赋值之后,返回的是o对象中的foo函数,函数的执行环境中有一个a对象。
var executeFunction=(function(){
console.log('这是第四招:');
function foo(){
console.log(this.a);
}
this.a=2;
this.o={a:3,foo:foo};
this.p={a:4};
(p.foo=o.foo)();
})();

/*第五招:变量属性*/
//当一个变量被声明之后,扩充其属性并不会改变原数据类型
var variableAttribute=(function(){
console.log('这是第五招:');
this.a=[];
a[0]=1;
a['foobar']=2;
console.log(a.length);
console.log(a.foobar);
});

/*第六招:精度问题*/
//当操作小数时请小心,js的小数计算并不精确,所以下面的判断是false
//字符串变量是常亮
var accuracyProblem=(function(){
console.log('这是第六招:');
this.a='foo';
a[1]='o';
console.log(0.1+0.2==0.3||a);
})();

/*第七招:命名提升*/
//声明的变量和命名函数都会被提升到代码的最前面,只不过声明的额变量的赋值语句在代码的位置不变。所以下面的代码可以理解为:
//var foo;
//function foo(){
//  console.log(1);
//}
//foo();
//foo=0;
//foo=function(){
//  console.log(2);
//};
var naming1=(function(){
console.log('这是第七招:');
foo();
this.foo=0;
function foo(){
console.log(1);
}
this.foo=function(){
console.log(2);
};
})();
/*更诡异的变招*/
var naming2=(function(){
console.log('下面的这招能看懂就是理解第七招精髓了:');
foo();
this.foo=0;
function foo(){
console.log(1);
}
/*下面就开始报错了(可以去掉注释看看)
this.foo();
this.foo=function(){
console.log(2);
};
this.foo();
*/
})();

/*第八招:作用域*/
//javascript没有代码作用域,只有函数作用域
// 下面的代码可以理解为:
// function foo(){
//  console.log('a');
// }
// function foo(){
//  console.log('b');
// }
// foo();
// var a=true;
// if(a){}else{}
var scope=(function(){
console.log('这是第八招:')
foo();
this.a=true;
if(this.a){
function foo(){
console.log('a');
}
}else{
function foo(){
console.log('b');
}
}
})();

/*第九招:闭包陷阱*/
//闭包有个重要的作用就是,在内层函数引用外层函数定义的变量时,外层函数的变量不会被持久化。这里有个隐藏陷阱就是for循环结束之后i仍然自增了1
var closureTrap=(function(){
console.log('这是第九招:');
for(var i=1;i<=5;i++){
setTimeout(function(){
console.log(i);
},i*1000);
}
})();

/*第十招:伪闭包*/
// 闭包是函数的嵌套定义,而不是函数的嵌套调用
var pseudoClosure1=(function(){
console.log('这是第十招:');
function foo(){
console.log(a);
}
function bar(){
var a=3;
foo();
}
this.a=2;
bar();
})();
//那么问题来了,怎么输出3呢?
var pseudoClosure1=(function(){
console.log('第十招变招:');
function bar(){
function foo(){
console.log(a);
}
var a=3;
foo();
}
this.a=2;
bar();
})();

/*
* @参考:亚里士朱德《十段代码打通js学习的任督二脉》
* http://yalishizhude.github.io/2015/10/25/10/ */

</script>
</body>
</html>


感兴趣的同学可以download下来 演示一下。

原文@ 亚里士朱德《十段代码打通js学习的任督二脉》

http://yalishizhude.github.io/2015/10/25/10/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: