一、前言

为什么读这本书?

其实做前端开发,一个需求给不同工作经验的人去做,只要完工时间不算苛刻,大家都是能实现的。功能实现虽然大致相同,但当我们回归代码去看实现方式,代码书写的美观程度,以及实现的方法其实是不尽相同的。毕竟经验丰富的人,拿到一个需求,可能脑海里就浮现了多个可供选择的方案,而经验较浅的人,就更偏向于如何实现基本需求了。
例如说到过滤一个数组,第一想到使用for循环,不会想到filter方法;再如做条件判断,首先想到if else,忽略掉了还有which case或Boolean?true:false三元运算符之类的其它选择。说这些不是说后者毕竟比前者要好,毕竟对于不同的使用场景,合适的才是最佳的,但能举一反三,从三种甚至多种方法中做出选择,是肯定要比一招鲜要更好的。
经验的积累不是一天两天的事情,这点我也明白,那能不能先从基本做起,比如了解更好的代码书写规范,掌握好基本概念,知道一些实用的js模式甚至说套路,那这就是我读这本书的原因了。
从这本书,你会知道比常规for循环更优的写法,知道new一个构造函数时究竟发生了什么,知道为什么setTimeout('fun()',1000),setTimeout(fun,1000)两种写法,为什么前者加引号都能执行,知道更优秀的编码方式以及更多有趣的东西。
这个系列只是作为读书笔记,挑出一些重要或者我觉得有趣的的概念,如果觉得有趣,推荐阅读原书。

二、JavaScript概念 

1.面向对象
JavaScript(以下简称js)是一门面向对象的编程语言,我们总说,万物皆对象,这点是没错的。但需要注意的是,js中的六种基本(原始)数据类型不是对象,它们分别是,String(字符串)Number(数字)Boolean(布尔类型)nullundefined,以及ES6新增的基本类型symbol
复杂(引用)数据类型可以归纳为对象类型,而对象有两大类,本地对象与宿主对象。

宿主对象包含window和所有DOM对象,而本地对象包括了内置对象(如 Function,Array,Date)或自定义对象(var o = {});
基本数据类型与引用数据类型的区别在于,基本数据类型的变量名与值都是存放在栈内存中,而对于引用数据类型,变量在栈内存中,值存放中堆内存中,变量名指向由堆内存提供的值地址,不理解可以具体看看博主对于深浅拷贝中值的存放图解。
说到数据类型,null是需要单独说说的。我们可以在浏览器F12调出控制台,输入typeof null回车,可以看到输出为object,这是为什么呢?
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null就错误的返回了"object"。

ECMAScript提出了一个修复(通过opt-in),但被拒绝。这将导致typeof null === 'object'。
这段话可以理解为,这是早期JS设计留下的缺陷,但我们只要记住,虽然typeof得到的是object类型,但null本质就是基本数据类型,那我们要判断null类型该怎么办呢,可以使用如下方法。

Object.prototype.toString.call(null) === [object Null]。

2.原型(prototype)
js中的继承是代码重用的一种方式,继承的方式很多,原型就是其中一种,需要注意的是,原型其实就是一个普通对象。我们创建的每一个函数其实都自带prototype属性,这个属性指向一个空对象,你可以为这空对象添加各种属性方法,而这些新增成员可以被其它对象继承,作为其它对象的自有属性。这个空对象也不是严格意义上的空,它自带一个constructo属性,它指向你新建的函数。
3.严格模式
严格模式是采用具有限制性JavaScript变体的一种方式,从而使代码显示地 脱离“马虎模式/稀松模式/懒散模式“(sloppy)模式。添加模式比较简单,你只需要在你希望执行严格模式的作用域添加"use strict"即可。

"use strict"

顾名思义,严格模式相比传统模式有以下改变:(笔试遇到过一次)

• 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
• 消除代码运行的一些不安全之处,保证代码运行的安全;
• 提高编译器效率,增加运行速度;
• 为未来新版本的Javascript做好铺垫。

二、高质量javaScript基本要点

1.编写可维护的代码

