1、Node.js
Node.js 是服务器端运行的 JavaScript 的开源的,跨平台运行环境
Node.js原始作者 瑞安-达尔,使用了 V8 引擎,并采用事件驱动,非阻塞,异步IO 模型
2010年,npm软件包管理器诞生,通过他,可以方便的发布,分享Node.js的库和源代码
Node.js 4.0 引入了ES 6语言特性。
2、安装
阿里云镜像站:https://npm.taobao.org/mirrors/node
Linux:https://npm.taobao.org/mirrors/node/latest-v8.x/node-v8.11.4-linux-x64.tar.gz
windows:https://npm.taobao.org/mirrors/node/latest-v8.x/node-v8.0.0-x64.msi
mis安装不需要手动添加PATH 路径,自动回生成。
3、开发
文档:
搜索MDN,Mozilla Developer Network 提供非常完善的HTML,CSS,JS等技术资料。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
指南:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide
开发使用任何的文本编辑器都可以,使用微软的Visual Studio Code 开发
下载:https://code.visualstudio.com/Download
有代码自动完成功能,还可以安装Node exec插件,将写的js 跑在Node.js上
Node Exec 插件快键键:F8 运行 JS 脚本,F9 停止
前端开发中,JS 脚本一般来说是为了控制浏览器的网页的,这里使用了VS Code,只是为了调试方便
4、基础语法:
4.1、注释
和C 、Java 一样
// 单行注释
/* 注释 */ 多行注释,可以写在语句中。
1 str = 'hello' + /* this is a test deamo */'JS' 2 console.log(str)
4.2、常量和变量
标识符
标识符必须是字母,下划线,美元符号$ 和数字,不能以数字开头
标识符 区分大小写
声明
var 声明一个变量
let 声明 一个块作用域中的局部变量
const 声明一个常量
JS 中的变量声明和初始化 是可以分开的。
1 var a // 只是声明 一个变量 a ,console.log(a) a a为undefined 2 let b 3 console.log(a,b) 4 // undefined undefined 5 6 a = 1 7 b = 'a string' 8 console.log(a,b) 9 // 1 'a string' 10 11 // 常量 ,因为常量,所以声明的时候就需要赋值,负责报错 12 // 常量一旦声明后,就不能改变, 也不能重复 声明,虽然没有提示,但是打印会提示已经声明过了 13 const c = 100 14 15 console.log(x) 16 var y 17 // 规范的声明并初始化,声明全局或局部变量 18 // var 会把变量提升到当前全局或函数作用域,也就是说在此之前调用可以找到,但是是undefined 19 // 如 上面的console.log(x) 返回结果是undefined 20 var x = 4 21 22 // 不规范的额声明,不推荐,在严格模式下,会报错, 23 // 在赋值之前不能引用,因为它没有声明,一旦止痒赋值,就是全局作用域 24 z = 6 25 26 function hello() { 27 var q // q 是一个局部变量。作用域在函数中 28 q = 100 29 } 30 31 hello() 32 33 console.log(q) // 没有定义 q,所以报异常 34 35 w = 200 // 不能声明提升 36 let w = 200 // 不能声明提升 37 var w = 200 // 声明提升
变量和常量的选择:
如果明确知道一个标识符方以后不在修改,应该尽量声明成const 常量,减少被修改的风险,减少bug
4.3、数据类型
ES是动态语言,弱类型语言。
虽然先声明了变量,但是变量可以重新赋值任何类型
1 // 类型转换 2 // 弱类型 3 console.log('====== string ======') 4 console.log(a = 3 + 'jack', typeof(a)) // 只要有字符串,就先转换为字符串 5 console.log(a = null + 'jack', typeof(a)) 6 console.log(a = undefined + 'jack', typeof(a)) 7 console.log(a = true + 'jack', typeof(a)) 8 9 // 报错 10 // console.log(a = symbol + 'jcak', typeof(a)) 11 // console.log(a = object + 'jack', typeof(a)) 12 13 // 数字 14 console.log('====== number =======') 15 console.log(a = null + 8, typeof(a)) 16 console.log(a = undefined + 8, typeof(a)) // undefined 是无法转换成一个对应的数字 17 console.log(a = true + 8, typeof(a)) 18 console.log(a = false + 8, typeof(a)) 19 20 // boolean 21 // & ==> 位与 22 console.log('====== boolean =======') 23 console.log(a = null + true, typeof(a)) 24 console.log(a = null + false, typeof(a)) 25 console.log(a = undefined + true, typeof(a))// NaN ==> not a number 26 console.log(a = undefined +false, typeof(a)) // NaN 27 console.log(a = null & true, typeof(a)) // 0 28 console.log(a = undefined | true, typeof(a)) // 1 29 console.log(a = undefined | false, typeof(a)) // 0 30 console.log('====== boolean =======') 31 console.log(a = undefined & true, typeof(a)) // 0 32 console.log(a = undefined & false, typeof(a)) // 0 33 34 35 // 短路,从打印结果看,console.log()后 会有一个空格 36 // and ===> && 37 console.log('====== 短路 =======') 38 console.log(a = null && true, typeof(a)) ------类型是 object 39 40 console.log(a = false && null, typeof(a)) 41 console.log(a = false && 'llll', typeof(a)) 42 43 console.log(a = true && 'llll', typeof(a)) 44 console.log(a = true && '', typeof(a)) 45 46 // null 47 console.log('===== null ===== ') 48 console.log(a = null + undefined, typeof(a))
结果:
1 Info: Start process (21:17:33) 2 ====== string ====== 3 3jack string 4 nulljack string 5 undefinedjack string 6 truejack string 7 ====== number ======= 8 8 'number' 9 NaN 'number' 10 9 'number' 11 8 'number' 12 ====== boolean ======= 13 1 'number' 14 0 'number' 15 NaN 'number' 16 NaN 'number' 17 0 'number' 18 1 'number' 19 0 'number' 20 ====== boolean ======= 21 0 'number' 22 0 'number' 23 ====== 短路 ======= 24 null 'object' 25 false 'boolean' 26 false 'boolean' 27 llll string 28 string 29 ===== null ===== 30 NaN 'number' 31 Info: End process (21:17:34)
弱类型,不需要强制类型转换,会隐式类型转换
NaN 即not a numober 转换数字失败,它和任何值都不等,和自己也不等,只能使用Number.isNaN(NaN)
总结:
-
-
- 遇到字符串,加号就是拼接字符串,所有非字符串隐式转换为字符串
- 如果没有字符串,加号把其他所有类型都当作数字处理,非数字类型隐式转换为数字,undefined特殊,因为它没有定义值,所有转换数字失败得到一个特殊值NaN
- 如果运算符是逻辑运算符,短路符,返回就是短路时的类型,没有隐式转换
- 除非十分明确,否知不要依赖隐式转换,往往为了程序的健壮,显示转换
-
4.4、字符串
将一个值使用 单引号或者 双引号 引用起来就是字符串。
ES6 提供了反引号 定义一个字符串,可以支持多行,还支持插值、
1 let a = 'abc' 2 let b = "123" 3 let c = `jack 4 like 5 love 6 `// 支持多行 7 console.log(c) 8 9 // 字符串插值,要求在反引号字符串中,python3.6支持 10 let name = 'tom', age = 12 11 console.log(`hi, my name is ${name}. I am ${age}`)
结果:
1 jack 2 like 3 love 4 5 hi, my name is tom. I am 12
4.5、转义字符
4.6、字符串操作方法
字符串操作方法很多,但是和Python 类似
1 let school = 'magedu' 2 console.log(school.charAt(2)) 3 console.log(school[2]) 4 console.log(school.toUpperCase()) 5 console.log(school.concat('.com')) 6 // 左包右不包,跟python类似 7 console.log(school.slice(3)) 8 console.log(school.slice(3,5)) 9 console.log(school.slice(-2,-1)) 10 console.log(school.slice(-2)) 11 12 console.log('================================') 13 let url = 'www.magedu.com' 14 console.log(url.split('.')) 15 console.log(url.substr(7,2)) // 2 是步进数 16 console.log(url.substring(7,10))// 是 索引范围 17 18 19 console.log('================================') 20 21 let s = 'magedu.edu' 22 console.log(s.indexOf('ed')) 23 console.log(s.indexOf('ed',4))// 开始索引 24 console.log(s.replace('.edu','.com')) 25 26 27 console.log('================================') 28 29 s = ' mag edu ' 30 // 去掉两端空白字符 31 console.log(s.trim()) 32 33 // 一下是非标准函数,少用 34 console.log(s.trimLeft()) 35 console.log(s.trimRight())
结果:
1 Info: Start process (22:01:56) 2 g 3 g 4 MAGEDU 5 magedu.com 6 edu 7 ed 8 d 9 du 10 ================================ 11 [ 'www', 'magedu', 'com' ] 12 ed 13 edu 14 ================================ 15 3 16 7 17 magedu.com 18 ================================ 19 mag edu 20 mag edu 21 22 mag edu 23 Info: End process (22:01:56)
4.6、数值型number
在JS 中,数据均为双精度浮点型,范围只能在 -(2^53 -1)和 2^53 -1 之间,整形也不例外。
数字类型还有三种符号值:
+infinity(正无穷)
-infinity(负无穷)
NaN:非数字
二进制:0b0011, 0B0011
八进制:0755,ES6中最好使用0O最前缀,0o72
十六进制:0xAA
指数表示:1E3(1000), 2e-2(0.02), e 大小写都可以
常量属性:
1 var biggestNum = Number.MAX_VALUE 2 var smallestNum = Number.MIN_VALUE 3 var infiniteNum = Number.POSITIVE_INFINITY 4 var negIngfiniteNum = Number.NEGATIVE_INFINITY 5 var notANUm = Number.NaN 6 7 console.log(biggestNum) 8 console.log(smallestNum) 9 console.log(infiniteNum) 10 console.log(negIngfiniteNum) 11 console.log(notANUm) 12 13 console.log(1/0) // Infinity
结果:
1 1.7976931348623157e+308 2 5e-324 3 Infinity 4 -Infinity 5 NaN 6 Infinity
数学方法:
测试:
1 a = Number.parseFloat('3') 2 console.log(a, typeof(a)) 3 4 console.log(Number.parseInt('3e-3')) 5 6 console.log(Number.isFinite(1/0)) 7 console.log(Number.isFinite(1)) 8 9 10 console.log(Number.isInteger(1/3)) 11 12 console.log(Number.isNaN(undefined)) 13 console.log(Number.isNaN(NaN))
结果:
1 3 'number' 2 3 3 false 4 true 5 false 6 false 7 true
内置数学对象Math
1 console.log(Math.PI) 2 console.log(Math.abs(-1)) 3 console.log(Math.log2(16)) 4 console.log(Math.sqrt(2)) 5 console.log(Math.random()) // 0-1之间的随机数,全开 6 7 8 9 Info: Start process (22:31:58) 10 3.141592653589793 11 1 12 4 13 1.4142135623730951 14 0.2193407529306861 15 Info: End process (22:31:59)
4.7、运算符
算数运算符: + - * / % 等跟python一样
测试:
1 console.log(1/2) // 该怎么除就怎么除 2 console.log(1/0) // 没有异常,且正无穷 3 console.log(5 % 3) // 余数,取模 4 console.log('=========================================') 5 console.log(parseInt(1/2)) // 同Number.parseInt() 6 console.log(parseInt('1/2')) // 同Number.parseInt() 7 console.log(parseInt(3/2)) // 同Number.parseInt() 8 console.log(parseInt('3/2')) // 同Number.parseInt() 9 console.log(parseInt(2e3)) // 同Number.parseInt() 10 console.log(parseInt('2e3')) // 同Number.parseInt() 11 console.log('=========================================') 12 console.log(Math.floor(3/2)) 13 console.log(Math.ceil(3/2)) 14 console.log(Math.round(3/2)) 15 console.log(Math.round(1/2))// 四舍五入,不同于python 16 console.log(Math.round(2/5)) 17 console.log(Math.round(3/5))
结果:
1 Info: Start process (10:44:15) 2 0.5 3 Infinity 4 2 5 ========================================= 6 0 7 1 8 1 9 3 10 2000 11 2 12 ========================================= 13 1 14 2 15 2 16 1 17 0 18 1 19 Info: End process (10:44:16)
++ 和 --
单目运算符,代表变量自增,自减
i++, 先用 i, 用完之后 i 再自增 加 1
++ i ,先加 1 ,在使用 i
测试:
1 let i = 0 2 let a = i++ 3 console.log(a, i) // 0,1 4 console.log(a, i++)//0,1 5 a = ++i// 3, 6 console.log(a, ++i)// 3,4 7 8 9 i = 0; 10 let b = ++i+i+++i+++i; 11 console.log(b, i) 12 13 // 单目优先级高于双目 14 // ++i + i++ + i++ + i 15 // 1 1 2 3 16 17 18 ---------------------------------------------------------------- 19 Info: Start process (10:55:33) 20 0 1 21 0 1 22 3 4 23 7 3 24 Info: End process (10:55:34)
比较运算符:
> , < , >=, <=, !=, ==, !==, ===
==:宽松相等,进行类型转换
===:严格相等,不进行类型转换
测试:
1 console.log(100 > '200') 2 console.log(300 > '200') 3 console.log(300 > '2000') 4 console.log(3000 > '2a') 5 console.log('3000' > '2a') 6 console.log('3e' > '2a') 7 console.log('3000' > '2000') 8 console.log('===============================') 9 console.log(300 == '300') 10 console.log('200' =='200') 11 console.log(300 === '300') 12 console.log('200' === '2000') 13 console.log('200' !== 200) 14 15 16 17 --------------------------------------------------------------- 18 Info: Start process (11:06:23) 19 false 20 true 21 false 22 true 23 true 24 true 25 =============================== 26 true 27 true 28 false 29 false 30 true 31 Info: End process (11:06:23)
像上面的是3000 > '2a' 就没法比较了,所以使用宽松比较的时候,尽可能保证 类型相同,,否则会引起隐式转换,而且隐式转换的规则很复杂不好把控
如果不知道类型是否一致,就使用严格等 ,也是建议使用的。
逻辑运算符:
&& || ! 与,或, 非
这些运算符和其他高级语言都一样,支持短路
位运算符:
& | ^ ~ << >> 位与,位或,异或,取反,左移,右移,和python一样
三元运算符:
条件表达式 ? 真值:假值
逗号操作符:
JS 运行多个表达式写在一起
1 let a = 4+5, b = true, c=a >20 ? 't':'f' 2 /** 3 * 分别执行: 4 * a = 4+5 // 9 5 * b = true 6 * c = 'f 7 */ 8 console.log(a) // 9 9 console.log(c) // 'f' 10 11 function test(){ 12 return 3, a + b, c = a++; 13 /** 14 * 因为 return 返回一个值,就是最后一个逗号之后的结果 15 * 前面有几个结果都不管 16 */ 17 } 18 19 console.log(test()) 20 console.log(c) 21 console.log(a) // 10 22 console.log('==================================')
结果;
1 9 2 f 3 9 4 9 5 10 6 ==================================
测试:函数可以后定义??,测试发现,调用了后面的函数
1 let a = 4+5, b = true, c=a >20 ? 't':'f' 2 /** 3 * 分别执行: 4 * a = 4+5 // 9 5 * b = true 6 * c = 'f 7 */ 8 console.log(a) // 9 9 console.log(c) // 'f' 10 11 function test(){ 12 return 3, a + b, c = a++; 13 /** 14 * 因为 return 返回一个值,就是最后一个逗号之后的结果 15 * 前面有几个结果都不管 16 */ 17 } 18 19 console.log(test()) 20 console.log(c) 21 console.log(a) // 10 22 console.log('==================================') 23 24 /////////////////////////////////////////////////// 25 function test(){ 26 a++; 27 return a++; 28 } 29 30 console.log(test()) 31 console.log(a) 32 33 38 ------------------------------------------------------------------------ 39 40 9 41 f 42 10 43 f 44 11 45 ================================== 46 12 47 13
其他一些方法:
1 console.log('a' instanceof String) 2 console.log(1 instanceof Number) 3 4 5 a = new String('b') 6 console.log(a instanceof String) 7 console.log(new Number(1) instanceof Number) 8 console.log(a instanceof Object) 9 10 console.log(typeof('a')) 11 console.log(typeof 'a') 12 console.log(typeof a) 13 14 15 ---------------------------------------------------------------------- 16 Info: Start process (11:41:32) 17 false 18 false 19 true 20 true 21 true 22 string 23 string 24 object 25 Info: End process (11:41:33)
instanceof 要求必须明确使用类型定义变量,就是对象必须是 new关键字 声明创建的,它可以用于继承关系的判断。
typeof 就是返回对象的类型字符串
测试:删除
1 x = 42; 2 var y = 43; 3 let z = 60; 4 myobj = new Number(); 5 myobj.h = 4; 6 console.log(delete x) //可以删除 隐式定义的 7 console.log(delete y) // 不可以 删除var, let声明的变量 8 console.log(delete z) 9 console.log(delete Math.PI) // 不能删除预定义的属性 10 console.log(delete myobj.h) //可以删除用户定义的对象属性 11 console.log(delete myobj) // 可以删除,隐式定义的 对象 12 console.log('========================================') 13 14 var trees = new Array('a', 'b', 'c', 'd', 'e') 15 for(var i=0;i<trees.length;i++){ 16 console.log(trees[i]) 17 } 18 19 20 可以看到 即便删除了某个元素,但是这个位置还在。 21 console.log('========================================') 22 delete trees[3] 23 for(var i=0;i<trees.length;i++){ 24 console.log(trees[i]) 25 }
结果;
1 Info: Start process (12:04:55) 2 true 3 false 4 false 5 false 6 true 7 true 8 ======================================== 9 a 10 b 11 c 12 d 13 e 14 ======================================== 15 a 16 b 17 c 18 undefined 19 e 20 Info: End process (12:04:56)
测试:索引,数组
1 let trees = new Array('a','b','c','d','e') 2 console.log(0 in trees)// 0 在属组对象的 index中 3 console.log(3 in trees) 4 console.log('a' in trees) // a 不是属性,是一个数组中的值 5 console.log('length' in trees) // length 是对象的属性 6 console.log(trees.length) 7 console.log('===========================================') 8 delete trees[3] 9 console.log(3 in trees);// 虽然位置在,但是索引 里已经删除了,也不会挪动 10 for(var i=0;i<trees.length;i++){ 11 console.log(trees[i]) 12 } 13 console.log('===========================================') 14 let mycar = { 15 color:'red', 16 year:1999, 17 } 18 console.log('color' in mycar) 19 console.log('model' in mycar)
结果:
1 Info: Start process (12:15:40) 2 true 3 true 4 false 5 true 6 5 7 =========================================== 8 false 9 a 10 b 11 c 12 undefined 13 e 14 =========================================== 15 true 16 false 17 Info: End process (12:15:40)
运算符优先级:从高到底
表达式:
基本表达式,和python差不多
解析式也和Python差不多,但是在ES6 中非标准 不推荐使用
生成器推荐使用生成器函数,ES6 开始支持
测试:生成器函数
1 function * inc(){ 2 let i = 0; 3 let j = 4; 4 while (true) { 5 yield i++; 6 if(!j--) return 100; 7 } 8 } 9 10 let gen = inc() 11 for(let i=0;i<10;i++){//循环10次 12 console.log(gen.next()) 13 }
结果:不同于python, 即便是return值,也会返回,结束后,不会抛异常
1 Info: Start process (12:27:58) 2 { value: 0, done: false } 3 { value: 1, done: false } 4 { value: 2, done: false } 5 { value: 3, done: false } 6 { value: 4, done: false } 7 { value: 100, done: true } 8 { value: undefined, done: true } 9 { value: undefined, done: true } 10 { value: undefined, done: true } 11 { value: undefined, done: true } 12 Info: End process (12:27:58)
每次调用next() 方法返回一个对象,这个对象包含两个属性:value 和done
value:属性表示本次yield 表达式的返回值
done:属性为布尔值,false表示后续还有yield语句执行,ture:如果执行完或return后
5、语句块:
JS 使用大括号 构成语句块
ES6 之前的语句块是没有 作用域的,从ES6 开始支持 块作用域的, let只能在块作用域内可见。
测试:自定义变量的作用范围,隐式定义,var , let
1 function hello(){ 2 let a = 1 3 var b = 2 4 c = 3 5 } 6 7 // let d = 10 8 if (1) { 9 let d = 4; 10 var e = 5; 11 f = 6 12 if (true) { 13 console.log(d)// 可以看到 d 14 console.log(e) 15 console.log(f) 16 console.log('================') 17 g = 10 18 var h = 11 19 } 20 } 21 22 hello() // 先调用 23 24 // console.log(a) // 不可见,因为let 只要遇到{} 就出不去 25 // console.log(b) // 不可见,因为var 遇到函数 就出不去 26 console.log(c) // 可见,c 隐式定义,在哪里都是全局的 27 // console.log(d) // 不可见,遇到 {} 出不去,但是内部的看可以看到 28 console.log(e) // 可见 29 console.log(f) // 隐式声明,可见 30 console.log(g) // 可见 31 console.log(h) // 可见
6、流程控制:
6.1、条件分支:
条件的False 等效:
false, undefined,null, 0, NaN, 空字符串
测试:等效 false
1 a = [null, NaN,0, undefined,false, '', [], {}] 2 for (let i=0;i<a.length;i++){ 3 console.log(a[i], i, typeof(a[i]), '==================') 4 if (a[i]) { 5 console.log('true') 6 } else { 7 console.log('false') 8 } 9 }
结果:
1 Info: Start process (12:33:09) 2 null 0 'object' '==================' // null 是object 类型 3 false 4 NaN 1 'number' '==================' 5 false 6 0 2 'number' '==================' 7 false 8 undefined 3 'undefined' '==================' 9 false 10 false 4 'boolean' '==================' 11 false 12 5 string ================== 13 false 14 [] 6 'object' '==================' 15 true 16 {} 7 'object' '==================' 17 true 18 Info: End process (12:33:09)
6.2、 switch...case 分支语句
这里最大的问题,就是会有 穿透问题,一定要在case中恰当的使用break,否则就会继续顺序执行下去
测试:穿透, 如果 x 值不在case 中,就执行default
6.3、for循环
测试:
6.4、while, do...while 循环
while:先判断,在循环
do...while: 先循环, 在判断
测试:
1 let x = 10 2 while (x--) {//先用10,判断10 是等价 true,再-- 就是9 3 console.log(x) 4 } 5 console.log('===========') 6 // 上面执行结束之后 x == -1 7 do { 8 console.log(x); 9 } while(x++ < 10) // -1 < 10, x += 1
结果:
1 Info: Start process (13:30:01) 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1 11 0 12 =========== 13 -1 14 0 15 1 16 2 17 3 18 4 19 5 20 6 21 7 22 8 23 9 24 10 25 Info: End process (13:30:02)
九九乘法表:(正常模式)
1 for (let i=1;i<10;i++) { 2 line = '' 3 for (let j=1;j<=i;j++) { 4 line += `${j}*${i}= ${i*j} `; 5 } 6 console.log(line) 7 }
结果:
1 Info: Start process (13:42:18)
2 1*1= 1
3 1*2= 2 2*2= 4
4 1*3= 3 2*3= 6 3*3= 9
5 1*4= 4 2*4= 8 3*4= 12 4*4= 16
6 1*5= 5 2*5= 10 3*5= 15 4*5= 20 5*5= 25
7 1*6= 6 2*6= 12 3*6= 18 4*6= 24 5*6= 30 6*6= 36
8 1*7= 7 2*7= 14 3*7= 21 4*7= 28 5*7= 35 6*7= 42 7*7= 49
9 1*8= 8 2*8= 16 3*8= 24 4*8= 32 5*8= 40 6*8= 48 7*8= 56 8*8= 64
10 1*9= 9 2*9= 18 3*9= 27 4*9= 36 5*9= 45 6*9= 54 7*9= 63 8*9= 72 9*9= 81
11 Info: End process (13:42:19)
6.5、for... in 循环
对象操作语句 用来遍历 对象的属性。
测试:
注意:for in 循环返回的是索引,需要间接的访问值,数组反正返回的是索引,,C风格for循环操作可能方便点
6.6、for...of 循环
ES6 新语法
注意: for...of 不能迭代对象,
原因是 of 后面必须是一个迭代器,
break,continue:
for迭代的 差别: