跟我学习javascript的全局变量


Posted in Javascript onNovember 16, 2015

一、尽量少用全局对象

全局变量的问题在于,你的JavaScript应用程序和web页面上的所有代码都共享了这些全局变量,他们住在同一个全局命名空间,所以当程序的两个不同部分定义同名但不同作用的全局变量的时候,命名冲突在所难免。

web页面包含不是该页面开发者所写的代码也是比较常见的,例如:

  • 第三方的JavaScript库
  • 广告方的脚本代码
  • 第三方用户跟踪和分析脚本代码
  • 不同类型的小组件,标志和按钮

比方说,该第三方脚本定义了一个全局变量,叫做result;接着,在你的函数中也定义一个名为result的全局变量。其结果就是后面的变量覆盖前面的,第三方脚本就一下子嗝屁啦!

因为,你不小心,在代码的某一处修改了全局变量, 会导致依赖全局变量的其它模块出错。而且出错原因难调试,难找到。

再者就是,网页运行肯定用到window对象,浏览器引擎又要遍历一次window的属性,性能下降。

  • 全局变量是维系不同模块之间的纽带,模块之间只能通过全局变量来访问对方提供的功能
  • 能使用局部变量的时候,绝不要使用全局变量
var i,n,sum//globals
function averageScore(players){
 sum =0;
 for(i = 1, i = player.length; i<n; i++){
  sum += score(players[i]);
 }
 return sum/n;
}

保持这些变量为局部变量,仅将其作为需要使用它们的代码的一部分。

function averageScore(players){
var i,n,sum;
 sum =0;
 for(i = 1, i = player.length; i<n; i++){
  sum += score(players[i]);
 }
 return sum/n;
}

在browser中,this关键字会指向全局的window对象
JavaScript 的全局命名空间也被暴露为在程序全局作用域中可以访问的全局对象,该对象作为 this 关键字的初始值。在 Web 浏览器中,全局对象被绑定到全局的 window 变量。添加或修改全局变量会自动更新全局对象。

this.foo; //undefined
foo ="global foo"; //"global foo"
this.foo; //"global foo"

类似地,更新全局对象也会自动地更新全局命名空间:

var foo ="global foo";
this.foo; //"global foo"
this.foo ="changed";
foo; //"changed"

两种用来改变全局对象的方式,通过var关键字声明以及给全局对象设置属性(通过this关键字)

通过全局对象进行针对当前运行环境的特性检测(Feature Detection),比如在ES5中提供了一个JSON对象用来操作JSON数据,那么可以通过if(this.JSON)来判断当前运行环境是否支持JSON

if(!this.JSON){
 this.JSON ={
  parse:...,
  stringify:...
 }
}

二、如何避免全局变量

方法一:只创建一个全局变量。

MYAPP.stooge = {
 "first-name": "Joe",
 "last-name": "Howard"
};

MYAPP.flight = {
 airline: "Oceanic",
 number: 815,
 departure: {
  IATA: "SYD",
  time: "2004-09-22 14:55",
  city: "Sydney"
 },
 arrival: {
  IATA: "LAX",
  time: "2004-09-23 10:42",
  city: "Los Angeles"
 }
};

方法二:使用模块模式

var serial_maker = function ( ) {

// Produce an object that produces unique strings. A
// unique string is made up of two parts: a prefix
// and a sequence number. The object comes with
// methods for setting the prefix and sequence
// number, and a gensym method that produces unique
// strings.

 var prefix = '';
 var seq = 0;
 return {
  set_prefix: function (p) {
   prefix = String(p);
  },
  set_seq: function (s) {
   seq = s;
  },
  gensym: function ( ) {
   var result = prefix + seq;
   seq += 1;
   return result;
  }
 };
}( );

var seqer = serial_maker( );
seqer.set_prefix = 'Q';
seqer.set_seq = 1000;
var unique = seqer.gensym( ); // unique is "Q1000"

所谓模块模式,就是创建一个函数,该函数包括,私有变量和一个特权对象,特权对象的内容是,利用闭包能访问到私有变量的函数,最后返回特权对象。

首先,方法二,不仅可以当作全局变量用,也可以用在局部声明全局变量。因为就算你在不知道某个地方修改了seqer,就会立即报错,因为这是个对象,不是字符串。

方法三:零全局变量

零全局变量实际上是为了适应一小段封闭代码而采取的一种局部变量处理方式,只适合在一些特殊场景中使用。最常见的就是一些不会被其他脚本访问到的完全独立的脚本。
使用零全局变量的方式需要采用立即执行函数,用法如下。

( function ( win ) {

 'use strict' ;
 var doc = win.document ;
 //在此定义其他的变量并书写代码
} )

三、意外的全局变量

由于JavaScript的两个特征,不自觉地创建出全局变量是出乎意料的容易。首先,你可以甚至不需要声明就可以使用变量;第二,JavaScript有隐含的全局概念,意味着你不声明的任何变量都会成为一个全局对象属性。参考下面的代码:

function sum(x, y) {
 // 不推荐写法: 隐式全局变量
 result = x + y;
 return result;
}

此段代码中的result没有声明。代码照样运作正常,但在调用函数后你最后的结果就多一个全局命名空间,这可以是一个问题的根源。

经验法则是始终使用var声明变量,正如改进版的sum()函数所演示的:

function sum(x, y) {
 var result = x + y;
 return result;
}

另一个创建隐式全局变量的反例就是使用任务链进行部分var声明。下面的片段中,a是本地变量但是b确实全局变量,这可能不是你希望发生的:

// 反例,勿使用
function foo() {
 var a = b = 0;
 // ...
}

此现象发生的原因在于这个从右到左的赋值,首先,是赋值表达式b = 0,此情况下b是未声明的。这个表达式的返回值是0,然后这个0就分配给了通过var定义的这个局部变量a。换句话说,就好比你输入了:

var a = (b = 0);
如果你已经准备好声明变量,使用链分配是比较好的做法,不会产生任何意料之外的全局变量,如:

function foo() {
 var a, b;
 // ... a = b = 0; // 两个均局部变量
}

然而,另外一个避免全局变量的原因是可移植性。如果你想你的代码在不同的环境下(主机下)运行,使用全局变量如履薄冰,因为你会无意中覆盖你最初环境下不存在的主机对象

  总是记得通过var关键字来声明局部变量

 使用lint工具来确保没有隐式声明的全局变量

以上就是对javascript的全局变量介绍,希望对大家的学习有所帮助。

Javascript 相关文章推荐
jquery 子窗口操作父窗口的代码
Sep 21 Javascript
基于jQuery的树控件实现代码(asp.net+json)
Jul 11 Javascript
兼容各大浏览器的JavaScript阻止事件冒泡代码
Jul 09 Javascript
js对象浅拷贝和深拷贝详解
Sep 05 Javascript
Vue2.0 v-for filter列表过滤功能的实现
Sep 07 Javascript
微信小程序实现点赞、取消点赞功能
Nov 02 Javascript
微信小程序全局变量的设置、使用、修改过程解析
Sep 24 Javascript
Vue在chrome44偶现点击子元素事件无法冒泡的解决方法
Dec 15 Javascript
详解在IDEA中将Echarts引入web两种方式(使用js文件和maven的依赖导入)
Jul 11 Javascript
vue 微信分享回调iOS和安卓回调出现错误的解决
Sep 07 Javascript
小程序点餐界面添加购物车左右摆动动画
Sep 23 Javascript
vue.js 使用原生js实现轮播图
Apr 26 Vue.js
浅析JavaScript访问对象属性和方法及区别
Nov 16 #Javascript
跟我学习javascript的基本类型和引用类型
Nov 16 #Javascript
简单实现限制uploadify上传个数
Nov 16 #Javascript
跟我学习javascript的隐式强制转换
Nov 16 #Javascript
跟我学习javascript的浮点数精度
Nov 16 #Javascript
跟我学习javascript的严格模式
Nov 16 #Javascript
javascript中tostring()和valueof()的用法及两者的区别
Nov 16 #Javascript
You might like
简单的php文件上传(实例)
2013/10/27 PHP
用PHP来计算某个目录大小的方法
2014/04/01 PHP
PHP数组与对象之间使用递归实现转换的方法
2015/06/24 PHP
yii2中结合gridview如何使用modal弹窗实例代码详解
2016/06/12 PHP
如何确保JavaScript的执行顺序 之jQuery.html并非万能钥匙
2011/03/03 Javascript
js和php如何获取当前url的内容
2013/09/22 Javascript
jQuery的显示和隐藏方法与css隐藏的样式对比
2013/10/18 Javascript
基于jquery实现等比缩放图片
2014/12/03 Javascript
Javascript数组与字典用法分析
2014/12/13 Javascript
JavaScript采用递归算法计算阶乘实例
2015/08/04 Javascript
Node.js刷新session过期时间的实现方法推荐
2016/05/18 Javascript
vue.js框架实现表单排序和分页效果
2017/08/09 Javascript
浅谈node的事件机制
2017/10/09 Javascript
JS常用的几种数组遍历方式以及性能分析对比实例详解
2018/04/11 Javascript
浅析vue 函数配置项watch及函数 $watch 源码分享
2018/11/22 Javascript
微信小程序自定义组件传值 页面和组件相互传数据操作示例
2019/05/05 Javascript
js纯前端实现腾讯cos文件上传功能的示例代码
2019/05/14 Javascript
[59:32]Liquid vs Fnatic 2019国际邀请赛淘汰赛败者组BO1 8.20.mp4
2020/07/19 DOTA
详解Python中的正则表达式的用法
2015/04/09 Python
python使用smtplib模块通过gmail实现邮件发送的方法
2015/05/08 Python
CentOS7.3编译安装Python3.6.2的方法
2018/01/22 Python
在python中实现对list求和及求积
2018/11/14 Python
对python打乱数据集中X,y标签对的方法详解
2018/12/14 Python
python实现QQ邮箱发送邮件
2020/03/06 Python
Pycharm导入anaconda环境的教程图解
2020/07/31 Python
Python使用requests模块爬取百度翻译
2020/08/25 Python
Python confluent kafka客户端配置kerberos认证流程详解
2020/10/12 Python
关于探究python中sys.argv时遇到的问题详解
2021/02/23 Python
使用Python制作一盏 3D 花灯喜迎元宵佳节
2021/02/26 Python
法学专业求职信
2014/07/15 职场文书
五五普法心得体会
2014/09/04 职场文书
关于运动会的广播稿(10篇)
2014/09/12 职场文书
教师师德表现自我评价
2015/03/05 职场文书
2016年大学自主招生自荐信范文
2015/03/24 职场文书
2016年第32个教师节红领巾广播稿
2015/12/18 职场文书
用Python爬取某乎手机APP数据
2021/06/15 Python