人人都喜欢开发新功能,一切从零开始,不喜欢维护旧代码,特别是一段段密密麻麻没有注释的代码,这点每个开发者都感同身受。但抛开阅读遗留代码或者同事的代码,就算是我们自己开发的功能,两三个月后回头再读也可能出现阅读困难的问题,这就导致了维护成本较高的问题;阅读代码超过开发功能的时间很明显是不合理的。
因此我们在开发新功能,或者维护旧代码的同时,就得花时间为不合理的代码进行调整,例如
• 可读的
• 一致的(看起来像同一个人写的,有统一的规范)
• 可预测的(能拓展)
• 有文档的(或注释)

2.减少全局对象

减少全局对象基本是每个前端者入行就被告知的点。js是使用函数来管理作用域(scope)的,那么可以说,在一个函数内定义的变量就是一个局部变量,局部变量在当前作用域外部是不可见的;反之,全局变量是不在任何函数体内声明的变量,或者是直接使用而未申明的变量。

function echo() {
var a = ;//局部
b = ;//虽然在函数体内,但是未使用var let之类申明。
};
var c = //全局,虽然有申明,但是在函数体外。

每个js运行环境都有一个隐式全局对象,通常浏览器用全局对象window代表这个全局对象隐式全局对象,我们创建的每个全局变量都是这个全局对象的属性,我们可以不在任何函数体内使用this就能查看这个全局对象的引用,如:

a = ;
console.log(a);//
console.log(this.a);//
console.log(window.a)//
console.log(window['a'])//

全局变量在js代码执行的整个作用域都是可见的,正因为它们存在于同一个命名空间中,所以会发生命名冲突的问题。我们很难保证自己定义的全局变量是否与三方库,插件中变量是否有重名,所以使用变量先去申明它是非常重要的。
顺带一提

function echo() {
var a = b = ;
}

其中b是全局变量,a是局部变量,等价于var a = (b = 0);(实际开发中肯定是不推荐这样的写法,可读性太差,只是书中有举例,顺带说说这种写法带来全局变量的问题)
隐式全局变量与显式全局变量
隐式全局变量:通过 var 创建的全局变量(在任何函数体之外创建的变量)不能被删除。
隐式全局变量:没有用 var 创建的隐式全局变量(不考虑函数内的情况)可以被删除。

var a = ;
b = ;
console.log(delete a)//false
console.log(delete b)//true

隐式全局变量并不算是真正的变量,可以说它们是全局对象的一个属性成员。而属性是可以通过delete运算符删除的,变量不可以被删除,这是两者的区别。

3.访问全局对象

我们在前面说,全局变量总是被隐性的添加为全局对象的属性,那么我们其实可以通过全局对象来访问全局变量,例如通过window。但并不是在所有的环境下默认隐性全局对象都是window,或者说某个环境的全局对象可能不叫window。但我们可以利用根据this指向原则始终能找到全局对象,
例如函数在自调情况下,this总是指向全局对象(严格模式下this会指向undefined)。

var global = (function (){
return this;
})();
console.log(global)//当前环境的全局对象

4.单 Var 模式

申明变量在编程中是高频率的,在函数顶部使用一个单独的var语句是非常推荐的一种模式。这么做有如下好处:

• 在同一个位置可以查找到函数所需的所有变量(变量集中,方便查找)
• 避免当在变量声明之前使用这个变量时产生的逻辑错误(申明提前的问题)
• 提醒你不要忘记声明变量,顺便减少潜在的全局变量
• 代码量更少(输入更少且更易做代码优化)

var a = ,
b = ,
c,
fun = function () {};

当然使用let const申明也是可以使用这种模式的,而且let申明变量也彻底解决了var申明提前这种较为诟病的问题,这里还是按照书中思路去整理了笔记,大家心里能明白就好。

5.申明提前:分散的var带来的问题

首先,申明提前可以说是var申明模式的一个隐性问题,有时候会带来一些不必要的麻烦,而在ES6中新增的let申明方式其实已经解决了var的申明提前问题,本来这一点可说可不说,但毕竟还是有一些面试题会说道,就简单带一带。
对于js来说,当我们在某个作用域(比如同一个函数内)里声明了一个变量,这个变量在整个作用域内都是可见的,可使用的,包括在 var 声明 语句之前,这种情况就是所谓的申明提前。

(function (){
console.log(a);//undefined
var a = echo;
console.log(a);//echo
})();

