第1章
js是专为网页交互而设计的脚本语言,由3部分组成:
- ECMAScript,提供核心语言功能
- DOM文档对象模型,提供访问和操作网页内容的方法和接口
- BOM浏览器对象模型,提供与浏览器交互的方法和接口
js是一种脚本语言、解释性语言、动态类型语言、基于对象的语言
第2章 在HTML中使用JavaScript
- 包含在< script>元素内部的JavaScript代码将被从上至下依次解释,解析js代码时(包括下载js文件时),页面的处理也会暂时停止(页面中的其余内容不会被浏览器加载或显示,head元素中的js代码需要被下载、解析和执行后,才开始呈现页面内容:浏览器在遇到body标签时才开始呈现内容),因此通常将js代码放入< body>元素中页面的内容后面;
- < script>的src属性可以包含来自外部域的js文件;(安全性问题)跨域
- 延迟脚本,< script>标签的defer属性,当defer = “defer”,js脚本将会延迟到浏览器遇到< /html>时才执行,理应按顺序,但实际情况不一定按顺序,因此最好只包含一个延迟脚本;
- defer 属性规定是否对脚本执行进行延迟,直到页面加载为止,以便加快处理文档的速度。因为浏览器知道它将能够安全地读取文档的剩余部分而不用执行脚本,它将推迟对脚本的解释,直到文档已经显示给用户为止。
- 异步脚本,< script>标签的asynv属性,只适用于外部脚本文件,并告诉浏览器立即下载,但并不保证按先后顺序执行;
- 推荐使用外部文件:
1)易于维护
2)可缓存:若多个页面使用同一js文件,只需下载一次,加快了页面加载速度
*指定async属性的目的不是让页面等待两个脚本下载和执行,从而异步加载其他内容。为此,建议异步脚本不要在加载期间修改DOM(P14) - < noscript>当浏览器不支持JavaScript时让页面平稳地退化;
1)浏览器不支持脚本
2)浏览器支持脚本,但脚本被禁用
<noscript><p>本页面需要浏览器支持(启用)JavaScript。</p>
</noscript>
defer、async作用和区别分析
8. 文档模式:混杂模式和标准模式(影响css内容的呈现)
doctype
若在文档开始处没有声明文档类型,则所有的浏览器都会默认开启混杂模式,但这样并不值得推荐,因为不同浏览器在这种模式下的行为差异非常大,如果不使用某些hack技术,跨浏览器的行为没有一致性可言。
标准模式声明:HTML5
<!DOCTYPE html>
- 严格模式
为js定义的解析与执行模型:在严格模式下,ECMAScript3中的一些不确定的行为将得到处理,对某些不安全的操作也会抛出错误
“use strict“
onload事件
window.onload
第3章 基本概念
3.1~3.3 语法、关键字和保留字、变量
- 区别大小写:True和False都不是Boolean类型;
- typeof是关键字而不是函数名,使用时不需要加括号;
- typeof null 返回object,null被认为是一个空的对象引用,如果定义的变量准备在将来用于保存对象,最好初始化为null而不是其他值;
- 隐式全局变量很难维护,不推荐这么用;
- 可以使用一条语句定义多个变量
var message = "hi",found = false,age =29;
3.4 数据类型
- typeof的返回值:4+1+1(5种基本数据类型除了null、object、function)
- undefined类型只有一个值,即其本身;
- null是另一个只有一个值的数据类型;
- undefined值是派生自null值的,因此undefined == null返回true;
- 对未声明和未初始化的变量,typeof的返回值居然都是undefined;
- 数值字面量:八进制必须以0开头,其后是0~7,若超出范围,前导0才会被忽略;十六进制前2位必须是0x;
- 保存浮点数值的内存空间是保存证书的2倍,因此ECMAScript会不失时机地将浮点数值转为整数;
var floatNum = 3.15e7; //等于31500000
- 浮点数值最高精度是17位小数,但其算术运算的精度远不及整数,因此无法测试特定的浮点数值;
- NaN用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)
- isNaN()会尝试将参数转为数值(我理解,先Number(参数));
- isNaN()也适用于对象:valueOf() → toString() ;
- Number(“ ”) 得到0;而parseInt(“ ”)得到NaN;
- Number()适用于任何数据类型;parseInt()、parseFloat()只用于字符串;
- parseInt(): 更多地考虑参数是否符合数值模式,
1)找到第一个非空格字符;
2)若第一个非空格字符不是数字或负号,则返回NaN;
3)parseInt()会识别各进制,但ECMAScript3和5存在分歧,因此推荐提供第二个参数(基数); - parseFloat()解析到遇见第一个无效的浮点数字字符为止(第二个小数点无效,并且会忽略先导0,只解析十进制);
- 字符串中若包含转义序列,在str.length时,转移序列当1个字符计算;
- null和undefined没有toString()方法,此时可用Sting()方法;
- toString()方法可传基数;
* 例子
var num1 = 070; // 八进制的56
var num2 = 079; // 无效的八进制数值-解析为79
var num3 = 0xA; // 十六进制的10var floatNum1 = .1 // 有效,但不推荐
var floatNum2 = 1.; //小数点后面没有数字 - 解析为1
var floatNum3 = 10.0; // 整数,解析为10isNaN(NaN); // true
isNaN(10); // false
isNaN("10"); // false (可以被转换成数值)
isNaN("blue"); // true
isNaN(true); // false(可以被转换成数值)Number(" ") // 0
Number("000011") // 11parseInt("1234blue") // 1234
parseInt(" ") // NaN
parseInt("0xA") // 10 (十六进制数)
parseInt(22.5) // 22
parseInt("070") // 56 (八进制数)
parseInt("70") // 70 (十进制数)
parseInt("0xf") // 15 (十六进制数)parseInt(“10”,2) // 2(二进制数)
parseInt(“10”,8) // 8(八进制数)
parseInt(“10”,10) // 10(十进制数)
parseInt(“10”,16) // 16(十六进制数) parseFloat("1234blue") // 1234
parseFloat("0xA") // 0
parseFloat("22.5") // 22.5
parseFloat("22.34.5") // 22.34
parseFloat("0908.5") // 908.5
parseFloat("3.125e7") // 31250000
第4章 变量、作用域和内存问题
函数提升优先级高于变量提升
1.typeof:基本数据类型 instanceof:引用类型
- 虽然在检测基本数据类型时typeof是非常得力的助手,但在检测引用类型时,这个操作符的用处不大。我们并非想知道某个值是对象,而是想知道它是什么类型的对象。instanceof操作符;
result = variable instanceof constructor
如果变量是引用类型的实例,则返回true;- instanceof检测基本数据类型永远返回false:基本数据类型不是对象;
- instanceof操作符假定单一的全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的Array构造函数。使用
value instanceof Array
可能不适用; - 全局执行环境被认为是window对象,所有全局变量和函数都是作为window对象的属性和方法创建的;
- 全局执行环境直到应用程序退出(例如关闭网页或浏览器)时才会销毁;
- js没有块级作用域(其他语言中,花括号封闭的代码有自己的作用域):指if、for的花括号内,依然是全局作用域;
for(var i = 0; i < 10; i++) {}
变量i即使退出了循环,也依然存在于循环外部的执行环境中;- 不建议隐式全局变量这种操作方式;
- 当局部变量和全局变量同名:如果不使用window.color,便无法访问全局变量;
- 对于上一点,访问局部变量快于全局变量,因为不用向上搜索作用域链;
- 垃圾收集:标记清除和引用计数方式;
- 对于循环引用的问题:最好在不使用时,手工断开原生js和dom之间的联系
element.someObject = null
- 分配给web浏览器的内存比其他桌面应用少,目的是防止运行js的网页耗尽系统内存而导致系统崩溃;
- 解除引用:一旦数据不再有用,设置其值为null来释放其引用;
2.执行环境及作用域
- 执行环境(简称环境),定义了变量或函数有权访问的其他数据,决定了她们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
- 当代码在一个环境中执行时,会创建变量对象的一个作用域链。如果这个环境是函数,则将其活动对象作为变量对象,即
arguments
对象;作用域链的下一个变量对象来自外部环境,最后一个对象是全局执行环境的变量对象。 - 内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。每个环境可以向上搜索作用域链。
- 延长作用域链:
with
try catch
语句,都会在作用域链的前端添加一个变量对象。P75 - 参数实际上是函数的局部变量。
执行环境及作用域
var color = 'blue'
function changeColor() {var anotherColor = 'red'function swapColors() {var tempColor = anotherColoranotherColor = color color = tempColor// 最内层函数可以访问全局的color,外层函数的局部变量anoteColor 和自己的局部变量tempColor}swapColors()// 全局函数可以访问全局的color和自己的局部变量anotherColor,但不能访问内部函数的tempColor
}
changeColor()
- 函数被调用时,活动对象是:this、arguments、和其他命名参数;
- 函数这类的局部环境的变量对象,只在函数执行过程中存在。当函数执行完毕后,局部活动对象就会被销毁;
- 创建函数时,先创建一个预先包含全局变量对象的作用域链,当调用函数时,会为函数创建执行环境,创建函数的活动对象,并将其推入执行环境作用域链的前端
闭包:有权访问另一个函数作用域中的变量的函数
- 重要的是,在外部函数执行完毕后,其活动对象也不会被销毁,因为内部匿名函数(闭包)仍然在引用这个活动对象。(但它的执行环境的作用域链会被销毁)直到匿名函数被销毁后,外部函数的活动对象才销毁。
- 匿名函数被返回,而且在其他地方被调用,也仍然可以访问变量
key
function createFunction(key) {return function(obj1, obj2) {var v1 = obj1[key]var v2 = obj2[key]if (v1 < v2) {return -1} else if (v1 > v2) {return 1} else {return 0}}
}
第5章 引用类型
5.1 Object
- 访问对象属性值(方括号方法,属性名一定要加双引号):
person["first name"]
5.2 Array
- 数组的每一项都可以存储任何类型的数据;
- 使用构造函数创建对象、数组时,省略new关键字,效果相同:
var obj = Object() <=> var obj = new Object()
var arr = Array() <=> var arr = Array()
- 避免这样字面量数组:
var arr = [1,2,] // 可能会创建包含2项或3项的数组
var arr= [,,,,,] // 可能会创建包含5项或6项的数组
- P87 与对象一样,在使用数组字面量表示法时,也不会调用Array构造函数;
- 新增的每一项都会取得undefined;
var arr = [1,2,3] arr.length = 4 // arr会新增一项,undefined
- 检测数组
Array.isArray(value)
(instanceof可能不适用)
这个方法确定某个值到底是不是数组,而不管它是在哪个全局执行环境中创建的; - 数组调用
toString()
:返回逗号拼接每个值的字符串形式(最终结果是一个字符串);
数组调用toLocaleString()
: 对数组每一项调用这个方法;
alert(数组) // 由于alert()要接收字符串参数,所以会在后台调用toString()
join()
方法只接受一个参数,作为分隔符;若无参数或参数是undefined,则以逗号作为分隔符;
5.3 Date
5.4 RegExp / /+标志
- 3个标志:
g:全局模式,应用于所有字符串,而非在发现第一个匹配项时立即停止;
i:不区分大小写;
m:多行模式; - 实例方法:
reg.exec(str)
reg.test(str)
5.5 Function
- 函数是对象,函数名是指针;
- 函数没有重载:若声明了2个同名函数,后者会覆盖前者;
- 解析器会率先读取函数声明,而函数表达式,需等到解析器执行到它所在的代码行,才会真正被解释执行;
- 函数内部arguments对象,拥有callee属性,指向函数;
- 递归方法,应当使用arguments.callee来消除函数执行与函数名的紧耦合;
- 函数内部this对象,指向函数环境对象;
- 函数对象属性caller,指向调用当前函数的函数,不能为caller赋值
arguments.callee.caller
apply()和call()
能设置函数体内的this值;bind()
创建一个函数的实例,this会被绑定到传给它的参数上;
5.6 基本包装类型
- 每当读取一个基本类型的时候,后台就会创建一个对应的基本包装类型对象,这个对象只存在一瞬间,会被立即销毁;
- typeof 基本包装类型的值是 object;
- 使用转型函数和构造函数(new)typeof有区别
var num = "25"
var num1 = Number(num)
console.log(typeof num1) // number
var num2 = new Number(num)
console.log(typeof num2) // object
var obj= new Object('str')
console.log(obj instanceof Object) // true
console.log(obj instanceof String) // true
5.6.1 Boolean
var obj = new Boolean(false)
var result = obj && (true)
console.log(result) // true
5.6.2 Number
var num = 10.005
console.log(num.toFixed(2)) // 10.01 自动舍入
5.6.3 String;
- 数组、字符串都有
concat()/slice()
方法; - 字符串不可变性;
- 字符串模式匹配;
5.7 单体内置对象
Global和Math
5.8 valueof()和toString()
- 数组调用
valueOf()
,结果还是数组; - Date调用
valueOf()
,结果是日期的毫秒; - RexExp调用
valueOf()
,返回正则表达式本身; - 基本包装类型Boolean的实例重写
valueOf()
,返回基本类型false或true; - 基本包装类型Number的
valueOf()
返回数值; - 数组调用
toString()
:返回逗号拼接每个值的字符串形式(最终结果是一个字符串);
数组调用toLocaleString()
: 对数组每一项调用这个方法; - RegExp的实例调用
toString() / toLocaleString()
返回正则表达式的字面量; - 函数的
toString() / toLocaleString()
返回函数代码; - 基本包装类型Boolean的
toString()
,返回字符串’false’ 或 ‘true’; - 基本包装类型Number的
toString()
,返回数值几进制的字符串形式;
5.9 判断类型终极方法Object.prototype.toString()
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('seymoe') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'// 对于内置对象 or 构造函数
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(Math) // '[object Math]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new WeakSet()) // '[object WeakSet]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Object.prototype.toString.call(new WeakMap()) // '[object WeakMap]'