一、基础JavaScript
A.背景
1.早期没有异常
2.支持函数式编程(高阶函数、内置的map和reduce)和面向对象编程(对象、继承)的混合编程风格
B.语法
1.原始值包括布尔值、数字、字符串、null和undefined,其他的值都对象。
2.typeof主要用于原始值,instanceof用于对象
二、为什么选择JavaScript
三、JavaScript的性质
A.JavaScript的本质
1.它是动态的
2.它是动态类型
3.它是函数式和面向对象的
4.它静默失败
5.它部署的是开源代码
6.它是网络平台的一部分
四、JavaScript是如何创造出来的
五、标准化ECMAScript
六、JavaScript的历史里程碑
七、JavaScript的语法
A.表达式与语句
1.表达式:表达式将会产生一个值,它可以写在任何需要值的地方。
2.语句:语句表示了一种行为,如循环和if语句,一个程序基本上就是语句的序列。凡是在JS期望语句的地方都可以写表达式,这样的语句叫做表达式语句。反之则不然,不能在需要表达式的地主使用语句。
3.eval需要返回对象时需要小括号,立即调用函数表达式最外层也需要小括号。
B.严格模式
1.严格格式需要注意:启用严格模式可能会破坏再有的代码;细心打包;变量必须显式声明;函数必须在作用域的顶部声明;设置或删除不可改变的属性会抛出异常;不合格标识符不能删除;with语句不能再被调用;没有八进制的数字 ;
八、值
A.JavaScript中的类型体系
1.JS是动态类型的语言:变量的类型在编译的时候是不确定的;
2.JS内置的转换机制只支持布尔值、数字、字符串和对象。
B.原始值和对象
1.每一个对象有唯一的标识符并且只(严格)和自身相等;所有的原始值,只要编码值相同,则被认为相等;
2.原始值:按值进行比较;不可改变;固定类型的组合;
3.对象:常见对象(简单对象,对象字面量来创建;数组,可以通过数组字面量创建;正则表达式;),特点(按引用进行比较;默认可变;用户可扩展;)
C.undefined和null
1.undefined:表示“没有值”(既不是原始值也不是对象)。
2.null:意思是“没有对象”。在用到对象时它表示空值。
D.原始值的包装对象
1.布尔值、数字和字符串这三种原始值都有相应的构造函数:Boolean、Number、String。它们的实例(称为包装对象)包含原始值。两种用法:作为构造函数,它们创建的对象和它们包装的原始值有很大的不同;作为函数,它们会将值转换为相应的原始值。
2.一种使用包装对象的场景:在你需要对一个原始值增加属性时,首先要对这个原始值进行包装并且给包装后的对象增加属性,而当你要使用值之前需要先对它进行去包装。通过调用包装构造函数来对原始值进行包装,通过调用valueOf(0来对原始值进行去包装(布尔值不能正确提取)。
3.原始值没有私有方法,但是它会从各自的包装器中借调方法。宽松模式中,原始值会在运行过程中转换为包装器;严格模式中,对包装器原型方法的调用是透明的;
E.强制类型转换
1.强制类型转换会隐藏bug
https://github.com/zhangyue0503/html5js/blob/master/speakingjavascript/8.js
九、运算符
A.运算符和对象
1.所有的运算符都会强制要求它们的运算为合适的类型。会被转换为原始值。数组会转换成字符串然后再把它们拼接起来。
B.赋值运算符
1.赋值运算是一种表达式,它用来计算要被赋予的值。因此可以进行链式赋值。
2.复合赋值运算符:+=、*=、/=、%=、-=,<<=、>>=、>>>=、&=、^=、|=
C.等号运算符:===和==
1.两种方式判断两个值是否相等
2.严格相等
3.普通(宽松)相等(==,!=)
D.通过typeof和instanceof判断值类型
十、布尔类型
A.转换成布尔值
1.undefined:false、null:false、布尔值:与输入相同、数字:0,NaN为false、字符串:’’为false、对象:总为true
2.手动转换:Boolean(value)、value?true:false、!!value
十一、数字
A.转换为数字
1.Number(value) --推荐
2.parseFloat(str) —对非字符串净系低
B.特殊的数字值
1.两个错误值NaN和Infinity
2.两个零值,+0和-0
3.NaN和它本身不相等,使用isNaN()判断
4.Infinity:表示大到无法表示的数字,或者除以了0,使用isFinite()可检查一个值是否是实际的值(既不是Infinity也不是NaN)
C.安全的范围
1.Math.pow(2,1023)正常Math.pow(2,1024)返回Infinity
2.安全的整型:Number.MAX_SAFE_INTEGER = Math.pwo(2,53)-1
D.转换为整数
1.Math函数:Math.floor()、Math.ceil()、Math.round()
2.定制的ToInteger()函数:return x<0?Math.ceil(x):Math.floor(x);
3.二进制位运算操作符
4.全局函数parseInt()
E.Number原型方法
1.Number.prototype.toFixed(N):返回不使用指数表示的数字,舍入到小数点后第N位,默认为0,如果数字大于或等于10的21次方,这个方法的作用和toString()相同
2.Number.prototype.toPrecision(N):在使用类似toString()等转换算法前会将尾数精确到N位,如果没有给出N,直接使用toString()
3.Number.prototype.toString(N):参数N指定了显示数字的系统使用的基数。指数标注:如果一个数字的小数点前有多于21个的数字;如果一个数字以0开头,并且紧跟了超过多于五个0和一个非0的数字;
4.Number.prototype.toExponential(N):强制使用指数标注来表示一个数字。
十二、字符串
A.手动转换为字符串
1.String(value)
2.’’+value
3.value.toString()
十三、语句
A.循环语句和条件主体
1.不要用for-in来遍历数组:for-in只会遍历索引而不是数组元素;for-in还会遍历所有的(非索引)属性值;
B.with语句
1.已被废弃
2.性能问题、代码可能会产生不可预期的结果、代码压缩工具无法压缩
十四、异常捕获
A.什么是异常捕获
两个原则:如果一处出错的含义不能被描述,那么就抛错;找到一个可以捕获错误的位置,捕获异常;
B.JavaScript中的异常捕获
1.thorw new Error(‘……’);
C.Error构造器
Error是通用异常构造器
RangeError表示一个数值超出了允许的范围
ReferenceError表示发现了一个非法的引用值,通常这是一个未知的变量
SyntaxError表示产生了一个语法解析错误
TypeError表示一个被操作值的实际类型与其期望的类型不一致
URIError表示某个全局的URI控制函数的使用不兼容其定义
D.栈跟踪
使用e.stack
https://github.com/zhangyue0503/html5js/blob/master/speakingjavascript/14.js
十五、函数
A.JavaScript中函数的3种形式
非方法的函数(“普通函数”):id(‘hello')
构造器:new Date()
方法:obj.method()
B.定义函数
1.函数表达式:var a = function(){},具名函数表达式(使得函数表达式可以引用它自己,对于递归有用):var a = function m(){}
2.函数声明:function a(){},等于函数表达式var a = function(){}
3.Function构造器:var a = new Function(),相对比较慢,并且把代码放在了字符串中。
C.函数提升
1.函数提升:将函数的声明放到作用域的开始。函数声明是做了完全提升的,而变量声明则是部分提升。
D.函数声明还是函数表达式
1.函数声明会做代码提升,因此你可以在源码中先于函数的定义来调用函数
2.函数声明具有名字
E.控制函数调用:call()、apply()和bind()
1.func.apply(thisValue,argArray),thisValue可以指定执行func时的this值
2.func.bind(thisValue,arg1,……argN),这个方法会执行部分的函数功能,它会创建一个新的函数,这个函数会调用func,并会将thisValue指定为this,同时应用参数arg1至argN,紧随其后的是新函数的实际参数。
F.参数缺失或者超出时的处理
1.arguments变量只存在于函数中(包括方法)。它是一个类数组的对象,包含了当前函数调用的所有实参。
2.arguments是类数组的,但又非数组,有一个length属性,但没有数组的方法
3.arguments是一个对象,因此它支持所有的对象方法和操作。
4.模拟参数的引用传递需要把值放在数组中,JS没有引用传递
G.具名参数
1.优点:它们对函数的参数进行了描述,同时它们对于处理可选参数的场景也很有用。
2.JS不支持具名参数,但可以通过对象字面量来命名参数,并将对象作为一个实参传入函数。
https://github.com/zhangyue0503/html5js/blob/master/speakingjavascript/15.js
十六、变量:作用域、环境和闭包
A.变量以函数为作用域
1.只有函数可以产生新的作用域,代码块在作用域中是不起作用的。
2.赋值给一个未定义的变量,不通过var的话,会产生一个全局的变量。
B.通过IIFE引入新的作用域
1.立即执行的函数表达式(IIFE),(function(){/*内容*/}());,它是立即执行的,必须是一个表达式,最后必须要有分号。
2.IIFE变体:前缀运算符,使用!或void,!function(){}();,void function(){}();,可以忘了分号结尾
3.IIFE变体:预内置表达式上下文,为IIFE强制执行表达式上下文并不是必需的,如果已经在一个表达式的上下文里面,那么你不必使用括号或者前缀操作符。
4.IIFE变体:传参的IIFE,var x = 23;(function(twice){console.log(twice);}(x*2));
5.IIFE的应用
C.全局变量
1.避免创建全局变量:程序中依赖全局作用域的代码片段会产生一些边缘效应,程序可能不够健壮,会产生一些不可预期的效果,重用性更低;一个WEB页面上面所有JS都共享一个相同的全局作用域以及其全局变量,可能产生名字的冲突问题。
2.模块系统可以减少全局变量的引入
D.全局对象
1.在全局作用域中,this指向全局对象
2.在浏览器this是window对象,在node.js中this是global
E.环境:变量的管理
1.当程序运行到变量所在的作用域时,变量被创建。这时它需要一个存储的空间,而JS中提供存储空间的数据结构就被称为环境。
2.动态维度:调用函数,执行上下文的栈,函数每调用一次就会创建一个新的环境将标识符和变量做映射。
3.词法维度:与外部作用域进行关联,环境链,JS会通过内部属性[[Scope]]来记录函数的作用域,在函数调用时,JS会为这个函数所有的新作用域创建一个环境,这个环境有一个外层域(outer),它通过[[Scope]]创建并指向了外部作用域的环境。
F.闭包:使得函数可以维持其创建时所在的作用域
1.如果一个函数离开了它被创建时的作用域,它还是会与这个作用域以及其外部的作用域的变量相关联。
2.闭包是一个函数外加上该函数创建时所建立的作用域。闭包的名字来源于闭包“关闭”了一个函数中自由变量的访问权。
3.闭包是一个代码执行完成之后离开作用域环境依旧存在的例子。
https://github.com/zhangyue0503/html5js/blob/master/speakingjavascript/16.js
十七、对象与继承
A.单一对象
1.笼统的说,JS中所有的对象都是从字符串(string)到值(value)的映射。一个对象中的某一项(键、值)称为属性。属性的键始终是文本字符串。属性的值可以是任何JS值,包括函数。方法是值为函数的属性。
2.属性的种类:属性(property,数据属性)、访问器(Accessor)、内置属性(Internal property)
3.对象字面量:你可以在没有类的情况下直接创建对象,然后进行抽象处理。
4.delete删除自有属性时返回false,其他都返回true
5.通过.和[]都可以访问对象属性,如obj.v和obj[‘v’]
B.this作为函数和方法的隐式参数
1.当你调用一个函数时,this总是作为一个(隐式)参数
2.在调用函数时设置this:call()、apply()和bind()
3.缺陷:提取方法时丢失this,使用bind()
4.缺陷:方法中的函数会掩盖this:使用that、使用bind()、使用forEach的thisValue
C.对象间的原型关系
1.两个对象间的原型关系类似继承:每个对象都可以把另一个对象作为它的原型,并继承原型的所有属性。
2.对象通过内部属性[[Prototype]]指定它的原型。通过[[Prototype]]属性连接成的对象链称为原型链。
3.原型链的行为就好像它是一个单独的对象。一个对象的属性可以覆写之后对象的相同键的属性,前者被先找到。
4.原型对于对象间数据共享十分有用:多个对象可以有相同的原型,这个原型持有所有的共享属性。
5.特殊属性__proto__,可以直接访问[[Prototype]],否则使用Object.create(原型,对象);
D.遍历和检测属性
1.遍历和检测属性的相关操作受到两个情况影响:继承(自有属性与继承属性)、枚举(枚举属性与非枚举属性)
E.属性特性和属性描述符
1.属性特性是属性的原子构建块,具有[[Value]]、[[Writable]]、[[Get]]、[[Set]]、[[Enumerable]]、[[Configurable]]
2.属性描述符:是一个编码属性特性的对象,每个描述符的属性对应一个特性。
3.一些操作可能通过属性描述符获取和设置属性的特性
4.复制对象:拷贝必须具有与原对象相同的原型;拷贝必须具有与原对象相同的属性和特性;
5.枚举性:最佳实践
F.保护对象
1.防止扩展:使用Object.preventExtensions(obj)
2.封闭:Object.seal(obj),防止扩展,并设置所有的属性“不可配置”
3.冻结:Object.freeze(obj),使所有的属性不可写,且封装obj,obj不能扩展,所有的属性都是只读的,且不能改变
4.保护对象只是浅层的,它影响自有属性,但不影响这些属性的值
G.构造函数——实例工厂
1.构造函数(简称构造器)帮助生成对象,构造函数在某些方面和普通函数类似,但命名、设置和调用不同。
2.构造函数创建的对象称为实例。包括两部分:
3.new操作符执行步骤:
4.new操作符:可以从构造函数返回一个任意的对象,它成为new操作符的返回结果。
5.实例的constructor属性
6.instanceof运算符
7.实现构造函数的小技巧
H.原型属性中的数据
1.对于实例属性,避免使用带初始值的原型属性
2.避免非多态的原型属性
3.多态的原型属性
I.保持数据私有性
1.构造函数环境中的私有数据(Crockford私有模式)
2.使用标记的键的属性保存私有数据
3.使用具体化键的属性保存私有数据
4.通过IIFE保持全局数据私有
J.构造函数之间的继承
1.继承实例属性:实例的属性是在它自己的构造函数中设置的,因此继承父构造函数的实例属性会涉及调用其父构造函数,不要通过new调用Super,因为这样会创建一个新的Super实例。使用Super.call(this,……)
2.继承原型属性:指定Sub.prototype的原型为Super.prototype,使用Object.create()
3.确保instanceof正常工作:意味着每个Sub的实例必须也是Super的实例。
4.覆写方法
5.父调用:从(原型中的)当前方法中的主对象“之后”,开始查找;查找方法;用当前的this调用此方法,基本原理是,父方法(supermethod)必须作为当前方法使用同一实例调用,父方法必须可以访问同一实例的属性;
6.避免硬编码父构造函数的名字:可以通过把父原型赋值给Sub的一个属性来避免这个问题。
K.所有对象的方法
1.转换为原始值
2.Object.prototype.toLocaleString():返回特定于本地语言环境的代表对象的字符串
3.原型式继承和属性
L.泛型方法:借用原型方法
1.通过字面量访问Object.prototype和Array.prototype
2.类似数组的对象和泛型方法:像数组但没有数组的方法且没有数组的原型链
M.缺陷:Object作为Map使用
1.继承影响读取属性
2.覆写会影响调用方法
3.特殊属性__proto__:对象不能在键为’__proto__’的属性中存储映射数据,如果允许使用,属性对它进行转义
4.字典模式:没有原型的对象更适合用作映射,没有继承的属性
N.备忘录:对象的使用*P267
https://github.com/zhangyue0503/html5js/blob/master/speakingjavascript/17-1.js
https://github.com/zhangyue0503/html5js/blob/master/speakingjavascript/17-2.js
十八、数组
A.概述
1.数组是映射,不是元组
2.数组也可以具有属性:但并不认为属性是数组的一部分
B.创建数组
1.字面量创建数组,后面的逗号会被忽略
2.数组构造函数:使用Array,可以创建给定长度的空数组,或给定元素的数组。new是可选的,作为普通函数调用和作为构造函数调用是相同的。
3.尽量避免使用给定元素的数组
C.数组索引
1.范围:0<=i<2^32-1,在这个范围之外的索引被视为普通的属性键。它们不会作为数组元素呈现,且不影响length属性。
2.delete删除数组元素,会产生空缺(不会更新属性length),也可以通过减少数组长度来删除数组尾部的元素。
3.ECMAScript规范的索引解释:
4.属性键(P)必须等于以下计算结果:
5.属性键(P)字符串:
D.长度
1.length的基本功能是追踪数组的最大索引,因此不计算元素的个数,必须编写函数来实现,先用forEach跳过空缺的元素
E.数组中的“空缺”
1.数组是由索引(indice)到值(value)的映射。这意味着数组可以有“空缺”(hole),索引个数小于数组长度说明数据缺少一些元素。在缺少元素的索引处读取该元素会返回undefined
2.含有空缺的数组称为稀疏(sparse),不含空缺的数组称为密集(dense)。密集数组是连续的,且在每个索引处(从0开始,到length-1结束)都存在元素。
3.涉及数组的一些操作会忽略空缺
F.添加和删除元素(破坏性地)
G.排序和颠倒元素顺序(破坏性地)
H.合并、切分和连接(非破坏性地)
I.值的查找(非破坏性地)
J.迭代(非破坏性地)
1.检测方法:arr.examinationMethod(callback,thisValue?)
2.转化方法:function callback(element,index,array)
3.归约函数:function callback(previousValue,currentElement,currentIndex,array)
https://github.com/zhangyue0503/html5js/blob/master/speakingjavascript/18.js