在这段代码中,尽管第一个console在变量a申明之前,它也不会报错,因为在这个函数体内,var a申明会提前(赋值不提前),任何一个地方,不管先后都能正确的使用它,它等同于

(function (){
var a;
console.log(a);//undefined
a = echo;
console.log(a);//echo
})();

6.更优的for 循环

这里不讨论for forEach while各类循环方法的性能优劣,毕竟循环之争一直存在,可读性,性能太多因素,还是根据实际使用场景来定夺,后面有空也确实想对于现有常用数据遍历可行方法进行一个整理。(应该不会鸽)
我们最常见的for循环写法

for (var i = ; i < arr.length; i++) {
//do something with arr[i];
}

在for 循环括号中,var i = 0其实只会申明一次,但i < arr.length 与i++是每次循环都会执行的。那么就存在一个问题,上面的代码每次循环都会重复取一次数组arr的length属性,这会降低代码的性能,特别是当arr不单单是个数组,而是一个HTMLCollection对象时。
HTMLCollection对象是由DOM方法返回的对象,例如:
• document.getElementsByName()
• document.getElementsByClassName()
• document.getElementsByTagName()
操作dom是一个很耗资源的行为,如果每次循环都要遍历查询dom元素显然不太合理,更好的做法是用变量一开始就保存数组的长度。

for (var i = , max = myarray.length; i < max; i++) {
// do something with myarray[i]
}

或者这样,将变量的申明统一在一起,for只用管好自己的循环。

var i = ,
myarray = [],
max = myarray.length;
for (; i < max; i++) {
// do something with myarray[i]
}

注意括号中的第一个分号我有保留,或者写成(i < max; i++;)也可以,分号不能丢,不然会报错。
通过上面的改写,不管循环多少次,其实都只用查询一次DOM节点的length,是不是比较nice。
对于for循环,其实还可以做少量的改进,在for中我们之所以申明i = 0的作用是告诉循环,i是从0开始递增并与max做判断是否需要继续下次循环,其实我们可以直接获取数组长度让其递减,效果是一样的。

var myarray = [],
i = myarray.length
for (; i --;){
// do something with myarray[i]
}

这样写分号总觉得有点奇怪,我们也可以使用while来进行代替

var myarray = [],
i = myarray.length;
while (i--) { //在某篇博客看到过while 比 for更快的说法
// do something with myarray[i]
}

这么做相比前面的写法有两个有点,第一,变量减少了,我们直接让将length赋予给i进行递减,省去了变量max,其次,递减到0的做法速度会更快,因为与零相比要比和非零数字或者数组长度比较要高效跟多。

第一篇就先记到这里,再写下去篇幅就太长了点,看着就不太想想读了,不过估计也没人会耐着性子读这样的文章吧。

第二篇也会抓紧时间写,倘若有人阅读过,也欢迎指出错误。

