跟我学习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 相关文章推荐
js下用层来实现select的title提示属性
Feb 23 Javascript
jquery的相对父元素和相对文档定位示例代码
Aug 02 Javascript
Node.js node-schedule定时任务隔多少分钟执行一次的方法
Feb 10 Javascript
js全选实现和判断是否有复选框选中的方法
Feb 17 Javascript
jquery实现鼠标悬浮停止轮播特效
Aug 20 Javascript
JS模仿腾讯图片站的图片翻页按钮效果完整实例
Jun 21 Javascript
微信小程序使用第三方库Immutable.js实例详解
Sep 27 Javascript
Vue.js简易安装和快速入门(第二课)
Oct 17 Javascript
详解vue 兼容IE报错解决方案
Dec 29 Javascript
Element-ui自定义table表头、修改列标题样式、添加tooltip、:render-header使用
Apr 11 Javascript
JS canvas实现画板和签字板功能
Feb 23 Javascript
详解Vue router路由
Nov 20 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/11/06 PHP
php的4种常见运行方式
2015/03/20 PHP
PHP的Socket网络编程入门指引
2015/08/11 PHP
php操作redis数据库常见方法实例总结
2020/02/20 PHP
学习ExtJS(一) 之基础前提
2009/10/07 Javascript
javascript一些实用技巧小结
2011/03/18 Javascript
javascript抖动元素的小例子
2013/10/28 Javascript
Extjs表单常见验证小结
2014/03/07 Javascript
Extjs的FileUploadField文件上传出现了两个上传按钮
2014/04/29 Javascript
基于jQuery实现下拉框
2014/11/24 Javascript
javascript设计模式--策略模式之输入验证
2015/11/27 Javascript
js实现瀑布流的三种方式比较
2020/06/28 Javascript
JS封装的三级联动菜单(使用时只需要一行js代码)
2016/10/24 Javascript
php 修改密码实现代码
2017/05/24 Javascript
Vue项目分环境打包的实现步骤
2018/04/02 Javascript
vue 国际化 vue-i18n 双语言 语言包
2018/06/07 Javascript
jQuery点击页面其他部分隐藏下拉菜单功能
2018/11/27 jQuery
Django模板继承 extend标签实例代码详解
2019/05/16 Javascript
JQuery 实现文件下载的常用方法分析
2019/10/29 jQuery
[46:48]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第三局
2016/02/25 DOTA
两个使用Python脚本操作文件的小示例分享
2015/08/27 Python
Python优化技巧之利用ctypes提高执行速度
2016/09/11 Python
使用Django Form解决表单数据无法动态刷新的两种方法
2017/07/14 Python
python实现协同过滤推荐算法完整代码示例
2017/12/15 Python
python实现感知器
2017/12/19 Python
python matplotlib绘图,修改坐标轴刻度为文字的实例
2018/05/25 Python
Python浮点数四舍五入问题的分析与解决方法
2019/11/19 Python
python中提高pip install速度
2020/02/14 Python
Python经纬度坐标转换为距离及角度的实现
2020/11/01 Python
JACK & JONES瑞典官方网站:杰克琼斯欧式风格男装
2017/12/23 全球购物
豪华床上用品 :Jennifer Adams
2019/09/15 全球购物
幼儿园元旦亲子活动方案
2014/02/17 职场文书
关于工作时间玩手机的检讨书
2014/09/18 职场文书
领导班子四风问题对照检查材料
2014/09/27 职场文书
格林童话读书笔记
2015/06/30 职场文书
联想win10摄像头打不开怎么办?win10笔记本摄像头打不开解决办法
2022/04/08 数码科技