数组
-
数组的两种声明方式
var arr1 = new Array(1, 'a', false) var arr2 = [2, 'b', true] -
越界不报错
console.log(arr1[5]) // undefined -
索引赋值,索引超过范围照样能赋值
arr1[5] = null console.log(arr1) // [ 1, 'a', false, <2 empty items>, null ] -
push pop向数组的末尾(添加、删除元素)
var s = arr1.pop() console.log(s) arr1.push(1, 2) -
unshift shift 向数组的头部(添加、删除元素)
arr1.unshift('a', 1) console.log(arr1.shift()) -
splice (start: number, deleteCount: number, ...items: string[])
- 从start开始删除 deletecount个参数, items为在删除后在start位置添加的参数
var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle']; // 从索引2开始删除3个元素,然后再添加两个元素: arr.splice(2, 3, 'Google', 'Facebook'); // 返回删除的元素 ['Yahoo', 'AOL', 'Excite'] -
sort/reverse 对arr进行排序 正向和反向
console.log(arr.sort()) console.log(arr.reverse()) -
concat 和slice 将数组拼接,拆分
console.log(arr1.concat(arr2)) console.log(arr1.slice()) //arr1的浅拷贝 console.log(arr1.slice(1, 3))
对象
-
对象的创建方法
var obj1 = new Object() var obj2 = {} -
未定义的属性不报错
obj1.a = 1 console.log(obj1.a) console.log(obj1.b) // undefined -
删除不存在的属性不会报错
delete obj1.b -
判断对象是否有该属性
console.log(obj1.hasOwnProperty('a')) -
null 为空值, undefined为未定义 没什么用处
运算符
- 逻辑运算符
- &&与 ||或 !非
var a = 1 if(a == 1 && a == 2){ console.log("a") } - 关系运算符
// 关系运算符 var b = true console.log(a == b) //自动转换类型比较 console.log(a === b) //数据类型不一致返回false, 一致再比较
变量
-
变量提升
- 全局变量无论声明在何处,都会被提升至所在作用域顶部
- JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有声明的变量“提升”到函数顶部
{ let a1 = 2 //局部变量声明,无变量提升 var a2 = 3 //全局变量声明,有变量提升 } // console.log(a1) 报错 console.log(a2) function foo1() { var x = 'Hello, ' + y; console.log(x); var y = 'Bob'; } // JavaScript引擎看到的代码相当于 function foo2() { var y; // 提升变量y的申明,此时y为undefined var x = 'Hello, ' + y; console.log(x); y = 'Bob'; } -
常量声明
const c1 = 20 -
解构赋值
var arr = ['hello', ['js', 'ES6']] var [x, [y, z]] = arr console.log(x, y, z) // 相比于传统方式简单不少 x = arr[0] y = arr[1][0] z = arr[1][1] console.log(x, y, z) var person = { name: '小明', age: 20, gender: 'male', } // 对象解开后是属性, 可以直接导出你需要的属性, 用的地方很多 var {name, age, passport} = person console.log(name, age, passport)
异常捕获
- try-catch-finally
- try: 捕获代码块中的异常
- catch: 出现异常时需要执行的语句块
- finally: 无论成功还是失败 都需要执行的代码块
var s = null try{ s.length }catch(e){ // e为捕获到的Error,可自己命名 console.log('has error, '+ e) }finally{ console.log('final') } - Error对象 与抛出异常
var err = new Error('异常') console.log(err) // Error: 异常 // at file:///d:/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/%E5%89%8D%E7%AB%AF/err.mjs:16:12 // at ModuleJob.run (node:internal/modules/esm/module_job:193:25) try{ throw err }catch(e){ console.log('has error, '+ e) }
函数
function add(x, y){
return x + y
}
console.log(add(1, 2))
console.log(add('a', 2))
- 对象添加方法
var person = {name:'小明', age:23} person.Name = function(){ console.log(`${this.name}`) // this为本对象 } person.Name() - this的坑:返回的函数找不到上下文(this)
person.greetfn = function() { return function() { console.log(`hello, my name is ${this.name}`) } } person.greetfn()() - 解决方法:通过变量+闭包把this传递
person.greetfn = function() { var that = this // 这个写法很多,别看不懂 return function() { console.log(`hello, my name is ${that.name}`) } } - 箭头函数(匿名函数)。 实体为: (params ...) => { ... }
var fn = x => x*x console.log(fn(2)) - 箭头函数的this可继承上下文
person.greetfn = function() { return () => { // this 继承自上层的this console.log(`hello, my name is ${this.name}`) } }
名称空间
不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象 window ,全局作用域的变量实际上被绑定到 window 的一个属性
浏览器内使用 alert("1") 与 window.alert("1") 相同
- 覆盖浏览器内置方法 alert
修改后
- 导出变量
//export.mjs文件 var firstName = 'Michael'; var lastName = 'Jackson'; var year = 1958; export {firstName, lastName, year}; //import.mjs文件 import { firstName, lastName as ln, MYAPP, year } from "./export.mjs" //as能进行重命名 console.log(firstName, ln) - 将导出的属性和方法绑定到一个变量
//export.mjs文件 var MYAPP = {} MYAPP.name = 'myapp'; MYAPP.version = 1.0; MYAPP.foo = function () { return 'foo'; }; export {MYAPP}; //import.mjs文件 import {MYAPP as Module}from'./export.mjs' console.log(Module.name) - 默认导出
- 使用 import 命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载, 比如
- 如果我们想要直接导入模块,再看该模块下有哪些变量可用
// export default命令用于指定模块的默认输出。 //显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。 //所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令 //export.mjs文件 var APP = {} APP.name = 'APP' export default APP //import.mjs文件 import myPKG from './export.mjs' console.log(myPKG.name)
条件与循环
-
if语句和for语句与c语言相同
-
for in 对象遍历出来的元素为对象的属性, 数组遍历的元素为索引
var o = { name: 'Jack', age: 20, }; for (var key in o) { console.log(key); // 'name', 'age' } -
for of 遍历数组元素,不能遍历对象(可有变通方法)
var a = ['A', 'B', 'C']; for (var x of a) { console.log(x); // 'A', 'B', 'C' } for (var key of Object.keys(o)){ // 变通方法 console.log(key) } -
forEach 相当于对for of的面向对象化
a.forEach(element => { console.log(element) })
Promise对象
- 在 JavaScript 的世界中,所有代码都是单线程执行的。
- 由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。Javascript 通过回调函数实现异步
单线程异步模型
- 回调:并不会真正阻塞1秒, 而是在1秒后调用该函数, 这就是 JavaScript 的编程范式: 基于回调的异步。
function callback(){ console.log('Done') } console.log('before setTimeout()'); setTimeout(callback, 1000); // 1秒钟后调用callback函数 console.log('after setTimeout()');
Promise与异步
-
我们来看一个函数,
resolve是成功后的回调函数,reject是失败后的回调函数function testResultCallBackFunc(resolve, reject){ var timeOut = Math.random() * 2; console.log('set timeout to :' + timeOut + 'seconds.') setTimeout(function(){ if(timeOut < 1){ console.log('call resolve()...'); resolve('200 ok'); }else{ console.log('call reject()...') reject('timeout in' + timeOut + 'seconds.') } }, timeOut * 100); } -
然后我们把处理成功和失败的函数 作为回调传递给该函数
function testResultCallBack(){ var success = (message)=>{console.log(`success ${message}`)} var failed = (error)=>{console.log(`failed ${error}`)} testResultCallBackFunc(success, failed) } testResultCallBack() // set timeout to: 0.059809346310547795 seconds. // call resolve()... // success 200 OK -
可以看出,
testResultCallbackFunc()函数只关心自身的逻辑,并不关心具体的resolve和reject将如何处理结果 -
JS 把这种编程方式抽象成了一种对象:
Promisevar p1 = new Promise(testResultCallbackFunc) p1.then((resp) => { console.log(resp) }).catch((err) => { console.log(err) }) // set timeout to: 0.628561731809246 seconds. // call resolve()... // 200 OK -
可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:
-
Async函数和promise组合
- 这些需要提到 async函数, async函数由内置执行器进行执行, 这和
go func()有异曲同工之妙 - 那我们如果声明一个异步函数, 其实很简单 在你函数前面加上一个
async关键字就可以了 - 这里
testWithAsync就是一个异步函数, 他执行的时候 是交给 JS 的携程执行器处理的, 而await关键字 就是 告诉执行器 当p1执行完成后 主动通知我(协程的一种实现)
async function testWithAsync(){ var p1 = new Promise(testResultCallBackFunc) try{ var resp = await p1 console.log(resp) }catch(e){ console.log(e) } } - 这些需要提到 async函数, async函数由内置执行器进行执行, 这和