javascript
ES5及以前
什么是javascript语言
-
轻量级脚本语言
不具备开发操作系统的能力,只用来编写控制其他大型应用程序(比如浏览器)的“脚本” -
嵌入式语言
只用来做数学和逻辑运算,调用宿主环境(浏览器和node)的底层API
标识符
- 第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)
- 后面字符加上Unicode 、$、_0-9
数据类型
数值、字符串、布尔值、undefined、null、对象(object、数组、函数)
确定类型方法
typeof(返回值是string)、instanceof、Object.prototype.toString
typeof Infinity// "number"
typeof '123' // "string"
typeof false // "boolean"
typeof undefined //"undefined"
// 检查未声明的变量,而不报错
typeof a //"undefined"
function f() {}
typeof f //"function"
typeof {} [] null //"object"
null和undefined
- null表示空的对象,转为数值为0,转为布尔为false
- undefined表示未定义的原始值,转为数值为NaN,转为布尔为false
布尔值:!、相等不等运算符、比较大小运算符会转为boolean
转为false:undefined、null、false、0、NaN、空字符串;其余值视为true
数值
所有数字以64位浮点数形式存储
1===1.0 // true
0.1 + 0.2 === 0.3 //false
数值精度
1位符号位(0,1) 第2到12位指数位 13到64位小数位
精确表示整数:指数在(0,2047)之间,算上1+52位有效位,因此精度为-2^53 到2 ^53,超出则会出现错误;最多表示( 2的-1075 ,2的1024] ‘0或者Infinity’
(-1)^符号位 * 1.xx...xx * 2^指数部分
xx为2位时
举例 1.11*2^2表示7
科学计数法 :e或者E
- 小数点前数字>21位或小数点后的0>5
进制表示
js内部会默认转为十进制
- 十进制:没有前导0的数值或0加8,9
- 八进制:0o或0O或(0加0-7的数字 es5严格模式、es6废弃)
- 十六进制:0x或0X的数值
- 二进制:0b或0B的数值
特殊数值
+0、-0 :区别作为分母
-0 === +0 // true
(1 / +0) === (1 / -0) // false +Infinity -Infinity
NaN:Not a Number,也是number类型
NaN不等于任何值包括自身
- 字符串解析为数字
- 数学函数运算结果
- 0/0
5 - 'x' // NaN
注:5 + 'x' // 5x 当作字符串连接
Infinity:表示无穷,+Infinity和-Infinity(表示正负无穷)
- Infinity与null计算时,null会转成0,等同于与0的计算
- Infinity与undefined计算,返回的都是NaN
Infinity > NaN // false
-Infinity < NaN // false
0 * Infinity // NaN
Infinity - Infinity // NaN
Infinity / Infinity // NaN
parseInt:将字符串转为整数(返回值是NaN或10进制数)
- 若不是字符串,转为字符串,去掉前缀空格
- 依次转换,遇到不能转换时,则返回转好的部分;若第一个字符不能转化为数字或不是数值或字符串,返回NaN
- 自动转为科学计算法的数字,会出现奇怪结果
- 字符串以0x或0X开头,按十六进制数解析,其余(0、0b、0O)一律按十进制
- 第二个参数(2,36)之间,表示被解析数的进制,超出则返回NaN,若参数是0、undefined、null、[]、{}直接忽略
parseInt('1546', 2) // 1 ,从最高位开始,只返回可以转换的数值
parseInt(0x11, 36) // 43
parseInt('') //NaN
// 等同于
parseInt('17', 36)
parseInt(011, 2) // NaN
// 等同于
parseInt(String(9), 2)
parseFloat:将一个字符串转为浮点数
与parseInt类似
isNaN:判断一个值位NaN
- 会先转为数值,使用Number()函数
//判断NaN
typeof value === 'number' && isNaN(value)
value !== value
isFinite :判断是否为正常的数值
- Infinity、NaN、undefined返回false,null返回true
- 会先转为数值,使用Number()函数
数据类型转换
强制转换
Number() :任意类型值转化为数值
- 比parseInt和parseFloat严格,只要一个字符不能转化为数值(2,8,16进制可以),则结果就为NaN
- 过滤前后缀空格
原始类型值
Number(324) // 324
Number('324') // 324
Number('324abc') // NaN
Number('') // 0
Number(true) // 1
Number(false) // 0
Number(undefined) // NaN
Number(null) // 0
对象
- 只有包含单个数值的数组,才返回对应值,否则返回NaN
Number({a: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([5]) // 5
Number([]) // 0
Number()求解流程
- 调用对象自身的valueOf方法,返回原始类型值,则直接Number求解,否则进入下一步
- 若valueOf方法返回的还是对象,则改为调用对象自身的toString方法,若tostring返回原始类型,则Number求解
- 若tostring返回时对象,则报错
注:默认下对象的valueOf方法返回本身,调用toString返回对象的类型字符串
可自定义对象的valueOf和toString的方法
let f=()=>{}
f.valueOf() //[Function: f] ()=>{}
f={}
f.toString() //"[object Object]"
f=[[1],2,3]
f.toString() //"1,2,3"
String()
- 数值:转为相应的字符串(还是会转成科学计数法)
- 字符串不变、布尔值转为‘true’,‘false’,undefined和null转为字符串形式
- 对象
String({a: 1}) // "[object Object]"
String([[1], 2, 3]) // "1,2,3"
String(()=>{}) //'()=>{}'
原理:先调用对象自身的toString,在调用源对象的valueOf,若最后返回对象则报错
Boolean
-Boolean(new Boolean(false)) // true
自动转换 (建议显式转换)
- 不同数据类型的数据互相运算
- 非布尔求布尔值(if,三元运算符)
- 非数值类型的值使用一元运算法
自动转换位字符串:+号一个元素是字符串
'5' + {} // "5[object Object]"
'5' + [] // "5"
'5' + function (){} // "5function (){}"
自动转换位数值:正负号,- * /,Math方法
字符串
- 单引号或双引号内部仍使用单双、或需要换行、转义则用反斜杠
- 视为字符串数组,若索引不是数字或超出,则返回undefined;但无法改变单个字符;length属性返回长度,也无法改变
- js引擎内部,所有字符用Unicode表示
Base64转码 :ASCLL0到31无法打印,以文本格式传递二进制格式
- 为了不出现特殊字符,简化程序处理;转成0-9,A-Z,a-z,+/64个字符
- btoa:转为base64编码
- atob:base64编码转为原始值
对象
键名:字符串和symbol(es6);符合标识名或数字,否则必须要加引号
{ console.log(123) } // 123 解释为代码块
({ console.log(123) }) // 报错
eval('{foo: 123}') // 123 对字符串求值
eval('({foo: 123})') // {foo: 123}
delete 删除返回false:属性不得删除
//读取
obj[123]
obj[foo] //foo为变量 obj.foo
//属性的查看
var obj = {
key1: 1,
key2: 2
};
Object.keys(obj);// ['key1', 'key2']
//属性的删除
delete obj.p//即使删除不存在的属性也返回true
in运算符:对象的属性(包含继承属性)是否存在
var obj = {a: 1, b: 2, c: 3};
'p' in obj // true
for (var i in obj) { // 遍历可遍历(enumerable);遍历自身和继承
console.log('键名:', i);
console.log('键值:', obj[i]);
}
with语句 :遍历操作同一个对象的多个属性
绑定当前作用域
var obj = {
p1: 1,
p2: 2,
};
with (obj) {
p1 = 4;
p2 = 5;
p3=6;//创建全局变量,且赋值失败
}
obj.p3 //undefined
p3 //6
with (obj) {
console.log(x); 无法知道是obj.x 还是全局变量x
}
函数
声明方式:function命令、函数表达式()、Function构造函数
- 重复声明 后面会覆盖前面
- 函数与其他数据类型地位平等,又称为第一等公民
- 函数提升:采用function命名,整个函数提升到代码头部,但函数表达式不会提升
- name属性返回函数名,但函数表达式匿名取变量名,具名取具名;获取参数函数名
- length属性返回 预期传入的参数个数(实现重载)
- toString()方法返回函数的源码包括换行符和注释,若是原生,则返回‘native code’
function print(s) {
console.log(s);
}
var print = function x(){
console.log(typeof x); //只在函数内部有用;方便除错工具显示函数名,不再显示匿名函数
};
var add = new Function(
'x',
'y',
'return x + y'
); //若只有一个参数,就是函数体
//name
var f3 = function myName() {};
f3.name // 'myName'
var myFunc = function () {};
function test(f) {
console.log(f.name);
}
test(myFunc) // myFunc
Math.sqrt.toString()
// "function sqrt() { [native code] }"
函数作用域
全局作用域:变量在整个程序一直存在,任何地方都可读取
函数作用域:
- 变量只在函数内部存在,函数内部定义的变量会覆盖同名全局变量
- 存在变量提升,提升到函数体的头部
- 绑定声明时所在的作用域
var a = 1;
var x = function () {
console.log(a);
};
function f() {
var a = 2;
x();
}
f() // 1
- 参数可省略,不可省略靠前参数
- 原始类型是传值传递(不会影响原参数),若是对象则是传址传递
- 同名参数,取最后出现的值
arguments对象:允许函数有不定数目的参数,函数内部获取所有参数
- 可在运行时修改(严格模式’use strict’修改后不影响到实际的函数参数)
- callee 属性返回原函数,严格模式禁用
Array.prototype.slice.call(arguments) //转为数组
闭包:能够读取函数内部变量的函数
- 读取外层函数内部的变量
- 变量记忆性,记住上一次调用的运算结果
function f1() {
var n = 999;
function f2() { //f2是闭包
console.log(n);
}
return f2;
}
var result = f1();
result(); // 999
function createIncrementor(start) {
return function () {
return start++;
};
}
var inc = createIncrementor(5);
inc() // 5
inc() // 6
inc() // 7
数组:特殊的对象
length属性:可读可写,置为0可清空数组,若大于当前元素个数,空位补充(undefined)
var a=[];
a[2]=1; // [,,1] 不需要连续
var arr = [ 'a', 'b', 'c' ];
arr.length = 0;
arr // []
//超出范围,键名自动转为字符串
var arr = [];
arr[-1] = 'a';
arr[Math.pow(2, 32)] = 'b';
arr.length // 0
arr[-1] // "a"
arr[4294967296] // "b"
in运算法:某个位置是空位,返回false
跳过空位遍历:forEach、for…in、Object.keys
空位不等同于undefined
var arr = [];
arr[100] = 'a';
100 in arr // true
1 in arr // false
//for...in 不仅遍历数字键,还遍历非数字键
var a = [1, 2, 3];
a.foo = true;
for (var key in a) {
console.log(key);
}
//delete 会形成空位,不影响length属性
delete a[1];
a[1] // undefined
a.length // 3
类数组对象
具有length属性,可转为数组(slice返回新数组)
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
Array.prototype.slice.call(arguments)
错误处理机制
Error构造函数,所有抛出的错误都是此对象的实例,并中断不再往下执行
var err = new Error('出错了');
err.message // "出错了"
原生错误类型
- SyntaxError 对象:语法解析错误
- ReferenceError 对象:不存在的变量或赋值给无法分配的对象
- RangeError 对象:超出有效范围。数组范围为负数,Number超出范围,函数堆栈溢出
- TypeError 对象:变量或参数不是预期类型时发生的错误
- URIError 对象:encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()
- EvalError:eval未被正确使用,被弃用
自定义错误
function UserError(message) {
this.message = message || '默认信息';
this.name = 'UserError';
}
UserError.prototype = new Error();
UserError.prototype.constructor = UserError;
throw:手动中断程序执行,抛出一个错误
throw new Error('x 必须为正数');
throw 42;
try…catch结构
- catch会捕获try的错误,会继续执行代码,也可继续抛错;若无catch,则中断程序执行
finally:不管是否抛错,都执行的代码
return和throw可触发转入finally
var count = 0;
function countUp() {
try {
return count;
} finally {
count++;
}
}
countUp()
// 0
count
// 1
function f() {
try {
console.log(0);
throw 'bug';
} catch(e) {
console.log(1);
return true; // 这句原本会延迟到 finally 代码块结束再执行
console.log(2); // 不会运行
} finally {
console.log(3);
return false; // 这句会覆盖掉前面那句 return
console.log(4); // 不会运行
}
console.log(5); // 不会运行
}
//0 1 3 false
编程风格
JavaScript自动添加句末的分号
不建议使用with;语句后分号不要省略;不建议使用switchcase,使用对象结构
console
console对象的浏览器实现(chorme),打开F12,console面板
- console方法都可自定义
- console.debug只有打开verbose,否则不会显示
- console.warn黄色标记 console.error红色标记
- console.table 数组和对象展示成表格
- console.count()该方法调用多少次
- console.dir(展示对象)和console.dirxml(dom节点以目录树展示,若不是dom则与dir一致)
- console.assert 不满足条件,则显示错误,不中断执行,第一个参数必须为false
- console.time(),console.timeEnd()算出程序的时间,setTimeout无效
console.log('a', 'b', 'c')// a b c
console.log(' %s + %s = %s', 1, 1, 2) //s d i f o c
['log', 'info', 'warn', 'error'].forEach(function(method) {
console[method] = console[method].bind(
console,
new Date().toISOString()
);
});
console.log("出错了!");
// 2014-05-18T09:00.000Z 出错了!
console.assert(false, '判断条件不成立')// Assertion failed: 判断条件不成立
运算法
算术运算符
3 + 4 + '5' // "75"
var obj = { p: 1 };
obj + 2 // "[object Object]2"
//运算结果的正负号由第一个运算子的正负号决定
-1 % 2 // -1
1 % -2 // 1
//数值运算法跟Number函数类似
+true // 1
-[] // 0
+{} // NaN
//指数 右结合
// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2
比较运算法
非相等运算法
- 字符串比较:按unicode码点按位比较
- 非字符串比较:原始类型,则转为数值再比较(出现NaN则false);对象先调用valueOf方法,如果返回的还是对象,再接着调用toString方法
let t=[300]>'4'; //false
let t=[300]>4; //true
== 和 ===
===:若不是同类型,则返回false,再比较(复合类型,比较是否指向同一地址)
==:会将它们转换成同一个类型,再用 ===比较
- 原始类型会转成数值再比较
- 对象类型(包括数组和函数)先调用valueOf(),再调用toString()
{} === {} // false
[] === [] // false
(function () {} === function () {}) // false
//null与undefined 与其他值都不相等
undefined == null // true
&&:如果第一个运算子的布尔值为true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值
||:如果第一个运算子的布尔值为true,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为false,则返回第二个运算子的值
void运算法:浏览器的书签工具,插入代码防止网页跳转
- 执行一个表达式,然后不返回任何值
<a href="http://example.com" onclick="f(); return false;">点击</a>
<a href="javascript: void(f())">文字</a>
逗号运算符 返回最后一个表达式的值
右结合:**,?,=
标准库
Obejct对象
value === Object(value) //判断是否为对象
var obj = new Object()//var obj = {} 等价
Object静态方法
- Object.keys:对象自身、可枚举的属性
- Object.getOwnPropertyNames:对象自身的所有属性
Object实例方法:定义再原型上的方法
- Object.prototype.valueOf():默认情况下与对象本身一样,除非修改valueof方法
- Object.prototype.toString():返回
- Object.prototype.toString.call(value):可判断类型
- Object.prototype.toLocaleString():与tostring类似,预留给地域翻译
- Object.prototype.hasOwnProperty():自身是否具有某属性(不算继承属性)
var obj = new Object();
obj.valueOf() === obj // true
var obj = new Object();
obj.valueOf = function () { //修改valueOf方法
return 2;
};
1 + obj // 3
var o1 = new Object();
o1.toString() // "[object Object]"
属性描述对象
{
value: 123, //属性值
writable: false, //属性值可写性
enumerable: true, //可枚举性 (遍历)
configurable: false, // 属性对象可写性,false时,value、writable、enumerable和configurable不能被修改
get: undefined,
set: undefined
}
- Object.getOwnPropertyDescriptor(obj,’p‘):获取自身属性的描述对象
var obj = { p: 'a' };
Object.getOwnPropertyDescriptor(obj, 'p')
// Object { value: "a",
// writable: true,
// enumerable: true,
// configurable: true
// }
- Object.defineProperty():定义或修改一个属性,返回修改后的对象
- Object.defineProperties():定义或修改多个属性,writable、configurable、enumerable默认值都为false
var obj = Object.defineProperty({}, 'p', {
value: 123,
writable: false,
enumerable: true,
configurable: false
});
obj.p // 123
obj.p = 246;
obj.p // 123
//修改多个属性
var obj = Object.defineProperties({}, {
p1: { value: 123, enumerable: true },
p2: { value: 'abc', enumerable: true },
p3: { get: function () { return this.p1 + this.p2 },
enumerable:true,
configurable:true
}
});
- Object.prototype.propertyIsEnumerable():某属性可枚举,若是继承返回false
get set
//configurable和enumerable都为true
var obj = {
get p() {
return 'getter';
},
set p(value) {
console.log('setter: ' + value);
}
};
控制对象状态
- Object.preventExtensions(obj):使得一个对象无法再添加新的属性
- Object.isExtensible():检查是否使用了Object.preventExtensions方法,检查是否可以为一个对象添加属性
- Object.seal(obj):对象既无法添加新属性,也无法删除旧属性
- Object.isSealed():是否使用了Object.seal
- Object.freeze():无法添加新属性、无法删除旧属性、也无法改变属性的值,使得这个对象实际上变成了常量
- Object.isFrozen():是否使用Object.freeze()
可以通过改变原型对象,来为对象增加属性;若属性值是对象,不能冻结对象本身的内容
Array
- Array.isArray(arr)