js在视频和菜鸟入坑之后,进入了一个卡顿期,边学ES6边看红宝书《Javascript高级程序设计》【我吐槽一下,这书明明得入坑ES6一段时间后看,才是进步最快的哇?好哇!还是太菜,今年重来,我马上能行!】
21年年末绝对发现一本JS入坑一段时间就可以看的书籍,我太太太感谢阮一峰老师了!!!
这书绝对大赞一波,我真真正正见识到了this,闭包,原型链,对象,AJAX,单线程,事件处理等等!!!
这绝对是走向JS高深之路的必读书籍啊,太推了呀,相见恨晚!一定得多读几遍,呜呜呜
文章标题
0序: 练习代码
1. 数组.html
```html
<!DOCTYPE html>
2、 console对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="aaa">
<ul>
<li>dejad</li>
<li></li>
<li></li>
</ul>
</div>
<script>
console.log(
'%cThis text is styled!',
'color: red; background: yellow; font-size: 24px;'
)
console.info('你好');
console.warn('警告⚠');
console.error('错了,个');
// ['log', 'info', 'warn', 'error'].forEach(function(method) {
// console[method] = console[method].bind(
// console,
// new Date().toISOString()
// );
// });
// console.log("出错了!");
console.error('Error: %s (%i)',
'Server is not responding', 500)
// Error: Server is not responding (500)
console.warn('Warning! Too few nodes (%d)', document.childNodes.length)
// Warning! Too few nodes (1)
var languages = [{
name: "JavaScript",
fileExtension: ".js"
}, {
name: "TypeScript",
fileExtension: ".ts"
}, {
name: "CoffeeScript",
fileExtension: ".coffee"
}];
console.table(languages);
console.dir({
f1: 'foo',
f2: 'bar'
})
// console.dir(obj, {
// colors: true
// })
console.dirxml(document.body)
console.log(document.body);
//<!--assert-->
console.assert(false, '判断条件不成立');
// 相当于
try {
if (!false) {
throw new Error('判断条件不成立');
}
} catch (e) {
console.error(e);
}
</script>
</body>
</html>
0-3 Object对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// Object对象的方法
Object.print = function(o) {
console.log(o);
}
// Object 的实例方法
Object.prototype.print = function() {
console.log(this);
}
var obj = new Object();
obj.print()
</script>
</body>
</html>
0-4 arr数组.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var list = [1, 2, 3, 4];
var item;
while (item = list.shift()) {
console.log(item);
}
list // []
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2, 1, 2) // ["e", "f"]
console.log(a); // ["a", "b", "c", "d", 1, 2]
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(-4, 2) // ["c", "d"]
console.log(a);
var out = [];
[1, 2, 3].forEach(function(elem) {
this.push(elem * elem);
}, out);
console.log(out);
// filter()方法用于过滤数组成员,满足条件的成员组成一个新数组
var b = [1, 2, 3, 4, 5].filter(function(elem) {
return (elem > 3);
})
console.log(b);
// 返回数组arr里面所有布尔值为true的成员
var arr = [0, 1, 'a', false];
var temarr = arr.filter(Boolean);
console.log(temarr, arr);
// filter方法可以接受三个参数 : elem,index和arr
var c = [1, 2, 3, 4, 5].filter(function(elem, index, arr) {
return index % 2 === 0;
})
console.log(c);
// filter() 方法可以接受第二个参数, 用来绑定函数内部的this变量
var obj = {
MAX: 3
};
var myFilter = function(item) {
if (item > this.MAX) return true;
};
var arr = [2, 8, 3, 4, 1, 3, 2, 9];
console.log(arr.filter(myFilter, obj));
</script>
</body>
</html>
0-5 string.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 生成随机字符的例子
function random_str(length) {
var ALPHABET = 'ABCDEFGHIGKLMNOPQRSTUVWXYZ';
ALPHABET += 'abcdefghijklmnopqrstuvwxyz';
ALPHABET += '0123456789-_';
var str = '';
for (var i = 0; i < length; ++i) {
var rand = Math.floor(Math.random() * ALPHABET.length);
str += ALPHABET.slice(rand, rand + 1);
}
return str;
}
console.log(random_str(6));
var a = 'The quick for jumped over the lazy dog.';
var pattern = /quick|brown|lazy/ig;
var d = a.replace(pattern, function replacer(pattern) {
return pattern.toUpperCase();
})
console.log(d);
</script>
</body>
</html>
0-6 this指向.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var obj = {
foo: function() {
console.log(this);
}
};
console.log(obj.foo()); // obj
console.log(obj.foo);
</script>
</body>
</html>
一、 入门篇
1-1导论+js简介
1-1-1 简介
- 轻量级脚本,嵌入式语言,
- 嵌入JS的宿主环境有浏览器,服务器环境,Node项目
- 语法角度:
- JavaScript 语言是一种“对象模型”语言
- JavaScript 并不是纯粹的“面向对象语言”,还支持其他编程范式(比如函数式编程)
- JavaScript 的核心语法部分相当精简,只包括两个部分:基本的语法构造(比如操作符、控制结构、语句)和标准库(就是一系列具有各种功能的对象比如
Array
、Date
、Math
等)。除此之外,各种宿主环境提供额外的 API(即只能在该环境使用的接口),以便 JavaScript 调用。以浏览器为例,它提供的额外 API 可以分成三大类。- 浏览器控制类:操作浏览器
- DOM 类:操作网页的各种元素
- Web 类:实现互联网的各种功能
1-1-2 历史
- 1995年,网景(Netscape)开发JS【Ns与Sun公司】联合发布: 对外宣布JS是JAva的补充,,属于轻量级的Java,专门用于操作网页
- 1996年,Navigator2.0
- 1996,微软模仿JS开发Jscript;Ns讲JS提交给ECMA
(European Computer Manufacturers Association)
- 1997年,ECMA发布262号标准文件的第一版,规定了浏览器脚本语言的标准
二、数据类型
1-1 数据类型
1-1- 1 数据类型
-
六种数据类型:
- number
- string
- boolean
- undefined
- null
- object
1-1-2 确定值是什么类型(3)
-
typeof
typeof window // "object" typeof {} // "object" typeof [] // "object" typeof null // "object"
-
instanceof
var a = [] a instanceof Array; // true
-
Object.prototype.toString
1-1-3 数据类型详解
1-1-3-1 null,undefined和布尔值
null
是一个表示“空”的对象,转为数值时为0
;undefined
是一个表示"此处无定义"的原始值,转为数值时为NaN
。
Number(undefined) // NaN
5 + undefined // NaN
-
undefined的典型场景
// 变量声明了,但没有赋值 var i; i // undefined // 调用函数时,应该提供的参数没有提供,该参数等于 undefined function f(x) { return x; } f() // undefined // 对象没有赋值的属性 var o = new Object(); o.p // undefined // 函数没有返回值时,默认返回 undefined function f() {} f() // undefined
-
转换规则是除了下面六个值被转为
false
,其他值都视为true
。undefined
null
false
0
NaN
""
或''
(空字符串)
if ([]) { console.log('true'); } // true if ({}) { console.log('true'); } // true
1-1-3-2 数值
-
JS底层根本没有整数
1 === 1.0 // true
-
精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-253到253,都可以精确表示。
-
- 如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回
Infinity
。
Math.pow(2, 1024) // Infinity
- 如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),那么就会发生为“负向溢出”,即 JavaScript 无法表示这么小的数,这时会直接返回0。
Math.pow(2, -1075) // 0
- 如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回
-
JavaScript 提供
Number
对象的MAX_VALUE
和MIN_VALUE
属性,返回可以表示的具体的最大值和最小值。Number.MAX_VALUE // 1.7976931348623157e+308 Number.MIN_VALUE // 5e-324
-
数值的进制:
- Oo前缀: 八进制
- Ox:十六进制
- Ob: 二进制
-
JS特殊值:NaN,Infinity
typeOf undefined = NaN typeof NaN = 'number' NaN === NaN // false
1-1-3-3 与数值相关的全局方法
-
parseInt(): 字符串转化为整数, 结果只有NaN / 整数
parseInt('123') // 123
-
如果
parseInt
的参数不是字符串,则会先转为字符串再转换。parseInt(1.23) // 1 // 等同于 parseInt('1.23') // 1
-
可以解析------> 十进制,不认识科学计数法的数字
-
可以两个参数:::
参数2: 指定进制
-
-
parseFloat(): 将一个字符串转为浮点数。
-
isNaN():
-
isFinite(): 某个值是否为正常的数值
1-1-3-4 字符串
- 字符串分成多行,须在尾部使用反斜杠
var longString = 'Long \
long \
long \
string';
longString
// "Long long long string"
-
反斜杠还有三种特殊用法:
-
三个八进制数(000-377),代表一个字符
-
\x
后面紧跟两个十六进制数(00
到FF
),代表一个字符。 -
\u
后面紧跟四个十六进制数(0000
到FFFF
),代表一个字符。'\251' // "©" '\xA9' // "©" '\u00A9' // "©" '\172' === 'z' // true '\x7A' === 'z' // true '\u007A' === 'z' // true
-
-
无法改变字符串中的单个字符
1-1-3-5 对象
-
键名都是字符(数字会被自动转化为字符串)
-
每个“键名”又称为“属性”
-
表达式还是语句:
-
这种差异在
eval
语句(作用是对字符串求值)中反映得最明显。eval('{foo: 123}') // 123 eval('({foo: 123})') // {foo: 123}
-
-
属性的操作:
-
读取属性使用点运算符,方括号运算符
-
var obj = { p: 'Hello World' }; obj.p // "Hello World" obj['p'] // "Hello World"
-
数字键名不能使用点运算符,只能使用方括号运算符
-
-
-
属性的查看:
-
使用Object.keys
-
var obj = { key1: 1, key2: 2 }; Object.keys(obj); // ['key1', 'key2']
-
-
属性是否存在:
- in运算符: 无法识别哪些属性是继承的
- toString()
- 使用对象的
hasOwnProperty
方法判断一下,是否是对象自身的属性
var obj = {}; if ('toString' in obj){ log(obj.hasOwnProperty('toString')) // false }
- in运算符: 无法识别哪些属性是继承的
-
属性的遍历: for…in…循环
var obj = {a:1, b:2, c:3}; for(var i in obj){ log('键名', i); log('键值',obj[i]); }
var obj = {}; for(var i in obj){ if(obj.hasOwnProperty(key)){ log(key); } }
-
with语句: 操作同一个对象的多个属性时【不要用,我看了个寂寞,去了】
- with区块内部有变量的赋值操作,必须是当前对象已经存在的属性
- 否则会创造一个当前作用域的全局变量
var obj = { p1: 1, p2: 2, } with(obj){ p1 = 4; p2 = 5; }
console.log(document.links[0].href); console.log(document.links[0].title); console.log(document.links[0].style); // 例二 with(document.links[0]){ console.log(href); console.log(href) console.log(href) }
-
建议使用临时变量替代with
with(obj1.obj2.obj3) { console.log(p1 + p2); } // 可以写成 var temp = obj1.obj2.obj3; console.log(temp.p1 + temp.p2);
1-2 函数
1-2-1 概述
1-2-1-1 函数的声明(3)
-
function函数:
function print(s) { console.log(s); }
-
函数表达式:
var print = function(s) { log(s); }
- 将一个匿名函数赋值给变量
- 该匿名函数又称函数表达式
var f = function f() {};
-
function构造函数(不用)
-
递归计算斐波那契数列
function fib(num) { if(num === 0) return 0; if(num === 1) return 1; return fib(num - 2) = fib(num - 1); } fib(6)
1-2-1-2 函数的属性和方法
-
toString() : 函数的
toString()
方法返回一个字符串,内容是函数的源码。- 注释内容也可以返回
-
对于那些原生的函数,
toString()
方法返回function (){[native code]}
。Math.sqrt.toString() // "function sqrt() { [native code] }"
-
<script> var multiline = function(fn) { console.log(fn); var arr = fn.toString().split('\n'); console.log(arr); console.log(arr.slice(1, arr.length - 1).join('\n')); }; function f() { WaveShaperNodedf fsf } multiline(f); </script>
ƒ f() { WaveShaperNodedf fsf } 25.集合实践.html:26 (4) ["function f() {", " WaveShaperNodedf", " fsf", " }"] 25.集合实践.html:27 WaveShaperNodedf fsf
1-2-1-3 函数本身的作用域
-
函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关
- 总之,函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。
var a = 1; var x = function () { console.log(a); }; function f() { var a = 2; x(); } f() // 1
var x = function () { console.log(a); }; function y(f) { var a = 2; f(); } y(x) // ReferenceError: a is not defined
-
1-2-1-3 arguments对象
-
arguments可以在函数体内部读取所有参数
-
arguments对象可以在运行时修改
- 严格模式下不会影响到实际的函数参数
var f = function(a, b) { arguments[0] = 3; arguments[1] = 2; return a + b; } f(1, 1) // 5
-
通过
arguments
对象的length
属性,可以判断函数调用时到底带几个参数。function f() { return arguments.length; } f(1, 2, 3) // 3 f(1) // 1 f() // 0
-
arguments是一个对象,不是数组
-
转化为 一个数组
var args = Array.prototype.slice.call(arguments); // 或者 var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); }
-
1-2-1-4 闭包
JS 语言的一个特色 + 难点
- 全局作用域+ 函数作用域
- 函数内部读取全局变量
- 函数外部无法读取函数内部声明的变量
- 链式作用域结构(chain scope):
- 子对象会一级一级向上寻找父对象的变量
- 父对象的所有变量,对子对象都是可见的,反之不成立
- 闭包的用处:
- 可以读取外层函数内部的变量
- 让这些变量始终保持的在内存中
1-3 数组
1-3-1 数组的简介
-
数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2…)。
-
var arr = ['a', 'b', 'c']; Object.keys(arr) // ["0", "1", "2"]
-
JavaScript 使用一个32位整数,保存数组的元素个数。这意味着,数组成员最多只有 4294967295 个(232 - 1)个
-
in运算符
var arr = [ 'a', 'b', 'c' ]; 2 in arr // true '2' in arr // true 4 in arr // false
上面代码表明,数组存在键名为
2
的键。由于键名都是字符串,所以数值2
会自动转成字符串。
1-3-2 数组的遍历
-
数组的forEach方法,也可以用来遍历数组,详见《标准库》的 Array 对象一章。 var colors = ['red', 'green', 'blue']; colors.forEach(function (color) { console.log(color); }); // red // green // blue
-
var a = [,,,]; a.forEach(function(x,i){ log(i+'.'+x); })
-
数组的
slice
方法可以将“类似数组的对象”变成真正的数组。var arr = Array.prototype.slice.call(arrayLike);
三、 运算符
3-1 算术比较符
3-1-1
- 除了加法运算符之外的都不会发生重载。所有运算子一律转为数值,在进行相应的数学运算
- 1-‘2’ //-1
- 1*‘2’ //2
- 1 / ‘2’ //0.5
3-1-2 对象的相加
-
运算子是对象,必须先转成原始类型的值
var obj = {p:1}; obj + 2 // "[object Object]2"
-
转为原始类型的值【对象得到toString方法默认返回
[object Object]
】var obj = {p:1}; obj.valueOf().toString() // "[object O]"
-
自己定义valueof或者toString方法
var obj = { valueof: function(){ return 1; } }; obj + 2; // 3
-
运算符是一个Date对象的实例,优先执行
toString()
var obj = new Date(); obj.valueOf = function () { return 1 }; obj.toString = function () { return 'hello' }; obj + 2 //'hello2'
-
3-1-3 余数运算符
运算结果的正负号由第一个运算子的正负号决定
3-2 布尔运算符
3-2-1 !和&&和||
-
以下六个值取反之后值为true
- undefined
- null
- false
- 0
- NaN
- 空字符串 (’ ')
-
&& 运算符:
- 如果第一个运算符是true,则返回第二个运算子的值
- 第一个运算符是false,直接返回第一个运算符的值
-
使用“短路”取代if结构
i && dosomething();
-
运算符用于为变量设置默认值
saveText(this.text || '')
四、 语法专题
4-1 数据类型的转换
4-1-1
- JS是一种动态类型的语言
- 强制转换类型
- Number();
- String()
- Boolean()
4-1-2 Number()
-
Number('abc123') // NaN Number(undefined) // NaN Number(null) // 0
-
Number({ valueOf: function () { return 2; }, toString:function () { return 3; } })
-
String
方法背后的转换规则,与Number
方法基本相同,只是互换了valueOf
方法和toString
方法的执行顺序。-
先调用对象自身的
toString
方法。如果返回原始类型的值,则对该值使用String
函数,不再进行以下步骤。 -
如果
toString
方法返回的是对象,再调用原对象的valueOf
方法。如果valueOf
方法返回原始类型的值,则对该值使用String
函数,不再进行以下步骤。 -
如果
valueOf
方法返回的是对象,就报错。
-
4-1-3 Boolean()
- 以下五个值转换为false
- undefined
- null
- 0
- NaN
- ‘’
4-2 错误处理机制
4-2-1
-
JS原生提供了Error构造函数,所有抛出的错误都是这个构造函数的实例
var err = new Error('出错了') err.message; // '出错了'
- 调用Error()构造函数,生成实例对象err
- 抛出Error实例对象之后,整个程序中断在发生错误的地方
-
对Error实例还提供了namehestack属性
- name
- message
- stack:错误的堆栈
-
if(error.name){ log(error.name + ':' + error.message); } function throwit() { throw new Error(''); } function catchit() { try { throwit(); } catch(e) { log(e.stack); // print stack trace } }
4-2-2 原生错误类型
- Error 实例对象是最一般的错误类型
- 在其基础上,定义了其他六种错误对象
- 存在Error的6个派生对象
4-2-2-1 SyntaxError对象
-
syntaxerror对象是解析代码时发生语法错误
var 1a; // Uncaught SyntaxError: Invalid or unexpected token // 缺少括号 log 'log') //Uncaught SynataxError: Unexpected string
4-2-2-2 ReferenceError对象
-
// 使用一个不存在的变量 unknownVariable // Uncaught ReferenceError: unknownVariable is not defined
-
另一种触发场景是,将一个值分配给无法分配的对象,比如对函数的运行结果赋值。
// 等号左侧不是变量 console.log() = 1 // Uncaught ReferenceError: Invalid left-hand side in assignment
4-2-2-3 RangeError对象
RangeError
对象是一个值超出有效范围时发生的错误。主要有几种情况,一是数组长度为负数,二是Number
对象的方法参数超出范围,以及函数堆栈超过最大值。
// 数组长度不得为负数
new Array(-1)
// Uncaught RangeError: Invalid array length
4-2–2-4 TypeError对象
-
TypeError
对象是变量或参数不是预期类型时发生的错误。比如,对字符串、布尔值、数值等原始类型的值使用new
命令,就会抛出这种错误,因为new
命令的参数应该是一个构造函数。 -
调用对象不存在的方法,也会抛出
TypeError
错误,new 123 // Uncaught TypeError: 123 is not a constructor var obj = {}; obj.unknownMethod() // Uncaught TypeError: obj.unknownMethod is not a function
4-2-2-5 URIError对象
URIError
对象是 URI 相关函数的参数不正确时抛出的错误
4-2-3 自定义错误
-
function UserError(message) { this.message = message || '默认信息'; this.name = 'UserError'; } UserError.prototype = new Error("这是自定义的错误!"); UserError.prototype.constructor = UserError;
4-2-4 throw语句
-
throw语句的作用是手动终端程序执行,抛出一个错误
var x= -1; if (x <= 0){ throw new Error('x必须是正数') } // Uncaught Error: x 必须为正数
-
throw也可以抛出自定义错误
function UserError(message) { this.message = message || '默认信息'; this.name = 'UserError'; } throw new UserError('出错了!'); // Uncaught UserError {message: "出错了!", name: "UserError"}
- throw抛出的是一个UserError实例
-
4-2-5 try…catch结构
-
try { throw new Error('出错了!'); } catch(e) { log(e.name + ':' + e.message); log(e.stack); }
- 错误被catch代码块捕获课
- catch接收的参数是try代码块抛出的值
4-2-6 总结
-
充分反映
try...catch..finally
三者的执行顺序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); // 不会运行 } var result = f(); // 0 // 1 // 3 result // false
4-3 编程风格
编写代码的样式规则
编译器的规范叫做“语法规则”,编译器忽略的部分就叫做“编程风格”
-
圆括号
- 一种表示函数的调用
- 表示表达式的组合
-
函数调用和定义时
- 函数名和左括号之间没有空格
-
其他情况下,前面位置的语法元素与左括号之间,都有一个空格
foo(bar) return (a+b); if (a === 0) {...} function foo(b) {...} function (x) {...}
-
分号
-
do…while循环要有分号
do { a--; } while(a > 0); // 分号不能省略
-
函数表达式仍然要使用分号
var f = function f() { };
-
-
ASI:
Automatic Semicolon Insertion
,分号的自动添加 -
==(相等运算符会自动转换变量类型),只使用严格相等运算符
-
建议自增(
++
)和自减(--
)运算符尽量使用+=
和-=
代替。 -
switch…case建议携程对象结构
function doAction(action) { switch (action) { case 'hack': return 'hack'; case 'slash': return 'slash'; case 'run': return 'run'; default: throw new Error('Invalid action.'); } }
function doActive(action) { var actions = { 'hack' : function () { return 'hack'; }, 'slash' : function () { return 'slash'; }, 'run': function (){ return 'run'; } }; if(typeof actions[action] !== 'function') { throw new Error('Invalid action.'); } return actions[action](); }
4-4 cosole对象与控制台
4-4-1 console对象以及静态方法
-
- performance: 查看网页的性能情况,比如CPU和内存消耗
-
console.log用于在控制台输出信息
-
支持以下占位符,不同数据必须使用对应的占位符
-
-
%s : 字符串
-
%d: 整数
-
%i : 整数
-
%f: 浮点数
-
%o : 对象的链接
-
%c : CSS格式字符串
console.log( '%cThis text is styled!', 'color: red; background: yellow; font-size: 24px;' )
-
-
-
参数是一个对象,console.log会显示对象的值
console.log({foo: 'bar'}) // Object {foo: "bar"} console.log(Date) // function Date() { [native code] }
4-4-2 console.info ; console.debug;error;warn;
-
info会在输出信息前面,加上一个蓝色图标(貌似没有)
-
debug : 会在控制台输出调试信息
- 只有在打开显示级别在
verbose
的情况下,才会显示
- 只有在打开显示级别在
-
warn 方法和 error方法 在控制台输出信息
-
error
console.error('Error: %s (%i)', 'Server is not responding', 500) // Error: Server is not responding (500) console.warn('Warning! Too few nodes (%d)', document.childNodes.length) // Warning! Too few nodes (1)
-
-
log方法写入标准输出(stdout),warn和error方法写入标准错误(stderr)
-
console对象的所有方法,都可以被覆盖
['log', 'info', 'warn', 'error'].forEach(function(method) { console[method] = console[method].bind( console, new Date().toISOString() ); }) log("出错了!"); //
4-4-3 console.table()
-
console.table 方法可以将其转为表格显示
var languages = [ { name: 'JavaScript', fileExtension: '.js' }, { name: 'TypeScript', fileExtension: '.ts' }, ]; table(languages);
4-4-4 console.count()
-
count 方法用于计数,输出它被调用次数
function aa() { console.count(); return 'hi'; }
-
count 可以接收一个字符串作为参数
function greet(user) { console.count(user); return "hi " + user; } greet('bob') // bob: 1 greet('alice') // alice: 1 greet('bob') // bob: 2
4-4-5 console.dir() 和 dirxml()
-
dir方法用来对一个对象进行检查(inspect),并以易于阅读和打印的格式
console.log({f1: 'foo', f2: 'bar'}) // Object {f1: 'foo', f2: 'bar'} dir({f1: 'foo', f2: 'bar'}) // Object // f1: "foo" // f2: "bar" // __proto__: Object
-
console.dirxml() == console.log():
-
主要用于以目录树的形式,显示DOM结点
console.dirxml(document.body)
-
4-4-6 console.assert()
-
接受两个参数,第一个参数是表达式,第二个参数是字符串。只有当第一个参数为
false
,才会提示有错误,在控制台输出第二个参数,否则不会有任何结果。console.dirxml([1, 2, 3]) // 等同于 console.dir([1, 2, 3])
-
节点数>50,才会提示错误
console.assert(list.childNodes.length < 500, '节点个数大于等于500')
五、标准库
5-1 Object 对象
5-1-1
- JS原生提供Object对象
- javascript的所有其他对象都继承自Object对象,那些对象都是Object的实例
- Object 对象的原生方法分为:
Object 本身的方法
和Object的实例方法
5-1-1-1 Object对象本身的方法
-
所谓本身的方法 : 定义在Object 对象的方法
Object.print = function (o) { console.log(o) };
5-1-1-2 Object的实例方法
-
Object 的实例方法: 定义在Object 原型对象
Object.prototype
上的方法,可以被Object实例直接使用Object.prototype.print = function () { console.log(this); }; var obj = new Object(); obj.print() // Object
5-1-1-3 Object()
- 写一个判断变量是否为对象的函数
function isObject(value){
return value === Object(value);
}
isObject([]) // true
isObject(true) // false
5-1-1-4 Object构造方法
-
var obj = {} ==== var obj = new Object()
5-1-1-5 Object.keys(),Object.getOwnPropertyNames()
都是遍历对象的属性
-
Object.keys()
-
参数是对象,结果是数组
-
该数组的成员都是该对象自身的所有属性名
var obj = { p1: 123, p2: 456 }; Object.keys(obj) // ["p1", "p2"] Object.getOwnPropertyNames(obj) // ["p1", "p2"]
-
-
Object.getOwnPropertyNames
方法 也是接受一个对象作为参数,返回一个数组,包含该对象自身的所有属性名 -
由于JavaScript没有提供计算对象属性个数的方法
var obj = { p1: 123, p2: 456 } Object.keys(obj).length // 2 Object.getOwnPropertyNames(obj).length // 2
5-1-2 Object的实例对象
Object
实例对象的方法,主要有以下六个。Object.prototype.valueOf()
:返回当前对象对应的值。Object.prototype.toString()
:返回当前对象对应的字符串形式。Object.prototype.toLocaleString()
:返回当前对象对应的本地字符串形式。Object.prototype.hasOwnProperty()
:判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。Object.prototype.isPrototypeOf()
:判断当前对象是否为另一个对象的原型。Object.prototype.propertyIsEnumerable()
:判断某个属性是否可枚举。
5-2 Array对象
5-2-1 构造函数
- Array是javascript的原生对象,同时也是一个构造函数,用它生成新的数组
5-2-1-1 Array.isArray()
-
Array.isArray方法返回一个布尔值,表示参数是否为数组,可以弥补typeof运算符的不足
var arr = [1, 2, 3]; typeof arr // "object" Array.isArray(arr) // true
5-2-1-2 实例方法
-
valueof方法返回数组本身
var arr = [1, 2, 3]; arr.valueOf() // [1, 2, 3]
-
toString()返回数组的字符串形式
var arr = [1, 2, 3]; arr.toString() // "1,2,3" var arr = [1, 2, 3, [4, 5, 6]]; arr.toString() // "1,2,3,4,5,6"
-
push(): 末尾添加元素,并返回添加新元素后的数组长度
-
pop() : 删除数组最后一个元素
- 对空数组使用pop方法,不会报错,而会返回undefined
-
shift() : 删除数组的第一个元素
var a = ['a', 'b', 'c']; a.shift() // 'a' a // ['b', 'c']
-
unshift() : 第一个位置添加元素,返回添加新元素后的数组长度
var a = ['a', 'b', 'c']; a.unshift('x','d'); // 4 a // ['x', 'd','a', 'b', 'c']
-
join() : 以指定参数作为分割符,将所有数组成员连接为一个字符串返回
- 不提供参数,默认用逗号分隔
var a = [1, 2, 3, 4]; a.join(' ') // '1 2 3 4' a.join(' | ') // "1 | 2 | 3 | 4" a.join() // "1,2,3,4" [undefined, null].join('#') // '#' ['a',,'b'].join('-') // 'a--b'
-
数组成员是undefined或null或空位时,会被转为空字符串
-
通过call方法,可以用于字符串或类似数组的对象
Array.prototype.join.call('hello','-') // "h-e-l-l-o" var obj = {0: 'a', 1: 'b', length: 2}; Array.prototype.join.call(obj, '-') // 'a-b'
-
concat() : 多个数组的合并
-
数组成员包括对象,concat方法返回当前数组的一个浅拷贝
-
浅拷贝,指的是新数组拷贝的是对象的引用
var obj = { a: 1 }; var oldArray = [obj]; var newArray = oldArray.concat(); obj.a = 2; newArray[0].a // 2
-
-
reverse() :
var obj = { a: 1 }; var oldArray = [obj]; var newArray = oldArray.concat(); obj.a = 2; newArray[0].a // 2
-
slice() :提取目标数组的一部分,并返回
var a = ['a', 'b', 'c']; a.slice(0) // ["a", "b", "c"] a.slice(1) // ["b", "c"] a.slice(1, 2) // ["b"] a.slice(2, 6) // ["c"] a.slice() // ["a", "b", "c"]
-
重要应用: 是将类似数组的对象转为真正的数组
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 }) // ['a', 'b'] Array.prototype.slice.call(document.querySelectorAll("div")); Array.prototype.slice.call(arguments);
-
-
splice() : 删除原数组的一部分成员,删除的位置添加新的数组成员
- 返回原数组
arr.splice(start, count, addElement1, addElement2, ...);
-
删除成员,还插入了两个新成员。
var a = ['a', 'b', 'c', 'd', 'e', 'f']; a.splice(4, 2, 1, 2) // ["e", "f"] a // ["a", "b", "c", "d", 1, 2]
-
插入元素,splice可以将第二个参数设为0、
var a = [1, 1, 1]; a.splice(1, 0, 2) // [] a // [1, 2, 1, 1]
-
拆分数组: 只提供第一个参数
var a = [1, 2, 3, 4]; a.splice(2) // [3, 4] a // [1, 2]
-
sort() : 对数组进行排序,按照字典顺序排
- 数值会被先转为字符串,再按照字典顺序进行比较
['d', 'c', 'b', 'a'].sort() // ['a', 'b', 'c', 'd'] [4, 3, 2, 1].sort() // [1, 2, 3, 4] [11, 101].sort() // [101, 11] [10111, 1101, 111].sort() // [10111, 1101, 111]
-
sort按照字定义方式排序,可以传入一个函数作为参数
[10111, 1101, 111].sort(function (a, b) { return a - b; }) // [111, 1101, 10111]
[ { name: "张三", age: 30 }, { name: "李四", age: 24 }, { name: "王五", age: 28 } ].sort(function (o1, o2) { return o1.age - o2.age; }) // [ // { name: "李四", age: 24 }, // { name: "王五", age: 28 }, // { name: "张三", age: 30 } // ]
[1, 4, 2, 6, 0, 6, 2, 6].sort((a, b) => a - b)
-
map() : 将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回
var nums = [1,2,3]; nums.map(function (n) { return n + 1; }) // [2,3,4] nums;
-
forEach() :
- 遍历数组的目的是为了得到返回值,使用map()方法,只是为了在屏幕上输出内容使用forEach()方法
-
filter
// filter()方法用于过滤数组成员,满足条件的成员组成一个新数组 var b = [1, 2, 3, 4, 5].filter(function(elem) { return (elem > 3); }) console.log(b); // 返回数组arr里面所有布尔值为true的成员 var arr = [0, 1, 'a', false]; var temarr = arr.filter(Boolean); console.log(temarr, arr); // filter方法可以接受三个参数 : elem,index和arr var c = [1, 2, 3, 4, 5].filter(function(elem, index, arr) { return index % 2 === 0; }) console.log(c); // filter() 方法可以接受第二个参数, 用来绑定函数内部的this变量 var obj = { MAX: 3 }; var myFilter = function(item) { if (item > this.MAX) return true; }; var arr = [2, 8, 3, 4, 1, 3, 2, 9]; console.log(arr.filter(myFilter, obj));
-
some(),every()
var arr = [1, 2, 3, 4, 5]; arr.some(function (elem, index, arr) { return elem >= 3; }); // true var arr = [1, 2, 3, 4, 5]; arr.every(function (elem, index, arr) { return elem >= 3; }); // false
-
只要一个成员的返回值是true,则整个some返回值是true,否则返回false
-
every
方法是所有成员的返回值都是true
,整个every
方法才返回true
,否则返回false
。function isEven(x) { return x % 2 === 0 } [].some(isEven) // false [].every(isEven) // true
-
记得看最后一个例子
5-3 包装对象
-
Number,String,Boolean
var v1 = new Number(123); var v2 = new String('abc'); var v3 = new Boolean(true); typeof v1 // "object" typeof v2 // "object" typeof v3 // "object" v1 === 123 // false v2 === 'abc' // false v3 === true // false
- 如果不作为构造函数,而是作为普通函数,常常用于将任意类型的值转为数值、字符串和布尔值
-
Boolean对象
- !! 可以将任意值转为对应的布尔值
-
Number对象(实例)
-
number.prototype.toString( ) :
(10).toString(2) // "1010" (10).toString(8) // "12" (10).toString(16) // "a"
-
通过方括号运算符也可以调用toString
10['toString'](2) // "1010"
-
-
-
String对象
// 生成随机字符的例子 function random_str(length) { var ALPHABET = 'ABCDEFGHIGKLMNOPQRSTUVWXYZ'; ALPHABET += 'abcdefghijklmnopqrstuvwxyz'; ALPHABET += '0123456789-_'; var str = ''; for (var i = 0; i < length; ++i) { var rand = Math.floor(Math.random() * ALPHABET.length); str += ALPHABET.slice(rand, rand + 1); } return str; } console.log(random_str(6));
5-4 Date对象
以国际标准时间(UTC)1970年1月1日00:00:00作为时间的零点
5-5 正则(RegExp对象)
5-5-1
- 新建正则表达式:
- 字面量:
var regex = /xyz;
- 引擎编译代码时,新建正则表达式
- 效率高
- RegExp构造函数 :
var trgrx = new RegExp('xyz');
- 运行时新建
- 字面量:
5-5-2 字面量 字符和元字符
-
点字符(
.
) : 匹配除回车(\r
)、换行(\n
) 、行分隔符(\u2028
)和段分隔符(\u2029
)以外的所有字符。/c.t/
上面代码中,
c.t
匹配c
和t
之间包含任意一个字符的情况[^]
包含一切字符[\S\s]
指代一切字符。
-
位置字符:
- 表示提示字符所处的位置,主要有两个字符
^
: 字符开始位置$
: 表示字符串的结束位置
-
选择符(
|
):竖线符号(
|
)在正则表达式中表示“或关系”(OR),即cat|dog
表示匹配cat
或dog
。/11|22/.test('911') // true
-
预定义模式
预定义模式指的是某些常见模式的简写方式。
\d
匹配0-9之间的任一数字,相当于[0-9]
。\D
匹配所有0-9以外的字符,相当于[^0-9]
。\w
匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]
。\W
除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]
。\s
匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]
。\S
匹配非空格的字符,相当于[^ \t\r\n\v\f]
。\b
匹配词的边界。\B
匹配非词边界,即在词的内部。
-
量词符
量词符用来设定某个模式出现的次数。
?
问号表示某个模式出现0次或1次,等同于{0, 1}
。*
星号表示某个模式出现0次或多次,等同于{0,}
。+
加号表示某个模式出现1次或多次,等同于{1,}
。
5-6 jSON
- JSON(JavaScript Object Notion): 用于数据交换的文本格式
- 取代繁琐的XML格式
- 可以优解释引擎直接处理,不用另外添加解析代码
-
- 复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
- 原始类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和
null
(不能使用NaN
,Infinity
,-Infinity
和undefined
)。 - 字符串必须使用双引号表示,不能使用单引号。
- 对象的键名必须放在双引号里面。
- 数组或对象最后一个成员的后面,不能加逗号。
- JSON的两个静态方法:
- JSON.stringify()
- 将一个值转为JSON字符串
- JSON.parse()
- 使用这个还原
- JSON.stringify()
六、 面向对象编程(Object Oriented Progranmming,OOP)
6-1 实例对象与new命令
- JS不是基于类的,而是基于构造函数(constructor)和原型链(prototype)的
- 构造函数:
- 第一个字母通常要大写
- new: 执行构造函数,返回一个实例对象
- 使用
new
命令时,它后面的函数依次执行下面的步骤。- 创建一个空对象,作为将要返回的对象实例。
- 将这个空对象的原型,指向构造函数的
prototype
属性。 - 将这个空对象赋值给函数内部的
this
关键字。 - 开始执行构造函数内部的代码。
6-2 this关键字
6-2-1 含义
-
- this可以用在构造函数中,表示实例对象
- this都有一个共同点:返回一个对象
6-3 对象的继承
JS继承机制的设计思想就是
- 原型对象的所有属性和方法,都能被实例对象 共享
6-3-1 原型对象
-
函数默认拥有prototype属性。
-
prototype属性 : 指向一个对象
-
function f() {} typeof f.prototype // "object"
-
-
function Animal(name) { this.name = name; } Animal.prototype.color = 'white'; var cat1 = new Animal('大毛'); var cat2 = new Animal('二毛'); cat1.color // 'white' cat2.color // 'white'
上面代码中,构造函数
Animal
的prototype
属性,就是实例对象cat1
和cat2
的原型对象。原型对象上添加一个color
属性,结果,实例对象都共享了该属性。
6-3-2 原型链
-
“原型链”(prototype chain):对象到原型,再到原型的原型……
-
Object.prototype
对象有没有它的原型呢?回答是Object.prototype
的原型是null
。null
没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null
。Object.getPrototypeOf(Object.prototype) // null
-
如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)。
6-3-3 Object的原型对象的方法
-
有亿点点的头脑风暴
var F = function () { this.foo = 'bar'; }; var f = new F(); // 等同于 var f = Object.setPrototypeOf({}, F.prototype); F.call(f);
上面代码中,
new
命令新建实例对象,其实可以分成两步。第一步,将一个空对象的原型设为构造函数的prototype
属性(上例是F.prototype
);第二步,将构造函数内部的this
绑定这个空对象,然后执行构造函数,使得定义在this
上面的方法和属性(上例是this.foo
),都转移到这个空对象上。
八、 DOM
- 父结点(parentNode): 直接的上级节点
- 子结点(childNodes): 直接的下级节点
- 同级节点关系(sibling) : 拥有同一个父节点的节点
8-1 Node接口
所有DOM节点都继承了Node接口,拥有一些共同的属性和方法
-
- 文档节点(document):9,对应常量
Node.DOCUMENT_NODE
- 元素节点(element):1,对应常量
Node.ELEMENT_NODE
- 属性节点(attr):2,对应常量
Node.ATTRIBUTE_NODE
- 文本节点(text):3,对应常量
Node.TEXT_NODE
- 文档片断节点(DocumentFragment):11,对应常量
Node.DOCUMENT_FRAGMENT_NODE
- 文档类型节点(DocumentType):10,对应常量
Node.DOCUMENT_TYPE_NODE
- 注释节点(Comment):8,对应常量
Node.COMMENT_NODE
- 文档节点(document):9,对应常量
8-2 ParentNode 接口,ChildNode 接口
8-3 Document 节点
-
代码检查网页是否加载成功
// 基本检查 if (document.readyState === 'complete') { // ... } // 轮询检查 var interval = setInterval(function() { if (document.readyState === 'complete') { clearInterval(interval); // ... } }, 100);
-
下面一点点没看
8-4 Element 节点
-
Element.clientHeight,Element.clientWidth
document.documentElement
的clientHeight
属性,返回当前视口的高度(即浏览器窗口的高度),等同于window.innerHeight
属性减去水平滚动条的高度- 一般来说,
document.body.clientHeight
大于document.documentElement.clientHeight
。
-
Element.scrollHeight,Element.scrollWidth
-
Element.scrollHeight
属性返回一个整数值(小数会四舍五入),表示当前元素的总高度(单位像素),包括溢出容器、当前不可见的部分。它包括padding
,但是不包括border
、margin
以及水平滚动条的高度(如果有水平滚动条的话),还包括伪元素(::before
或::after
)的高度。 -
Element.scrollWidth
属性表示当前元素的总宽度(单位像素),其他地方都与scrollHeight
属性类似。这两个属性只读。整张网页的总高度可以从
document.documentElement
或document.body
上读取。// 返回网页的总高度 document.documentElement.scrollHeight document.body.scrollHeight
注意,如果元素节点的内容出现溢出,即使溢出的内容是隐藏的,
scrollHeight
属性仍然返回元素的总高度。// HTML 代码如下 // <div id="myDiv" style="height: 200px; overflow: hidden;">...<div> document.getElementById('myDiv').scrollHeight // 356
上面代码中,即使
myDiv
元素的 CSS 高度只有200像素,且溢出部分不可见,但是scrollHeight
仍然会返回该元素的原始高度。
-
-
-
Element.scrollLeft
属性表示当前元素的水平滚动条向右侧滚动的像素数量,Element.scrollTop
属性表示当前元素的垂直滚动条向下滚动的像素数量。对于那些没有滚动条的网页元素,这两个属性总是等于0。 -
如果要查看整张网页的水平的和垂直的滚动距离,要从
document.documentElement
元素上读取。
document.documentElement.scrollLeft document.documentElement.scrollTop
这两个属性都可读写,设置该属性的值,会导致浏览器将当前元素自动滚动到相应的位置。
-
-
Element.offsetLeft,Element.offsetTop
Element.offsetLeft
返回当前元素左上角相对于Element.offsetParent
节点的水平位移,Element.offsetTop
返回垂直位移,单位为像素。通常,这两个值是指相对于父节点的位移。下面的代码可以算出元素左上角相对于整张网页的坐标。
function getElementPosition(e) { var x = 0; var y = 0; while (e !== null) { x += e.offsetLeft; y += e.offsetTop; e = e.offsetParent; } return {x: x, y: y}; }
8-5 属性的操作
-
下面代码可以遍历一个元素节点的所有属性。 var para = document.getElementsByTagName('p')[0]; var result = document.getElementById('result'); if (para.hasAttributes()) { var attrs = para.attributes; var output = ''; for(var i = attrs.length - 1; i >= 0; i--) { output += attrs[i].name + '->' + attrs[i].value; } result.textContent = output; } else { result.textContent = 'No attributes to show'; }
8-6 CSS操作
下面一半和MUtation Observar API,我好桑心,仿佛没学过JS