汤姆大叔博客笔记【随时更新】
1、忘记var的副作用(Side Effects When Forgetting var)
隐式全局变量和明确定义的全局变量间有些小的差异,就是通过delete
操作符让变量未定义的能力。
- 通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的。
- 无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的。
这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过delete
操作符删除的,而变量是不能的:
// 定义三个全局变量 var global_var = 1; global_novar = 2; // 反面教材 (function () {global_fromfunc = 3; // 反面教材 }());// 试图删除 delete global_var; // false delete global_novar; // true delete global_fromfunc; // true// 测试该删除 typeof global_var; // "number" typeof global_novar; // "undefined" typeof global_fromfunc; // "undefined"
2、预解析:var散布的问题(Hoisting: A Problem with Scattered vars)
// 反例 myname = "global"; // 全局变量 function func() {alert(myname); // "undefined"var myname = "local";alert(myname); // "local" } func(); //等价于下面这段代码 myname = "global"; // global variable function func() {var myname; // 等同于 -> var myname = undefined;alert(myname); // "undefined"myname = "local";alert(myname); // "local"} func();
for-in循环(for-in Loops)
for-in
循环应该用在非数组对象的遍历上,使用for-in
进行循环也被称为“枚举”。
从技术上将,你可以使用for-in
循环数组(因为JavaScript中数组也是对象),但这是不推荐的。因为如果数组对象已被自定义的功能增强,就可能发生逻辑错误。另外,在for-in中,属性列表的顺序(序列)是不能保证的。所以最好数组使用正常的for循环,对象使用for-in循环。
有个很重要的hasOwnProperty()
方法,当遍历对象属性的时候可以过滤掉从原型链上下来的属性。
for (var i in man) {if (man.hasOwnProperty(i)) { // 过滤原型属性或方法console.log(i, ":", man[i]);} }// 反面例子: // for-in loop without checking hasOwnProperty() for (var i in man) {console.log(i, ":", man[i]); }
另外一种使用hasOwnProperty()
的形式是取消Object.prototype上的方法。像是:
for (var i in man) {if (Object.prototype.hasOwnProperty.call(man, i)) { // 过滤console.log(i, ":", man[i]);} }
其好处在于在man对象重新定义hasOwnProperty情况下避免命名冲突。也避免了长属性查找对象的所有方法,你可以使用局部变量“缓存”它。
var i, hasOwn = Object.prototype.hasOwnProperty; for (i in man) {if (hasOwn.call(man, i)) { // 过滤console.log(i, ":", man[i]);} }
严格来说,不使用
hasOwnProperty()
并不是一个错误。根据任务以及你对代码的自信程度,你可以跳过它以提高些许的循环速度。但是当你对当前对象内容(和其原型链)不确定的时候,添加hasOwnProperty()
更加保险些。
格式化的变化(通不过JSLint)会直接忽略掉花括号,把if语句放到同一行上。其优点在于循环语句读起来就像一个完整的想法(每个元素都有一个自己的属性”X”,使用”X”干点什么):
// 警告: 通不过JSLint检测 var i, hasOwn = Object.prototype.hasOwnProperty; for (i in man) if (hasOwn.call(man, i)) { // 过滤console.log(i, ":", man[i]); }
(不)扩展内置原型((Not) Augmenting Built-in Prototypes)
扩增构造函数的prototype属性是个很强大的增加功能的方法,但有时候它太强大了。
增加内置的构造函数原型(如Object(), Array(), 或Function())挺诱人的,但是这严重降低了可维护性,因为它让你的代码变得难以预测。使用你代码的其他开发人员很可能更期望使用内置的 JavaScript方法来持续不断地工作,而不是你另加的方法。
另外,属性添加到原型中,可能会导致不使用hasOwnProperty属性时在循环中显示出来,这会造成混乱。
因此,不增加内置原型是最好的。你可以指定一个规则,仅当下面的条件均满足时例外:
- 可以预期将来的ECMAScript版本或是JavaScript实现将一直将此功能当作内置方法来实现。例如,你可以添加ECMAScript 5中描述的方法,一直到各个浏览器都迎头赶上。这种情况下,你只是提前定义了有用的方法。
- 如果您检查您的自定义属性或方法已不存在——也许已经在代码的其他地方实现或已经是你支持的浏览器JavaScript引擎部分。
- 你清楚地文档记录并和团队交流了变化。
如果这三个条件得到满足,你可以给原型进行自定义的添加,形式如下:
if (typeof Object.protoype.myMethod !== "function") {Object.protoype.myMethod = function () {// 实现... }; }
注释(Writing Comments)
你必须注释你的代码,即使不会有其他人向你一样接触它。通常,当你深入研究一个问题,你会很清楚的知道这个代码是干嘛用的,但是,当你一周之后再回来看的时候,想必也要耗掉不少脑细胞去搞明白到底怎么工作的。
很显然,注释不能走极端:每个单独变量或是单独一行。但是,你通常应该记录所有的函数,它们的参数和返回值,或是任何不寻常的技术和方法。要想到注 释可以给你代码未来的阅读者以诸多提示;阅读者需要的是(不要读太多的东西)仅注释和函数属性名来理解你的代码。例如,当你有五六行程序执行特定的任务, 如果你提供了一行代码目的以及为什么在这里的描述的话,阅读者就可以直接跳过这段细节。没有硬性规定注释代码比,代码的某些部分(如正则表达式)可能注释 要比代码多。
函数表达式和函数声明
在ECMAScript中,创建函数的最常用的两个方法是函数表达式和函数声明,两者期间的区别是有点晕,因为ECMA规范只明确了一点:函数声明必须带有标示符(Identifier)(就是大家常说的函数名称),而函数表达式则可以省略这个标示符:
函数声明:
function 函数名称 (参数:可选){ 函数体 }
函数表达式:
function 函数名称(可选)(参数:可选){ 函数体 }
所以,可以看出,如果不声明函数名称,它肯定是表达式,可如果声明了函数名称的话,如何判断是函数声明还是函数表达式呢?ECMAScript是通过上下文来区分的,如果function foo(){}是作为赋值表达式的一部分的话,那它就是一个函数表达式,如果function foo(){}被包含在一个函数体内,或者位于程序的最顶部的话,那它就是一个函数声明。
function foo(){} // 声明,因为它是程序的一部分var bar = function foo(){}; // 表达式,因为它是赋值表达式的一部分new function bar(){}; // 表达式,因为它是new表达式 (function(){function bar(){} // 声明,因为它是函数体的一部分})();
函数声明只能出现在程序或函数体内。从句法上讲,它们 不能出现在Block(块)({ ... })中,例如不能出现在 if、while 或 for 语句中。因为 Block(块) 中只能包含Statement语句, 而不能包含函数声明这样的源元素。另一方面,仔细看一看规则也会发现,唯一可能让表达式出现在Block(块)中情形,就是让它作为表达式语句的一部分。但是,规范明确规定了表达式语句不能以关键字function开头。而这实际上就是说,函数表达式同样也不能出现在Statement语句或Block(块)中(因为Block(块)就是由Statement语句构成的)。
汤姆大叔博客笔记【随时更新】相关推荐
- 大叔手记(21):汤姆大叔博客园开博100天总结
介绍 昨天是注册博客园的第100天,截止到今天大叔发了99篇帖子,加上今天这篇总共100篇,想来也应该来个总结了,本来是昨天写总结的,但由于加班,于是挪到今天了. 为何开博 博客这种事物在兴起的时候就 ...
- Javascript深入浅出理解----汤姆大叔博客(二)
编写高质量JavaScript代码的基本要素 1)书写可维护代码 2)最小全局变量 JavaScript通过函数管理作用域.在函数内部声明的变量只在这个函数内部,函数外面不可用.另一方面,全局变量就是 ...
- 汤姆大叔JavaCript系列3阅读笔记
Module模式: var blogModule = (function () {var my = {}, privateName = "博客园"; function privat ...
- 汤姆大叔JavaCript系列10阅读笔记
原型对象也是普通的对象,并且也有可能有自己的原型,如果一个原型对象的原型不为null的话,我们就称之为原型链(prototype chain). ECMAScript没有类的概念.但是,重用[reus ...
- 汤姆大叔JavaCript系列10阅读笔记1
闭包(Closures) 在ECMAScript中,函数是"第一类"对象.这个名词意味着函数可以作为参数被传递给其他函数使用 (在这种情况下,函数被称为"funargs& ...
- 为什么Android项目mainactivity中有一个变量R_博客笔记大汇总,Android优化总结篇
博客笔记大汇总[16年3月到至今],包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并 ...
- Python表示不甘心,汤姆大叔送书,Python抢书之毫秒级跟进--获取服务器时间
@鲜宏大牛果断使用js将抢书的误差提高到毫秒级, wid表示真心的很佩服鲜宏大牛! wid的水平虽说不怎么样, 但内心说, wid也想尝试着将抢书的误差提高到毫秒级, 思考了一会, 还真有思路了! 现 ...
- 收集优质的中文前端博客(不定期更新中)
收集优质的中文前端博客(不定期更新中) 注:博主的公司信息来自网上公开资料,仅供参考,不保证准确性. 个人(控制在42个以内) 阮一峰的网络日志(蚂蚁金服) <读懂 ECMAScript 规格& ...
- 怎么禁止/开启Ubuntu自动更新升级_豆豆技术派的博客-CSDN博客_ubuntu 自动更新
怎么禁止/开启Ubuntu自动更新升级_豆豆技术派的博客-CSDN博客_ubuntu 自动更新
最新文章
- poi设置单元格格式为文本_身份证号乱码?日期显示不对?都是单元格格式的锅...
- [脑海成像]科学家利用动态电极绕过眼睛直接刺激大脑,在盲人脑海画出字母
- 将 Shiro 作为应用的权限基础 五:密码的加密/解密在Spring中的应用
- STM8中GPIO的12种模式
- Solaris ALOM1.6 SC Password Reset
- 数据库:SQLServer 实现行转列、列转行用法笔记
- ASP.NET 数据库缓存依赖
- Java通过反射访问成员变量
- SpringBoot注解 @Configuration @PropertySource @ConfigurationProperties
- 如何为网站添加百度统计功能
- 【计算机组成原理】计算机的发展及应用
- 本地文件上传到阿里云生成网址
- k8s高可用环境部署7(Dashboard and metrics)
- 什么软件可以支持视频转换成文字?
- 适合于初学者—软路由全探索系列(一):探索 VMware 虚拟机旁路由安装及设置
- 阿里云域名注册详解与Github绑定
- 华为设备ACL配置命令
- 统信 UOS 连接 Windows 共享打印机
- 自行车改装电动车怎么样_电动车听起来应该是什么样?
- quartus编译报错:Error (176310): Can‘t place multiple pins assigned to pin location Pin_F16 (IOPAD_X34_Y1