阅读笔记《JavaScript语言精粹》
阅读笔记《JavaScript语言精粹》
对象
1.检索属性
使用[]和.
2.引用传递
JavaScript的简单数据类型包括数字、字符串、布尔值、null值和undefined值。其它所有的值都是对象。数组是对象,函数是对象,正则表达式是对象。对象通过引用传递,它们永远不会被复制。
3.原型
当我们对某个对象做出改变时,不会触及该对象的原型,只有在检索值的时候才会被用到。原型连接在更新时是不起作用的。delete删除对象中的属性,它也不会触及原型链中的任何对象,删除对象的属性可能会让来自原型链中的属性透现出来。
4.枚举
for-in语句枚举过程会列出所有的属性——包括函数和你可能不关心的原型中的属性——所以有必要过滤掉那些你不想要得值。最为常用的过滤器是hasOwnProperty方法,以及使用typeof来排除函数。
5.减少全局变量污染
JavaScript依赖于全局变量来进行链接,应当把全局性的资源都纳入一个名称空间之下,你的程序与其它应用程序、组件或类库之间发生冲突的可能性就会显著降低。
函数
1.函数对象
函数对象连接到Function.prototype(该原型对象本身连接到Object.prototype),每个函数在对象创建时会附加两个隐藏属性:函数的上下文和实现函数行为的代码。函数的与众不同之处在于它们可以被调用。
2.闭包
函数可以定义在其他函数中。一个内部函数除了可以访问自己的参数和变量,同时它也能自由访问把它嵌套在其中的父函数的参数和变量。通过函数字面量创建的函数对象包含一个连到外部上下文的连接。这被称为闭包。
3.调用
除了声明时定义得形式参数,每个函数还接收两个附加的参数:this和arguments。参数this的值取决于调用的模式,这些模式在如何初始化关键参数this上存在差异。
方法调用模式:当函数为对象的一个属性时,称它为该对象的方法,this绑定到该对象,方法可以通过this访问该对象的属性。
函数调用模式:当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用的,以此模式调用函数时,this被绑定到全局对象。这是语言设计上的一个错误。(应当绑定到外部父函数的this变量。)
构造器调用模式:如果在一个函数前面带上new来调用,那么背地里将会创建一个连接到该函数的prototype成员的新对象,同时this会被绑定到那个对象。new前缀也会改变return语句的行为。(参照5.返回)
apply调用模式:函数是对象,所以也拥有方法。apply方法让我们构建一个参数数组传递给调用函数。apply接收两个参数,第一个是要绑定给this的值,第二个就是一个参数数组。
4.参数
当函数被调用时,会得到一个arguments参数,可以通过它访问函数所有的参数列表,这使得编写一个无须指定参数个数的函数成为可能。arguments拥有一个length属性,但它不是数组,并没有任何数组的方法。
5.返回
一个函数总会有返回值,如何没有指定就返回undefined。如果函数调用时前面加上了new前缀,且返回值不是一个对象,则返回this(该新对象)。
6.扩充类型的功能
通过给基本类型增加方法,我们可以极大的提高语言的变现力。因为JavaScript原型继承的动态本质,新的方法立刻被赋予到所有的对象实例上,哪怕对象示例是在方法被增加之前就创建好了。object.prototype.METHOD_NAME = ...
7.递归
递归函数可以非常高效的操作树形结构,遗憾的是,javas当前并没有提供递归优化。深度递归的函数可能会因为堆栈溢出而运行失败。
8.作用域
JavaScript不支持块作用域,只有函数作用域,意味着定义在函数中的参数和变量在函数外部不可见,而在内部任何位置定义的变量,在该函数任何地方都可见。所以,最好在函数体的顶部声明函数中可能用到的所有变量。
9.模块
使用函数和闭包来构造模块。模块是一个提供接口却隐藏状态与实现的函数或对象,通过使用函数产生模块,我们几乎可以完全摒弃全局变量的使用。它促进了信息隐藏和其他优秀的设计实践。
模块模式的一般形式:一个定义了私有变量和函数的函数;利用闭包创建可以访问私有化变量和函数的特权函数;最后返回这个特权函数,或者把它们保存到一个可以访问到的地方。
10.级联
级联技术可以产生出极富表现力的接口。它也能给那波构造“全能”接口的热潮降温,一个接口没有必要一次做太多事情。
obj.setPositionX(10)
.setPositionY(10)
.color("red")
.border("10px")
.tip("级联");
11.记忆
函数可以将先前操作的结果记录在某个对象里,从而避免无谓的重复运算。这种优化被称作记忆。JavaScript的对象和数组要实现这种优化非常的方便。比如用递归计算Fibonacci数列...
继承
JavaScript是弱类型的语言,从不需要类型转换。对象继承关系变得无关紧要。对于一个对象来说重要的是它能做什么,而不是它从哪里来。
在基于类的语言中,对象是类的示例,并且类可以从另一个类继承。JavaScript是一门基于原型的语言,这意味着对象直接从其他对象继承。
JavaScript中可能的继承模式有很多。
1.伪类
使用new前缀。伪类模式本意是想向面向对象靠拢,但它看起来格格不入。
2.原型
原型模式中会摒弃类,转而专注于对象,一个新对象可以继承一个旧对象的属性。
3.函数化(模块)
函数化模式有很大的灵活性。它相比伪类模式不仅带来的工作更少,还让我们得到更好的封装和信息隐藏,以及访问父类方法的能力。
4.部件
我们可以从一套部件中把对象组装出来。例如,我们可以构造一个给任何对象添加简单事件处理特征的函数。
数组
数组是一段线性分配的内存,它通过整数计算偏移并访问其中的元素。数组是一种性能出色的数据结构。不幸的是,JavaScript没有像此类数组一样的数据结构。
作为替代,JavaScript提供了一种拥有一些类数组特征的对象。它把数组的下标转换成字符串,用其作为属性。它明显地比一个真正的数组慢,但它使用起来很方便。它的属性检索和更新与对象一模一样,只不过多一个可以用整数作为属性名的特性。
1.长度
每个数组都有一个length属性。和大多数其它语言不同,JavaScript数组的length是没有上界的。如果用大于等于当前length的数字作为下标来存储一个元素,那么length值会被增大以容纳新元素,不会发生越界错误。length属性的值是这个数组的最大整数属性名加上1:
var arr = [];
arr[100] = true;
//arr.length === 101
设置更大的length不会给数组分配更多的空间。而把length设小将导致所有下标大于等于新length的属性被删除。
2.删除
由于JavaScript的数组其实就是对象,所以delete运算符可以用来从数组中移除元素。
var arr = [10,20,30];
delete arr[1];
// arr: [10, undefined, 30]
不幸的是,那样会在数组中留下一个空洞。因为前排的在被删除元素之后的元素保留着它们最初的属性。而你通常想要递减后面每个元素的属性。
JavaScript数组有一个splice方法用来进行数组元素的增加删除,对于大型数组来说可能会效率不高。
3.判断是否数组
JavaScript本身对于数组和对象的区别是混乱的。typeof运算符报告数组的类型是'object',这没有任何意义。我们可以通过is_array
函数来弥补这个缺陷。
var is_array = function (value) {
return value && typeof value === 'object' && value.constructor === Array;
};
遗憾的是,它在识别不同的窗口(window)或帧(frame)里构造的数组时会失败。有一个更好的方式去判断一个对象是否为数组:
var is_array = function (value) {
return Object.prototype.toString.apply(value) === '[Object Array]';
};
代码风格
- 优秀的程序拥有一个前瞻性的结构,它会预见到未来才可能需要的修改,但不会让其成为过度的负担。
- 使用K&R风格,把 { 放在一行的结尾而不是下一行的开头,因为它会避免JavaScript的return语句中的一个可怕的设计错误。(插入分号)
- JavaScript拥有C语言的语法,但它的代码块没有作用域。所以在每个函数的开始部分声明所有的变量。
- JavaScript可以方便的使用全局变量,但随着程序的日益复杂,全局变量逐渐变得问题重重。对一个脚本应用或工具库,尽量只使用唯一一个全局变量。每个对象都有它自己的命名空间。使用闭包能提供进一步的信息隐藏。
毒瘤
展示JavaScript一些难以避免的问题特性。你必须知道这些问题并准备好应对措施。
1.全局变量
全局变量可以被程序的任何部分在任意时间修改,它们使得程序的行为变得极度复杂。在程序中使用全局变量降低了程序的可靠性。
全局变量使得在同一个程序中运行独立的子程序变得困难。如果某些全局变量的名称碰巧和子程序中的变量名称相同,那么他们将会相互冲突,可能导致程序无法运行,而且通常难以调试。
JavaScript的问题不仅在于它允许使用全局变量,而且在于它依赖全局变量。JavaScript没有连接器,所有的编译单元都会载入一个公共的全局对象中。
共有3种方式定义全局变量:
- 第1种是在任何函数之外放置一个var语句:
var foo = value;
- 第2种是直接给全局对象添加一个属性。全局对象时所有全局变量的容器。在Web浏览器里,全局对象名为window:
window.foo = value;
- 第3种是直接使用未经声明的变量,这被称为隐身的全局变量:
foo = value;
2.作用域
JavaScript的语法来源于C。它采用了块语法,却没有提供块级作用域:代码块中声明的变量在包含此代码块的函数的任何位置都是可见的。所以应该在每个函数的开头部分声明所有的变量。
3.自动插入分号
JavaScript有一个自动修复机制,它试图通过自动插入分号来修正有缺损的程序。但是,千万不要指望它,它可能会掩盖更为严重的错误。
return返回一个值时,这个值表达式的开始部分必须和return位于同一行,否则return后面被插入分号后,返回结果将是undefined。
4.Unicode
JavaScript设计之初,Unicode预期最多会有65536个字符。但从那以后它的容量慢慢增长到了拥有一百万个字符。
JavaScript的字符是16位的,足以覆盖原有的65536个字符。剩下的百万字符中的每一个都可以用一对字符来表示。Unicode把一对字符视为一个单一的字符。而JavaScript认为一对字符是两个不同的字符。
5.typeof
typeof null返回的是'Object',而不是null
对于正则表达式typeof /a/
各种JavaScript的实现版本不太一致
6.parseInt
parseInt把一个字符串转换为整数,它在遇到非数字时会停止解析。
parseInt("16")与parseInt("16 haha")会产生相同的结果,它不会提醒我们出现了额外的文本。
7.+运算符
+运算符用于加法运算或字符串连接。如果其中一个运算数是一个(空)字符串,它会把另一个运算数转换成字符串并返回。如果你打算用 + 去做加法运算,请确保两个运算数都是Number。这个复杂的行为是bug的常见来源。
8.NaN
typeof NaN === 'number' //true
但是NaN表示的不是一个数字,该值可能会在试图把非数字形式的字符串转换为数字时产生。
typeof不能辨别数字和NaN,而且NaN也不等同于它自己:
NaN === NaN //false
NaN !== NaN //true
isNaN(NaN) //true
isNaN(0) //false
isNaN("0") //false
isNaN("haha") //true
9.伪数组
arguments不是一个数组,它只是一个有着length成员属性的对象。
检测数组:
if(Object.prototype.toString.apply(VALUE) == "[object Array]") {
//VALUE是一个数组
}
10.假值
//值 (类型)
0 //Number
NaN //Number
"" //String
false //Boolean
null //Object
undefined //Undefined
undefined和NaN并不是常量。它们居然是全局变量,而且你可以改变它们的值。千万不要这样做。
11.hasOwnProperty
hasOwnProperty方法可以用做一个过滤器去避开for in语句中的一个隐患。遗憾的是,它是一个方法,而不是一个运算符,所以在任何对象中,它可能会被一个不同的函数甚至一个非函数的值所替换。
11.对象
JavaScript的对象永远不会是真的空对象,因为它们可以从原型链中取得成员属性。有时候那会带来麻烦。
糟粕
展示JavaScript一些有问题的特性,但我们很容易就能避免它们。
1.==
如果两个运算数类型不同,和!=会强制转换运算数值的类型。永远不要使用它们!
使用=和!,只有在两个运算数类型相同且拥有相同值时=才会返回true,!==返回false。
2.with语句
with语句本意是用来快捷访问对象的属性,不幸的是,它的结果可能有时不可预料,所以应该避免使用它。且它本身就严重影响了JavaScript处理器的速度,因为它阻断了变量名的词法作用域。
3.eval
eval使得代码更加难以阅读。还使得性能显著降低,因为它需要运行编译器,还会让JSLint无法检测其中的问题。
浏览器提供的setTimeout和setInterval函数,参数传人字符串时也会调用eval。
4.continus语句
continue语句跳到循环的顶部,通过移除continue语句之后的代码,性能都会得到改善!
5.switch穿越
不要使用switch穿越,这会让我们更加容易发现不小心造成的case条件穿越导致的bug。
6.缺少块的语句
if, while, do 或 for 语句可以接受一个括在花括号中的代码,也可以接受单行语句。但那会模糊了程序的结构,不要这么做。
7.位运算符
JavaScript的执行环境一般接触不到硬件,所以非常慢。JavaScript很少被用来执行位操作。
8.function语句
不要在if中使用function语句,不同的浏览器在解析时的处理是不同的,这就会造成可移植性的问题。
一个语句不能以函数表达式开头,因为官方的语法假定单词function开头的语句是一个function语句。解决方法是把函数调用括在一对圆括号中:
(function () {
//
}());
9.类型的包装对象
JavaScript有一套类型的包装对象,例如:new Boolean(false)
会返回一个对象,该对象有一个valueOf方法会返回被包装的值。这其实完全没有必要,并且又是还令人困惑。
不要使用new Boolean
, new Number
, new String
, 也请避免使用new Object
和new Array
,可使用 {} 和 [] 来代替。
10.new
使用new创建原型的新对象时,会涉及到this的绑定问题,如果在创建对象是忘记加上new,则会把this绑定到全局对象,造成全局变量污染。所以尽量避免去使用new。
11.void
在JavaScript中void是一个运算符,它接受一个运算数并返回undefined。这没什么用,且令人困惑。应避免去使用它。
阅读笔记《JavaScript语言精粹》的更多相关文章
- 阅读《RobHess的SIFT源码分析:综述》笔记
今天总算是机缘巧合的找到了照样一篇纲要性质的文章. 如是能早一些找到就好了.不过“在你认为为时已晚的时候,其实还为时未晚”倒是也能聊以自慰,不过不能经常这样迷惑自己,毕竟我需要开始跑了! 就照着这个大 ...
- RobHess的SIFT源码分析:imgfeatures.h和imgfeatures.c文件
SIFT源码分析系列文章的索引在这里:RobHess的SIFT源码分析:综述 imgfeatures.h中有SIFT特征点结构struct feature的定义,除此之外还有一些特征点的导入导出以及特 ...
- RobHess的SIFT源码分析:综述
最初的目的是想做全景图像拼接,一开始找了OpenCV中自带的全景拼接的样例,用的是Stitcher类,可以很方便的实现全景拼接,而且效果很好,但是不利于做深入研究. 使用OpenCV中自带的Stitc ...
- 阅读《RobHess的SIFT源码分析:综述》笔记2
今天开始磕代码部分. part1: 1. sift特征提取. img1_Feat = cvCloneImage(img1);//复制图1,深拷贝,用来画特征点 img2_Feat = cvCloneI ...
- element-ui button组件 radio组件源码分析整理笔记(一)
Button组件 button.vue <template> <button class="el-button" @click="handleClick ...
- element-ui 组件源码分析整理笔记目录
element-ui button组件 radio组件源码分析整理笔记(一) element-ui switch组件源码分析整理笔记(二) element-ui inputNumber.Card .B ...
- element-ui Carousel 走马灯源码分析整理笔记(十一)
Carousel 走马灯源码分析整理笔记,这篇写的不详细,后面有空补充 main.vue <template> <!--走马灯的最外层包裹div--> <div clas ...
- STL源码分析读书笔记--第二章--空间配置器(allocator)
声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...
- element-ui MessageBox组件源码分析整理笔记(十二)
MessageBox组件源码,有添加部分注释 main.vue <template> <transition name="msgbox-fade"> < ...
- element-ui switch组件源码分析整理笔记(二)
源码如下: <template> <div class="el-switch" :class="{ 'is-disabled': switchDisab ...
随机推荐
- HDU 6206 Apple (高精确度+JAVA BigDecimal)
Problem Description Apple is Taotao's favourite fruit. In his backyard, there are three apple trees ...
- iOS动画的要素:CALayer维护数据模型和图片,沟通了CPU和GPU--视图中与图形绘制相关的功能
1)iOS动画的模型:三层树模型: CALayer维护数据模型和图片,沟通了CPU和GPU:数据模型和图片本尊有CPU生成和维护:图片动画由GPU合成和呈现: https://developer.ap ...
- HDU 6386 Age of Moyu 【BFS + 优先队列优化】
任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6386 Age of Moyu Time Limit: 5000/2500 MS (Java/Others ...
- 2018 Multi-University Training Contest 4 Problem J. Let Sudoku Rotate 【DFS+剪枝+矩阵旋转】
任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6341 Problem J. Let Sudoku Rotate Time Limit: 2000/100 ...
- Cow Relays 【优先队列优化的BFS】USACO 2001 Open
Cow Relays Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Tota ...
- Educational Codeforces Round 56 (Rated for Div. 2) D. Beautiful Graph 【规律 && DFS】
传送门:http://codeforces.com/contest/1093/problem/D D. Beautiful Graph time limit per test 2 seconds me ...
- 2springboot:快速创建springboot项目
使用IDEA快速创建springboot项目流程: 创建新的项目选择 项目的命名以及包名 需要什么包就导入什么包 进行测试的单元 <dependency> <groupId>o ...
- mysql忘记密码重置密码方法
https://blog.csdn.net/weidong_y/article/details/80493743
- PL/SQL添加Oracle对象
1.首先用system的身份进入数据库 2.找到user文件夹 3.右击新建用户 在“创建用户”窗口中,输入新用户的名称.口令,默认表空间.临时表空间等 4.赋予新用户权限,赋予其角色权限:conne ...
- Vue--- 一点车项目 连接数据库
Vue--- 一点车项目 连接数据库 创建连接数据库配置 ###导入 const Koa = require('koa'); const Router = require('koa-router') ...