精读JavaScript模式(一)的更多相关文章

  1. 精读JavaScript模式(七),命名空间模式,私有成员与静态成员

    一.前言 惰性十足,这篇2月19号就开始写了,拖到了现在,就是不愿意花时间把看过的东西整理一下,其它的任何事都比写博客要有吸引力,我要反省自己. 从这篇开始,是关于JS对象创建模式的探讨,JS语言简单 ...

  2. 精读JavaScript模式(二)

    我在想知识点怎么去分类,原本计划一章节一篇,但这样会会显得长短不一.更主要的是看到哪写的哪更为随意.那么这一篇还是紧接第一篇进行知识梳理,上篇说到了更优化的for循环,现在继续聊聊其它的循环方式. 1 ...

  3. 精读JavaScript模式(八),JS类式继承

    一.前言 这篇开始主要介绍代码复用模式(原书中的第六章),任何一位有理想的开发者都不愿意将同样的逻辑代码重写多次,复用也是提升自己开发能力中重要的一环,所以本篇也将从“继承”开始,聊聊开发中的各种代码 ...

  4. 精读JavaScript模式(三),new一个构造函数居然发生了什么?

    一.前言 上个月底,爸爸因为事故突然离世,说心里话,现在看到'去世','爸爸'这样的字眼,眼泪都会忍不住在眼眶打转,还是需要时间治愈.最近也只是零碎的看了下东西,始终沉不下心去读书,直到今天还是决定捡 ...

  5. 精读JavaScript模式(六),Memoization模式与函数柯里化的应用

    假期就这么结束了!十天假就有三天在路上,真的难受!想想假期除了看了两场电影貌似也没做什么深刻印象的事情.流浪地球,特效还是很赞,不过对于感情的描写还是逃不掉拖沓和尴尬的通病,对于国产科幻还是抱有支持的 ...

  6. 精读JavaScript模式(五),函数的回调、闭包与重写模式

    一.前言 今天地铁上,看到很多拖着行李箱的路人,想回家了. 在上篇博客结尾,记录到了函数的几种创建方式,简单说了下创建差异,以及不同浏览器对于name属性的支持,这篇博客将从第四章函数的回调模式说起. ...

  7. 精读JavaScript模式(四),数组,对象与函数的几种创建方式

    一.前言 放了个元旦,休息了三天,加上春运抢票一系列事情的冲击,我感觉我的心已经飞了.确实应该收收心,之前计划的学习任务也严重脱节了:我恨不得打死我自己. 在上篇博客中,笔记记录到了关于构造函数方面的 ...

  8. javascript 模式(1)——代码复用

    程序的开发离不开代码的复用,通过代码复用可以减少开发和维护成本,在谈及代码复用的时候,会首先想到继承性,但继承并不是解决代码复用的唯一方式,还有其他的复用模式比如对象组合.本节将会讲解多种继承模式以实 ...

  9. 【读书笔记】读《JavaScript模式》 - 函数复用模式之现代继承模式

    现代继承模式可表述为:其他任何不需要以类的方式考虑得模式. 现代继承方式#1 —— 原型继承之无类继承模式 function object(o) { function F() {}; F.protot ...

随机推荐

  1. 用命令行上传本地代码到GitHub

    有两种方式上传,ssh和https,ssh老是报错=.=我用的是https 先下载git   https://git-scm.com/downloads 在代码的文件夹的同级目录中邮件打开git ba ...

  2. AngularJS 模块及provide

    一.模块 模块是一些功能的集合,如控制器.服务.过滤器.指令等子元素组成的整体. 1.注册和使用 模块相当于是一个注册表,保存着名字和编程元素的对照表,可存入也可取出. angular.module( ...

  3. CSS 基础 例子 display属性:block、inline和inline-block的区别

    HTML中块级元素(block)和行级元素(inline):比如div就是常见的块级元素,span就是常见的行级元素. 可以通过css的display属性来设置一个元素到底是块级,还是行级元素:dis ...

  4. 分频器的verilog设计

    笔者最近由于实验室老师的任务安排重新又看了一下分频器的verilog实现,现总结如下,待以后查看之用(重点是查看计数器计到哪个值clk_out进行状态翻转) 1.偶数分频占空比为50% 其实质还是一个 ...

  5. verilog中defparam的用法 (verilog调用底层模块(只改变)参数的传递)

    当一个模块引用另外一个模块时,高层模块可以改变低层模块用parameter定义的参数值,改变低层模块的参数值可采用以下两种方式: 1)defparam 重定义参数 语法:defparam path_n ...

  6. 7.css浮动与定位

    外边距塌陷 解决方案: ◆给父盒子加border ◆overflow:hidden; bfc 行内元素可以定义左右的内外边距,上下会被忽略掉. 行内块可以定义内外边距. 文档流(标准流) 元素自上而下 ...

  7. JS原生事件处理(跨浏览器)

    一.关于获取事件对象 FF有点倔强,只支持arguments[0],不支持window.event.这次真的不怪IE,虽然把event作为window的属性不合规范,但大家都已经默许这个小问题存在了, ...

  8. ASP.NET MVC高亮显示当前页面菜单

    1.创建MvcHtmlExtension扩展类 public static class MvcHtmlExtension { public static MvcHtmlString MenuLink( ...

  9. Python中super()的用法

    参考链接:https://www.cnblogs.com/shengulong/p/7892266.html super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是 ...

  10. Code Chef December Challenge 2018题解

    传送门 \(MAXEP\) 二分,不过二分的时候要注意把\(mid\)设成\(\left\lfloor{9l+r\over 10}\right\rfloor\),这样往右的次数不会超过\(6\)次 / ...