深入学习JavaScript(一)
1、全局变量与局部变量
全局变量:全局变量就是在函数的外部定义的一个在其他地方都可以调用的变量
局部变量:局部变量是相对于全局变量而言的,局部变量指的是在一个区域内存在这个变量
全局变量的创建原理是在JavaScript加载页面的时候会自动的创建一个window对象,这个对象我们可以在方法的外部通过this去调用,我们所定义的变量其实就是对这个window对象进行添加属性而已
myglobal = "hello"; // 不推荐写法 console.log(myglobal); // "hello" console.log(window.myglobal); // "hello" console.log(window["myglobal"]); // "hello" console.log(this.myglobal); // "hello"
好了说一下,相信大家都知道全局变量的好处吧,全局变量就是的一个好处就是可以避免多次使用的变量被重复的定义(相对于局部变量而言)
局部变量的好处是当web页面需要引入广告代码或者等其他的第三方的代码的时候,通过创建局部变量就可以避免与第三方代码发生冲突,创建局部变量只要在方法内响应的变量加上var就行了,说到这里我就来挖一个坑给大家填填
(function foo(){ var a=b=1; }()); console.log(b); console.log(a);
大家先不要打开调试工具,先猜一猜运行的结果是什么?好了不管你猜对还是猜错我在这里就公布答案了
原因是我们应该要把var a=b=1;这就一分为二其中b是全局变量,a是局部变量但是他们的值是相同的,但是在方法的外部是不能访问到局部变量,所以才会出现a未定义的提示
2、使用var创建的全局变量和隐式创建全局变量的区别?
使用var创建的全局变量可以不可以通过delete删除
隐式创建全局变量可以通过delete删除
从侧面我们可以说明通过隐式创建全局变量不是在全局对象中创建变量,而是在全局对象创建属性(也就是说在window对象上创建属性)
var myglobal = "hello"; myglobal1="hello1"; function foo(){ myglobal2="hello2"; } //删除 delete myglobal; delete myglobal1; delete myglobal2; //调试一下,看看结果
结果如下:
3、单var定义变量
function func() { var a = 1, b = 2, sum = a + b, myobject = {}, i, j; // function body... } //查看单var结果 console.log(myobject); console.log(i);
这样定义的变量全部都是局部变量,而且还有还有在单一地方寻找所有的局部变量、减少代码等好处
4、var的悬置问题
JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)
这个定义可能有些云里雾里,我们就来写一个演示看看理解理解
myglobal="leslie"; function foo(){ console.log(myglobal);//undefined var myglobal="les"; console.log(myglobal);//les } foo();
运行的结果如注释所注,可能有些朋友会有所疑惑,其实这个就是一个var悬置的问题,在foo方法中我们创建了另外的一个局部变量myglobal,这个局部变量就会虽然看起来没有置顶,但是实际上在运行的过程中会将这个局部变量置顶,由于新创建的变量表现为undefined,所以这个时候第一句打印出来的值就是undefined,运行代码如下:
myglobal="leslie"; function foo(){ var myglobal;//undefined console.log(myglobal);//undefined var myglobal="les"; console.log(myglobal);//les } foo();
5、为对象模型添加方法以及遍历去除原始模型的方法
1、创建一个对象模型
// 对象 var man = { hands: 2, legs: 2, heads: 1 };
2、为对象添加方法
// 对象 var man = { hands: 2, legs: 2, heads: 1 }; // 在代码的某个地方 // 一个方法添加给了所有对象 if (typeof Object.prototype.clone === "undefined") { Object.prototype.clone = function () {}; }
3、过滤对象模型的方法
// 1. // for-in 循环 for (var i in man) { if (man.hasOwnProperty(i)) { // 过滤 console.log(i, ":", man[i]); } } /* 控制台显示结果 hands : 2 legs : 2 heads : 1 */
虽然可以为对象模型添加属性或者是方法,但是这个一般我们是不推荐使用的, 因为这样会造成团队沟通障碍以及其他的问题
6、避免发生隐式转换
JavaScript在比较的时候会发生隐式转换,为了避免发生隐式转换我们应该使用"==="和“!==”来代替"=="和“!=”
var test=1; if(test===true){ alert("this is one test"); } if (test==true) { alert("this is two test"); };
结果:
7、慎重使用eval()
在使用eval来动态加载脚本的时候,由于安全问题以及eval会污染环境
var un="test"; console.log(typeof un);//string console.log(typeof deux); // "undefined" console.log(typeof trois); // "undefined" var jsstring = "var un = 5; console.log(un);"; eval(jsstring); // un=5; jsstring = "var deux = 2; console.log(deux);"; new Function(jsstring)(); // deux=2; jsstring = "var trois = 3; console.log(trois);"; (function () { eval(jsstring); }()); // trois=3 console.log(typeof un); // number console.log(un); console.log(typeof deux); // "undefined" console.log(typeof trois); // "undefined"
从上面的代码我们可以分析得出直接使用eval会污染原来的环境(将un原来的string修改为number),较为推荐的是使用第三种方法,即解决了这个问题同时还比较符合编程的代码习惯
上面其实是实现对方法外部的eval的隔离,其实在方法中我们也可以使用相同的方法来达到隔离的作用
(function () { jsstring = "var trois = 3; console.log(trois);"; (function () { jsstring="var trois=10;console.log(trois);"; eval(jsstring); }()); console.log(jsstring); }());
打印的结果是
除了使用两种相同的方法套接外,还可以使用new function(){}的这种方法的套接
其实说白了就是通过将eval放置在一个局部的作用域中运行,其实还有一种更加简便的方法可以实现(这是我自己想出来的方法,不对的地方请大家指正)
(function () { jsstring = "var trois = 3; console.log(trois);"; { jsstring="var trois=10;console.log(trois);"; eval(jsstring); } console.log(jsstring); }());
这样运行的结果也是同上一个实例一样
8、编写规范
除了要注意这些问题编写规范也是很重要的
对于构造函数,可以使用大驼峰式命名法(upper camel case),如MyConstructor()
。对于函数和方法名称,你可以使用小驼峰式命名法(lower camel case),像是myFunction(), calculateArea()
和getFirstName()
。常量的命名我们一般用大写,例如:var MAX=1