2022-06-02
devops
00
请注意,本文编写于 665 天前,最后修改于 665 天前,其中某些信息可能已经过时。

目录

HTML
结构
标签
用户注册
CSS
使用3种方式
语法
selector
NodeJS
vscode插件
node语言学习
注释
变量
数据类型
弱类型转换
任何类型+字符,前面都为字符, 结果为字符
除字符之外任何类型+数值,结果均为数值
除字符,数值之外任何类型 + bool, 结果均为数值
位与, 结果均为数值
null与undefined, 结果均为数值
与或非
字符串操作
数值型number 操作
运算符
算术运算符
比较运算符
逻辑运算符
位运算
三元运算
逗号运算
其他
typeof, instanceof
delete 删除对象
in 判断属性
运算优先级
表达式
生成器
循环分支语句
分支语句
for循环
遍历索引 i<?, 遍历值of,遍历属性 in
多初始化
死循环
while循环
完成 9 X 9 乘法表
js进阶
作用域
类使用方法
实现相同的过程
npx 相当于 npm execute, 即执行$(npm bin)目录下的文件
现在可以导入了

HTML

vscode + live server插件

重点在css, 更重点在js(java script)

不好看,没有人使用。

结构

head: meta元数据, title标签, link 引入css,script引入外部js, <style> 内联样式

body: 浏览器渲染

标签

ul > li 无序

ol>li 有序

table>tr>th*3 tr>td*3

input textarea

用户注册

<!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> <h1>欢迎来到mykernel.cn</h1> <form action="" method="POST" enctype="application/x-www-form-urlencoded"> <table border="1" width="50%"> <tr> <td colspan="2"> 注册</td> </tr> <tr> <td> 用户 </td> <td> <!-- <input type="text" name=""> 只提交有name的部分 --> <input type="text" name="username"> </td> </tr> <tr> <td> 密码 </td> <td> <input type="password" name="password"> </td> </tr> <tr> <td> 性别 </td> <td> <!-- <input type="radio" name="gender" id=""> 男 没有value, 点就是on, 不点就是空 --> <input type="radio" name="gender" id="" value="1" checked> 男 <input type="radio" name="gender" id="" value="0"> 女 </td> </tr> <tr> <td> 爱好 </td> <td> <input type="checkbox" name="love" id="" value="1"> music <input type="checkbox" name="love" id="" value="2" checked> movie <input type="checkbox" name="love" id="" value="3"> game </td> </tr> <tr> <td> 其他描述 </td> <td> <textarea name="desc" id="" cols="30" rows="10"></textarea> </td> </tr> <tr> <td colspan="2"> <input type="submit" value="提交"> <input type="reset" value="重置"> </td> </tr> </table> </form> </body> </html>
  1. <form action="" method="POST" enctype="application/x-www-form-urlencoded"> 默认GET方法,参数是查询 参数。POST方法,参数就是请求体,不限制大小,更安全;

    application/x-www-form-urlencoded 默认

    multipart/form-data 上传文件; input multiple 多文件

    <form action="" method="POST" enctype="multipart/form-data"> <input type="file" name="test" id="" multiple>
  2. <!-- <input type="text" name=""> 只提交有name的部分 --> 当我们把上面的name取消之后,只有name有值的部分才会提交

  3. <!-- <input type="radio" name="gender" id=""> 男 没有value, 点就是on, 不点就是空 --> 当radio/checkbox没有value时,点了就是on, 不点就是空。所以给value. radio就给0和1 checkbox就给编号

    网页是给人看的,而数据库中实际存储的是数字ID。

  4. <input type="radio" name="gender" id="" value="1" checked> 男 默认值带checked

image-20220426162848146

以后的课程不会使用原生的,但最终也是原生的。

以后不使用以上的enctype, 全部使用json.

CSS

样式,布局

使用3种方式

行内,内联,外链

123<input type="text" style="border: 0;"> <style> input { outline: none; } </style> <link rel="stylesheet" href="css/1.css">

语法

selector { key1: value1; key2: value2; key3: value3; } selector1, selector2 { key1: value1; key2: value2; key3: value3; }

selector

标签,类,id

多级,同级

伪类,伪元类

p {} # <p></p> .test {} # <input type="text" class="test"> #test {} #<input type="text" id="test"> div p # 多级 div > p # 1级 div > p+a # 同级 # 伪类 a:hover a:first-child # 伪元素 a::before a::after # 属性选择器 e[attr] e[attr=value] e[attr=^value] e[attr=$value]

NodeJS

JS标准很多,浏览器支持的不同,需要解决这个问题。框架就可以解决,我们只管使用最新的框架,不用担心浏览器版本不同。

vscode插件

chinese, live server, node exec(f8一键执行)

配置: ctrl + ,

node exec: f8

image-20220429142250232

node语言学习

注释

javascript
/** 回车,完成多行注释 // 完成单行注释

代码中也可以注释,一般在代码上下注释

变量

javascript
/** * 推荐 * 声明方式: * var 支持提升 * let ES6的新语法,解决var的问题; * const 声明必须赋值 */ var b // 声明 b = 'abc' // 赋值 console.log(b); var b = 'cde', c = 2; // 声明并赋值 console.log(b,c); let d = 125; console.log(d); /** * 不声明赋值 * 隐式定义;不推荐,严格模式下报错 */ a = 1 console.log(a); /** * 声明不赋值 undefined */ var e; let f; console.log(e,f); /** * 不声明,不赋值 ReferenceError: g is not defined */ // console.log(g); /** * 常量必须声明+赋值 * SyntaxError: Missing initializer in const declaration */ // const h const h = undefined; // 悬空, python None -> js null console.log(h); /** * 先使用,后声明 * 声明提升 * var 支持提升, undefined * let 不支持提升, ReferenceError: Cannot access 'abc' before initialization */ console.log(ab); var ab; // console.log(abc); let abc; /** * 变量引用 * `` 可以引用变量,可以多行 */ const x= 100, y = 200; console.log(x,y,`${x} ${y}`); // 100 200 100 200

使用var bug多

作用域

javascript
function test() { a = 100 // 未定义 作用域全局,函数外部可访问;严格模式下禁止 var b = 2 // 作用域在函数中 let c = 3 } test() console.log(a); console.log(b); // ReferenceError: b is not defined console.log(c); // ReferenceError: c is not defined

变量

var a = 100; var a = 200; console.log(a); // 正常 let b = 10; let b = 20; // SyntaxError: Identifier 'b' has already been declared console.log(b);

框架中,使用最多let, 其次const。不要使用var, 隐式定义;

标识不修改,直接定义const。

标识需要修改,直接let。

数据类型

名称描述
number整型,浮点
booleantrue, false
string字符串, ' ' 或 " "
nullpython中的None
undefined悬空的,就是声明不赋值
symbolES6引入 ,常量
object类型类似字典; ES3出现 json js object notation
javascript
let obj = { a: 1, // a不加引号,等价 "a", 'a', `a`; 属性为a, 属性值为1。 "b": 'abc', // 右边值字符串必须使用引号; ' ', ` `, " " c: undefined, d: null, e: [1,2,3], // array 数组 --> python的 list } console.log(obj.b,obj.c,obj.d,obj.a, obj.e);

判断语言的强弱

javascript
/** * 是否支持隐式类型转换,正常就是弱类型 */ console.log('a' + 1); /** * 类c语言的语法 * a=, a是标识符 */ console.log(a='a' + 1,a+'2', typeof (a + '2')); //a1 a12 string

弱类型转换

任何类型+字符,前面都为字符, 结果为字符
javascript
console.log('============== string ====================='); console.log(a = 3 + 'a', typeof(a)); // 3a string console.log(a = null + 'a', typeof(a)); // nulla string console.log(a = undefined + 'a', typeof(a)); // undefineda string console.log(a = true + 'a', typeof(a)); // truea string
除字符之外任何类型+数值,结果均为数值
javascript
console.log('============== number ====================='); console.log(a = null + 8, typeof(a)); // null 为 0 8 number console.log(a = undefined + 8, typeof(a)); // NaN number console.log(a = true + 8, typeof(a)); // true 为 1 9 number console.log(a = false + 8, typeof(a)); // false 0 8 number
除字符,数值之外任何类型 + bool, 结果均为数值
javascript
console.log('============== bool ====================='); console.log(a = null + true, typeof(a)); // 1 number console.log(a = null + false, typeof(a)); // 0 number console.log(a = undefined + true, typeof(a)); // NaN number console.log(a = undefined + false, typeof(a)); // NaN number console.log(a = true + true, typeof(a)); // 2 number console.log(a = false + false, typeof(a)); // 0 number
位与, 结果均为数值
javascript
/** * & 与 * | 或 * ~ 非 */ console.log(a = null & true, typeof a); // 0 number console.log(a = undefined & true, typeof a); // 0 number
null与undefined, 结果均为数值
javascript
console.log('========= null ========='); console.log(a = null + undefined, typeof(a)); // NaN number console.log(a = null - undefined, typeof(a)); // NaN number console.log(a = null * undefined, typeof(a)); // NaN number console.log(a = null / undefined, typeof(a)); // NaN number
与或非
javascript
/** * && and 与 * || or 或 * ! not 非 */ console.log(a = null && true, typeof(a)); // null object console.log(a = "magedu" && true, typeof(a)); // true boolean console.log(a = 'magedu' && true, typeof(a)); // true boolean console.log(a = true && "magedu", typeof(a)); // magedu string console.log(a = true && 'magedu', typeof(a)); // magedu string console.log(a = "magedu" && false, typeof(a)); // false boolean console.log(a = 'magedu' && false, typeof(a)); // false boolean console.log(a = false && "magedu", typeof(a)); // false boolean console.log(a = false && 'magedu', typeof(a)); // false boolean console.log(a = true && '' && 'magedu', typeof(a)); // string // 1 * 0 * 1 = 0 console.log(a = null || true, typeof(a)); // true boolean console.log(a = ! null, typeof(a)); // true boolean // [] , {} 在javascript中识别为true console.log(a = [] && 'abc', typeof(a)); // abc string console.log(a = {} && 'abc', typeof(a)); // abc string

字符串操作

javascript
/** * 引用 `${variable}` a * 索引 [] * 切片,没有 slice * 大写,小写 toUpperCase, toLowerCase * 组合, contact, +, `` * 分割 split * 替换 replace * 取子串 substring * 查询字符串位置 index * 重复字符中 repeat * 删除两头 trim */ const a = 'mykernel' console.log(`blog.${a}.cn`); // blog.mykernel.cn console.log(a[2], a.charAt(2)); // console.log(a[2:5]); console.log(a.slice(2,5)); // ker console.log(a.slice(2)); // kernel console.log(a.slice(2,-1)); // kerne console.log(a.toUpperCase()); // MYKERNEL console.log(a.toLowerCase()); // mykernel const b = ('blog.' + a).concat('.cn') console.log(b); // blog.mykernel.cn console.log(b.split('.')); // [ 'blog', 'mykernel', 'cn' ] console.log(b.replace('blog.','liangcheng.')); // liangcheng.mykernel.cn console.log(b.substring(0)); // blog.mykernel.cn console.log(b.substring(0,b.length)); // blog.mykernel.cn console.log(b.indexOf('.')); // 从左到右,搜索第1个.出现的索引位置 4 console.log(b.indexOf('.',5)); // 从左到右,搜索第1个.出现的索引位置 13 console.log('-'.repeat(30)); // ------------------------------ console.log('\r\n\t a b\tc\nde\f\n\r\n\r\t '.trim()); // a b c ...de

数值型number 操作

javascript
var biggestNum = Number.MAX_VALUE var smallestNum = Number.MIN_VALUE var infiniteNum = Number.POSITIVE_INFINITY // 正无穷 var negInfiniteNum = Number.NEGATIVE_INFINITY // 负无穷 var notANum = Number.NaN // 不是数值

二进制 0b

八进制 0O

十六进制 0x

javascript
/** * 取整 * python: int, floor, ceil, round; * javascript: parseInt, Math.floor, Math.ceil, Math.round; * */ console.log(parseInt('1')); console.log(1/2); // 0.5 自然除 console.log(Math.floor(0.5)); /** * parseInt 正数或负数截取整数部分 * floor 正数或负数向下取整 * ceil 正数或负数向上取整 * round 正数或负数 四舍五入 右侧最近整数 */ console.log('=--------正数------'); let nums = [0.1,0.5,0.6,2.2,2.5,2.9,3.499999,3.50001] for (let i = 0; i<nums.length; i++) { console.log(nums[i],parseInt(nums[i]),`parseInt`); console.log(nums[i],Math.floor(nums[i]),`Math.floor`); console.log(nums[i],Math.ceil(nums[i]),`Math.ceil`); console.log(nums[i],Math.round(nums[i]),`Math.round`); } console.log('=--------负数------'); for (let j of nums) { console.log(-j,parseInt(-j),`parseInt`); console.log(-j,Math.floor(-j),`Math.floor`); console.log(-j,Math.ceil(-j),`Math.ceil`); console.log(-j,Math.round(-j),`Math.round`); }

Math操作

javascript
/** * Math.PI * Math.abs * Math.log2 2为底的对数 * Math.sqrt 开根 * Math.pow 次方 * Math.random 随机在(0,1)之间 */ console.log(Math.PI); //3.141592653589793 console.log(Math.abs(-1)); // 1 console.log(Math.log2(16)); // 4 console.log(Math.sqrt(2), 2**0.5); // 1.4142135623730951 console.log(Math.pow(2,3), 2**3); // 8 console.log(Math.random() ); // 0.18607565307639917 console.log(Math.random() * 100); // (0-100) console.log(Math.random() * 97); // (0-97) console.log(Math.random() * 95 + 5); // (5-100) 同时-5 -> (0-95) console.log(Math.random() * 92 + 5); // (5-97) 同时-5 -> (0-92)

判断

javascript
/** * 判断NaN */ let a = undefined + 1 console.log(a); // NaN console.log(a == NaN); //false console.log(Number.isNaN(a)); // true

运算符

算术运算符

javascript
console.log(1/0); // Infinity 正无穷, 特殊的数值 console.log(-1/0); // -Infinity 负无穷, 特殊的数值

自增运算

javascript
/** * 自增: C/C++ 内存中直接增,效率更高;虚拟机语言也类似原则; i++ , ++i * java当中优化 i+=1, 已优化为自增; * i++ 先用后加 * ++i 先加后用 */ let i = 1 console.log(i++); // 1 语义相当于 log(i); i+=1 实际上是原地增加; console.log(i++); // 2 console.log(i); // 3 console.log(++i); // 4

完成示例

javascript
let i = 0, a = i++ console.log(a, i); // 0, 1 console.log(a, i++); // 0, 2 a = -i++ // -2, i=3 console.log(a,++i); // -2 4

完成c/java面试题

javascript
let i = 0 let a = ++i + i++ + i++ + i /** * ++i + i++ * 1 + 1 i=2 * 2 + i++ * 2 + 2 i=3 * 4 + i * 4 + 3 = 7 i=3 */ console.log(a); // 7

比较运算符

javascript
console.log(100 > 200); console.log(100 > 2000); /** * 隐式类型转换 * 按ASCII, 100 > '20' 20肯定大于100,应该是false. * 注意:任何情况下,不要使用不同类型比较; * ***** 没有意义, 会带来bug ***** */ console.log(100 > '20'); // true console.log(100 > '200'); // false console.log(200 > '200'); // false console.log(201 > '200'); // true console.log(100 > '2000'); // false /** * 比较不了,不用记 */ console.log(100 > '20a'); // false console.log(300 > '20a'); // false /** * == 字符比较 * === 字符和类型比较 */ console.log(100 == '100'); // true console.log(100 === '100'); // false

逻辑运算符

&& || !

and or not

位运算

& | ~

javascript
/** * 是否奇数 * 左移 * 2 * 右移 / 2 */ console.log( (5 & 1) === 1); // true 5是奇数

三元运算

javascript
/** * python: 成立 if 条件 else 不成立 * 类c: 条件?成立:不成立 ; 可以嵌套, 不推荐嵌套; 方便后续维护。 */ console.log(5>20?'大于':'小于等于');

逗号运算

javascript
/** * , 参数 * , 表达式 */ console.log(1, 2); console.log('finished-------1--- '); // , 表达式 相当于 let a=1; let b = 2 let a = 1, b = 2 // ; 代码分隔 let c = 1; d = 2; /** * 连续赋值 从左到右的优先级 * = > 三目 > 逗号 * */ let e = 1, f = 2, g = e++ > f ? 't' : 'f' console.log(e, f, g); console.log('finished-----2----- '); /** * test函数调用 * 逗号优先级最低,最终就是返回e. * * 表达式是有值的~~~~~~~~ * 逗号表达式的值,取决于最后一个表达式的值; * 赋值表达式的值,取决于变量的值。 */ function test() { return e = 1, f = 2, g = e++ > f ? 't' : 'f' } console.log(test()); // 逗号表达式,就是最后一个。最后一个是赋值表达式,就是g变量的值; 结果 是f console.log('finished------3---- '); /** * let, var, const 作用域 * 函数外定义, 在函数中也可以见。 全局变量 * 函数内定义,在函数外不可见。 作用域在函数中, 局部变量,局部常量 * * j 是隐式声明(因为外面没有定义j,才是隐式定义; 如果外面定义let j 就是修改全局变量),全局变量; 会造成环境污染。以后框架是严格模式,压根写不了。 * h,i 是外层的作用域,也相当于全局变量 * */ let h = 1, i = 2 function test1() { console.log(h, i, '=====test1===='); // 1 2 ========= let k = 3 var kk = 3 const kkk = 3 return null, h + i, j = h++>i?'t': 'f' } console.log(test1()); // 表达式的值,逗号最后1个,变量的值 ; f console.log(j); // f 全局变量 console.log(h); // 2 全局变量 console.log(i); // 2 全局变量 // console.log(k); // ReferenceError: k is not defined // console.log(kk); // ReferenceError: kk is not defined // console.log(kkk); // ReferenceError: kkk is not defined console.log('finished------4---- '); /** * 外面定义的let, 内部可以访问;内部定义的let外部不可以访问; * * 内部隐式定义修改,就是直接修改的外部的变量。 */ let l = 1, m = 2, n = 3 function test2() { console.log(l, m, '=====test2===='); // 1 2 ========= let o = 3 return null, l + m, n = l++>m?'t': 'f' } console.log(test2()); // console.log(o); // 访问不到 console.log(n); // test2函数外部的let console.log(l, m); // 2, 2 console.log('finished------5---- '); /** * 外层let和内层let,同时使用let * 就可以看到同一个变量有作用域了 */ let cc = 3 function test3() { let cc = 4 // python直接定义,为使用当前作用域的变量。javascript即当前这种方法类似python的方法。 console.log(cc); // 4 return cc } console.log(test3()); // 4 console.log(cc); // 3 console.log('finished------6---- ');
javascript
1 2 finished-------1--- 2 2 f finished-----2----- f finished------3---- 1 2 =====test1==== f f 2 2 finished------4---- 1 2 =====test2==== f f 2 2 finished------5---- 4 4 3 finished------6----

其他

typeof, instanceof
javascript
/** * typeof 类似 type * instanceof 类似 isinstance * 字面实例,和new实例不一样。instanceof只能识别new * * instaceof 和 typeof使用方法不一样,typeof === 字符串。instanceof与new比较, 这个就是语言兼容 * * new的是对象,统一需要大写开头 * */ console.log(typeof a); // undefined // 字面量直接定义不能这样方式 console.log('abc' instanceof String); // false console.log(1 instanceof Number); // false console.log(typeof 'abc' === "string"); // true console.log(typeof 1 === 'number'); // true // c/c++/java 一致的,必须new console.log(new Number(100) instanceof Number); // true console.log(new String(`abc`) instanceof String); // true let x = new Number(100) console.log(typeof x); // object let y = new Object() console.log(typeof y) // object
delete 删除对象
javascript
a = 1 var b = 2 let c = 3 const d = 4 let obj = { x: 100, "y": 100, } console.log(a, b, c, d); // 1 2 3 4 console.log('============= 1 =============='); /** * 删除 delete 标识符或关键字 * true 删除成功 * false 删除失败 */ console.log(delete a); // true console.log(delete b); // false console.log(delete c); // false console.log(delete d); // false console.log(b, c, d); // 2 3 4 console.log(obj.x, obj.y); // 100 100 console.log(delete obj.x); // true console.log(delete obj.y); // true console.log(obj); // {}, 注意 {} [] 当真 console.log(obj.x, obj.y); // undefined undefined console.log('============= 2 =============='); /** * 有关键字定义,不可以删除 * 没有关键字定义,可以删除 */ obj1 = new Object() console.log(delete obj); // false console.log(delete obj1); // true console.log('============= 3 =============='); /** * 内建函数库,是否可以删除 */ console.log(delete Math.floor); // true console.log(delete Math.PI); // false console.log(delete Math); // true // console.log(Math.pow(2, 4)); // ReferenceError: Math is not defined console.log('============= 4 =============='); /** * 数组删除 * 删除后索引的值undefined, 索引不会改变 * 0 1 1 3 2 5 3 7 4 9 true 0 1 1 3 2 undefined // 这个就是删除的值,就是悬空值,undefined 3 7 4 9 */ let arr = [1, 3, 5, 7, 9] console.log(arr.length); // 5 for (let i = 0; i < arr.length; i++) { console.log(i, arr[i]); } console.log(delete arr[2]); for (let i = 0; i < arr.length; i++) { console.log(i, arr[i]); } console.log('============= 5 =============='); /** * 数组定义 * [] 方便 * new Array("item1", "item2", "item3", 'item4') */ let arr2 = new Array(1, 3, 5, 7, 9) console.log(arr2.length); // 5 for (let i = 0; i < arr2.length; i++) { console.log(i, arr2[i]); } console.log(delete arr2[2]); for (let i = 0; i < arr2.length; i++) { console.log(i, arr2[i]); } console.log('============= 6 ==============');
in 判断属性
javascript
/** * in操作符不等价于python的in操作。不是判断元素 * 是判断 属性是否在对象中 * * javascript会将索引和值构建为 属性:值 对,内建有length */ let arr = [1, 3, 5, 7, 9] console.log(arr.length); // 5 console.log(0 in arr); // true console.log(1 in arr); // true console.log(3 in arr); // true console.log(5 in arr); // false console.log(2 in arr); // true console.log('length' in arr); // true console.log('============== 1 ======================'); /** * 对象in */ let obj = { a: 1, b: 'abc' } // console.log(a in obj); // a全局变量是否在对象中 ReferenceError: a is not defined console.log('a' in obj); // true console.log('============== 2 ======================'); /** * 数组定义 * [] 方便 * new Array("item1", "item2", "item3", 'item4') */ let arr2 = new Array(1, 3, 5, 7, 9) console.log(arr2.length); // 5 console.log(0 in arr2); // true console.log(1 in arr2); // true console.log(3 in arr2); // true console.log(5 in arr2); // false console.log(2 in arr2); // true console.log('length' in arr2); // true console.log('============= 3 ==============');

运算优先级

由高到低

. [] () new 单目运算: ! ~ - + ++ -- typeof void delete 双目: * / % + - << >> >>> 比较: < <= > >= in instanceof == != === !== & ^ | 逻辑: && || 三目: ? : 赋值 = += -= *= /= %= <<= >>= >>>= &= ^= |= 逗号 ,

单目 > 双目 > 三目 > 赋值 > 逗号

表达式

算术,逻辑,生成器表达式

生成器

javascript
/** * 生成器 * 与python不同,支持yield需要在function 和函数名之间加*号,不是指针的概念 */ function * test() { let c = 0 while (true) { yield c++ // 没有*号,SyntaxError: Unexpected identifier } } let x = test() console.log(x); console.log(x.next()); // yield值 0 console.log(x.next()); // yield值 1 console.log(x.next()); // yield值 2 console.log('============= 1 ============='); function* test1() { let x = 0, y = 7 while (1) { yield x++ if (!y--) { return 100 } } } let xx = test1() console.log(xx.next()); // 0 x=1 console.log(xx.next()); // 当next时,会从上一个yield向下执行,!7不进入, 返回1; x=2 y=6 console.log(xx.next()); // 当next时,会从上一个yield向下执行,!6不进入, 返回2; x=3 y=5 console.log(xx.next()); // 当next时,会从上一个yield向下执行,!5不进入, 返回3; x=4 y=4 console.log(xx.next()); // 当next时,会从上一个yield向下执行,!4不进入, 返回4; x=5 y=3 console.log(xx.next());// 当next时,会从上一个yield向下执行,!3不进入, 返回5; x=6 y=2 console.log(xx.next());// 当next时,会从上一个yield向下执行,!2不进入, 返回6; x=7 y=1 console.log(xx.next());// 当next时,会从上一个yield向下执行,!1不进入, 返回7; x=8 y=0 { value: 7, done: false } console.log(xx.next());// 当next时,会从上一个yield向下执行,!0进入返回100, x=9 y=-1 { value: 100, done: true } return之后,done就true, 后面不进行运算 console.log(xx.next());// 当next时,会从上一个yield向下执行,!-1不进入, 返回-1, x=10 y=-2 { value: undefined, done: true } if (!-1) { console.log('enter'); } else { console.log('no'); } console.log('============= 2 =============');

循环分支语句

分支语句

javascript
/** * 单分支 if (cond1) { } 多分支 if (cond1) { } else if (cond2) { } if (cond1) { } else if (cond2) { } else { } 等价true false 非0数值 字符 [], [1,2] {}, {a:1} 等价false false undefined null NaN switch (variable) { case value1: xxx break case value2: xxx break ... case valueN: xxx break default: xxx //break } 如果不break, 就向下执行 好的习惯,就每一个加break; 实现值 或 5 或 4; 不能写 case 5 || 4 case 5: case 4: xxx break */ let x = 5 // 4 other x = 1 // 1 3 switch (x) { case 0: console.log(0); case 1: console.log(1); case 3: console.log(3); break case 5: case 4: console.log(4); default: console.log('other'); //break }

for循环

遍历索引 i<?, 遍历值of,遍历属性 in

遍历索引,number类型

遍历属性, string类型

javascript
/** * for索引 * * 第1段,第2段:为真先循环,后第3段; * 第2段假,结束循环 */ // 1. 0, 小于5, 执行语句, 打印0 // 2. i++ => i=1, i< 5, 1 // 2 // 3 // 4 // i++ => i= 5, i<5, 不进入循环体 for (let i = 0; i < 5; i++) { console.log(i); } console.log('---'); for (let i = 0; i < 5; i++) { console.log(i++); } console.log('========== 1 偶数 0 2 4 ============='); for (let i = 0; i < 5; i++) { console.log(++i); } console.log('========== 2 奇数 1 3 5 ============='); for (let i = 0; i < 5; i++) { console.log(i + 1); } console.log('========== 3 0-4 -> 1 2 3 4 5 ============='); // 0 1 2 3 4 for (let i = 0; i < 5; i += 1) { console.log(i); } console.log('========= 4'); // 0 2 4 for (let i = 0; i < 5; i += 2) { console.log(i); } console.log('========= 5'); // 第3段,i++或++i 均一样,表达式的值并不会使用,只是执行 for (let i = 0; i < 5; ++i) { console.log(i); } console.log('========= 6'); /** * 数字属性 0 number 1 */ let arr = [1, 3, 6, 7] for (let i = 0; i < arr.length; ++i) { console.log(i,typeof i , arr[i]); } console.log('---------------------------'); /** * for值 */ let y = new Array('one', 'two', `three`, "five") for (let i of y) { console.log(i); } console.log('========== 6 遍历值 ============='); /** * for属性 * 取的是字符串 a string 1 undefined * 内部存的是字符串 * */ let obj = { a: 1, b:'abc' } for (let y in obj) { // 属性,属性类型, 变量y为属性的值, y属性 console.log(y,typeof y,obj[y],obj.y); }

多初始化

javascript
/** * 两个循环变量 */ for (let i = 0, j = 9; i < 10; i++, j--) { console.log(i, j, i*j); } console.log('-----------');

死循环

javascript
/** * 死循环 */ for (; ;) { console.log('hello world'); } while(1) { }

while循环

javascript
/** while (cond) { } cond为真进入循环 * * do { } while (cond) 先循环一次, 条件为真,才继续执行 */ // 10 打印9; 1 打印0, x=0; x--,取0不满足,但是x已减1 ~~~~~~~~~~~~~ let x = 10 while (x--) { console.log(x); } console.log('9 到 0 '); console.log(x,'~~~~~~~~~~~~~'); // x = -1 // 打印-1 // -1< 10 打印0 // 0 打印 1 // 9 打印10 // 10 不打印,但是运算了,x为11 do { console.log(x); } while (x++ < 10) console.log(x,' ~~~~~~~~~~~~~'); console.log('-1 到 10');

完成 9 X 9 乘法表

javascript
for (let i = 1; i < 10; i++) { str = '' for (let j = 1; j <= i; j++) { if (i * j < 10) { str += `${i} * ${j} = ${i*j} ` } else { str += `${i} * ${j} = ${i*j} ` } } console.log(str); }

js进阶

作用域

隐式声明为全局

函数/if块, 局部变量 向内穿透, var/let/const. 向外不可见; 特殊: if块的var也会变全局, 向外可见;

javascript
/** * 函数作用域 * 函数中,if或多级if中, 隐式定义,均为全局变量; * 函数中var/const/let定义均为局部变量; ~~ 向内穿透, 向外不可见 ~~ * if块中,const/let定义为局部变量 ~~ 向内穿透, 向外不可见 ~~; var为全局变量; python中没有块的概念 */ function test() { a = 100; // 隐式变成全局, 不推荐 var b = 200; // var可以在函数中, 不能变全局 let c = 300; } test() console.log(a); // console.log(b); // 不可见 // console.log(c); // 不可见 console.log('----------------'); if (1) { d = 100; // 隐式变成全局, 不推荐 let e = 200; var f = 300; // var可以在if中变全局 const g = 400 console.log(e,f,g); } console.log(d); // console.log(e); // 不可见 console.log(f); // var if可以向外穿透 // console.log(g); // 不可见 console.log('`````````````````````````````'); if (1) { h = 100; let i = 200; var j = 300; const k = 400 console.log(i, j, k); // 200 300 400 { let l = 1; var m = 2; const n = 3; console.log(h,i,j,k,l,m,n,'============'); // 向内穿透 100 200 300 400 1 ============ } } console.log(h); // 100 // console.log(i); // 不可见 console.log(j); // 300 var if可以向外穿透 // console.log(k); // 不可见 // console.log(l); // 不可见 console.log(m); // 2 var 多级if可以向外穿透 // console.log(n); // 不可见

例题

javascript
var j = 'jj' var k = 'kk' function t() { j = 'aa' var k = 'bb' var z = '123' console.log(j); // 因为外面声明了j, 修改外面的j; aa console.log(k); // 外面var, 里面var. 里面就是不可穿透; bb } t() console.log(j); // aa 穿透 console.log(k); // kk 不可穿透 /** * var 声明提升,相当于z未赋值 */ console.log(z); // undefined var z z = 'abc' console.log(z); // abc

严格模式

框架会在每个js文件前添加 "use strict" , 隐式声明报错

javascript
"use strict" x = 500; // ReferenceError: x is not defined

异常处理

抛出

javascript
/** * 抛出异常 * 类java: throw * python: raise */ throw new ReferenceError(123)

抓异常

异常处理比较简单, 所以一般只是记录异常

js是单线程, 抛出异常不管这个单线程就异常了。所以一般需要处理异常。

javascript
/** * 抛出异常 * 类java: throw * python: raise * * 抓异常, try不可以单独使用; try {} catch {} finally {} */ try { throw new ReferenceError(123) } catch (e) { /** 不能区别异常 */ console.log(e); // 异常本身 console.log(typeof e); // typeof 返回字符串 console.log(e.constructor); // 获取构造器,异常实例是类构造出来 的。 说的是类,实际看到是函数,习惯称为类: [Function: ReferenceError] console.log(e.constructor.name); // 异常类名,字符串 ReferenceError console.log(e.message); // 异常消息 123 console.log('+'.repeat(12)); } finally { console.log('-'.repeat(12)); }

不抛异常类型

javascript
try { // throw 'abc' // python才会检查抛出来的异常类型; 所以在javascript中,建议使用 throw new Error的子类, 抛出异常实例。 throw new Error('abc') // 建议 } catch (e) { /** 不能区别异常 */ console.log(e); // 异常本身 console.log(typeof e); // typeof 返回字符串 console.log(e.constructor); // 获取构造器,异常实例是类构造出来 的。 说的是类,实际看到是函数,习惯称为类: [Function: String] console.log(e.constructor.name); // 异常类名,字符串 String console.log(e.message); // 字符串没有异常消息 console.log('+'.repeat(12)); } finally { console.log('-'.repeat(12)); }

JS对象模型

js一种基于原型(Prototype)的面向对象语言, 而不是基于类的面向对象语言。基于原型、原型链来实现对象。

基于原型,构建原型链。

封装、继承、多态均可以实现。

c++, java class和instance概念, 类是一类事物抽象, 实例是类的实体。

js应用于前端,后端 nodejs.

微软的flash,有安全问题。js有沙盒。

定义对象

  1. 箭头函数
  2. 定义对象
javascript
/** * 直接定义 * 写对象名, 名为key, 值为值 * [对象名]:对象名,值为key, 值为值 * 函数没有写function关键字,只有名() {}, 名为key, 函数对象为值 */ const fn = () => { console.log('ABC'); } let x = 100 console.log(typeof fn, typeof x); // function number let obj = { a: 1, b: 'abc', 'c': [], // fn: fn, // 'fn': fn 右边是函数对象; 相当于fn fn, // 等价 fn:fn, 等价 'fn': fn show: () => { console.log('123'); }, x, // x:x 或 'x': x [x]: x, // 取变量值:x, 100:x test() { console.log('7'); } // test: test, 'test': test } console.log(obj); /** { '100': 100, a: 1, b: 'abc', c: [], fn: [Function: fn], show: [Function: show], x: 100, test: [Function: test] } */

自定义类

es6之前没有类, 缺的是构造器。

js
# 类使用方法 类() 就是实例 # 实现相同的过程 js给你函数, 函数() 构建实例即可
ES6之前容易丢new, 传统方式

还有部分人在使用的,常用的语法,与python类似

函数名,首字母大写

this指针,类中,永远指向当前实例。

javascript
/** * ES6之前 * * @param {*} x 参数1 数值 * @param {*} y 参数2 数值 */ function Point(x, y) { this.x = x // 实例属性 this.y = y } let p1 = Point(4, 5) // 函数调用 console.log(p1, typeof p1); // undefined undefined let p2 = new Point(4, 5) // 构造实例 console.log(p2, typeof p2, p2.x); // Point { x: 4, y: 5 } object /** * 写继承 * 没有(像python)直接写哪个是父类,需要手工调用父类 * 借用函数的call方法,把this(Point3D实例)传递给父类。 * @param {*} x * @param {*} y * @param {*} z */ function Point3D(x, y, z) { Point.call(this,x, y) // python中,直接调用父类,就需要把self传递给父类;python是显式传递self;c/c++/java不需要显式传递;这里借用函数的call方法,把this(Point3D实例)传递给父类。 this.z = z } let p3 = new Point3D(7, 8, 9) console.log(p3, p3.constructor); // Point3D { x: 7, y: 8, z: 9 } [Function: Point3D]
  1. function Point(x, y) { 完成封装
  2. function Point3D(x, y, z) { 完成封装
  3. Point.call(this,x, y) 完成继承
  4. 学了this的动态绑定之后,Point.call(this,x, y) 由于这个是函数Point()调用,不是实例调用。所以函数中this是全局对象, Point.call(this,x,y) 就将Point函数中的this修正为传入的this。python中,也一样: Point(self,x,y)
ES6之后,直接写class, class extends
javascript
/** * ES6之后 class * 实例化没有new就报错,改进了 * */ class Point { constructor(x, y) { this.x = x // this指针,类中,永远指向当前实例。 this.y = y } // __init__(x,y) } // 新语法,不加new就会异常 let p1 = new Point(4, 5) console.log(p1); // Point { x: 4, y: 5 } // 使用父类的构造器 class Point3D1 extends Point {} let p3 = new Point3D1(4, 5, 6) // Point3D1 { x: 4, y: 5 } console.log(p3); class Point3D extends Point { constructor(x, y, z) { super(x, y) // python中可以将调用父类__init__在最后一句;而javascript必须先构造,才可以this.z this.z = z } } let p4 = new Point3D(4, 5, 6) // Point3D { x: 4, y: 5, z: 6 } console.log(p4);
  1. class Point { constructor(x, y) { 封装
  2. class Point3D1 extends Point {} 继承,不构造,直接使用父类的构造
  3. class Point3D extends Point { constructor(x, y, z) { super(x,y) 继承

类方法

ES6之前
diff
/** * ES6之前 * * @param {*} x 参数1 数值 * @param {*} y 参数2 数值 */ function Point(x, y) { this.x = x // 实例属性 this.y = y + this.showMe = () => {console.log(this.x, this.y);} } let p1 = Point(4, 5) // 函数调用 console.log(p1, typeof p1); // undefined undefined let p2 = new Point(4, 5) // 构造实例 console.log(p2, typeof p2, p2.x); // Point { x: 4, y: 5 } object +p2.showMe() // 4 5 /** * 写继承 * 没有直接写哪个是父类,需要手工调用父类 * 借用函数的call方法,把this(Point3D实例)传递给父类。 * @param {*} x * @param {*} y * @param {*} z */ function Point3D(x, y, z) { Point.call(this,x, y) // python中,直接调用父类,就需要把self传递给父类;python是显式传递self;c/c++/java不需要显式传递;这里借用函数的call方法,把this(Point3D实例)传递给父类。 this.z = z } let p3 = new Point3D(7, 8, 9) console.log(p3, p3.constructor); // Point3D { x: 7, y: 8, z: 9 } [Function: Point3D] +p3.showMe() // 7 8

问题:子类p3实例只有7,8没有9; 添加新的方法,覆盖即可;

es6之后
继承,完全覆盖
diff
/** * ES6之后 class * 实例化没有new就报错,改进了 * */ class Point { constructor(x, y) { this.x = x // this指针,类中,永远指向当前实例。 this.y = y } // __init__(x,y) + showMe() { + // c/java不用 明着传this + // python需要明着传this + console.log(this.x, this.y); + } } // 新语法,不加new就会异常 let p1 = new Point(4, 5) console.log(p1); // Point { x: 4, y: 5 } +p1.showMe() // 4 5 class Point3D1 extends Point {} let p3 = new Point3D1(4, 5, 6) // Point3D1 { x: 4, y: 5 } console.log(p3); +p3.showMe() // 4 5 class Point3D extends Point { constructor(x, y, z) { super(x, y) // python中可以将调用父类init在最后一句;而javascript必须先构造,才可以this.z this.z = z } + showMe() { + console.log(this.x, this.y, this.z); + } } let p4 = new Point3D(4, 5, 6) // Point3D { x: 4, y: 5, z: 6 } console.log(p4); +p4.showMe() // 4 5 6

新语法,继承后,修改showMe

继承,不完全覆盖
diff
/** * ES6之后 class * 实例化没有new就报错,改进了 * */ class Point { constructor(x, y) { this.x = x // this指针,类中,永远指向当前实例。 this.y = y } // __init__(x,y) showMe() { // c/java不用 明着传this // python需要明着传this console.log(this.x, this.y); } } // 新语法,不加new就会异常 let p1 = new Point(4, 5) console.log(p1); // Point { x: 4, y: 5 } p1.showMe() // 4 5 class Point3D1 extends Point {} let p3 = new Point3D1(4, 5, 6) // Point3D1 { x: 4, y: 5 } console.log(p3); p3.showMe() // 4 5 class Point3D extends Point { constructor(x, y, z) { super(x, y) // python中可以将调用父类init在最后一句;而javascript必须先构造,才可以this.z this.z = z } + showMe() { + super.showMe() // super调用父类方法, 实现了较为复杂的实现。我们只需要下面完成自己的逻辑。 自动解决this问题 + console.log(this.z); + } } let p4 = new Point3D(4, 5, 6) // Point3D { x: 4, y: 5, z: 6 } console.log(p4); +p4.showMe() // 4 5 6

类方法优先级

以上全部定义为方法,子类方法会覆盖父类的方法。

父有方法,子有方法。子方法优先 (规范的方法)
javascript
class Point { showMe() { // c/java不用 明着传this // python需要明着传this console.log(this.x, this.y,'**'); } constructor(x, y) { this.x = x // this指针,类中,永远指向当前实例。 this.y = y // this.showMe = () => {console.log(this.x,'//');} } // __init__(x,y) } // 新语法,不加new就会异常 let p1 = new Point(4, 5) console.log(p1); // Point { x: 4, y: 5 } // p1.showMe() // 4 构建器中优先 class Point3D extends Point { constructor(x, y, z) { super(x, y) // python中可以将调用父类init在最后一句;而javascript必须先构造,才可以this.z this.z = z // this.showMe = () => { // console.log(this.x, this.y, this.z,'++'); // } } showMe() { super.showMe() console.log(this.x, this.y, this.z,'--'); } } let p3 = new Point3D(4, 5, 6) // Point3D { x: 4, y: 5, z: 6 } console.log(p3); p3.showMe() // 4 5 6 ++
只有父类方法+属性,子无属性和方法。父属性优先
class Point { showMe() { // c/java不用 明着传this // python需要明着传this console.log(this.x, this.y,'**'); } constructor(x, y) { this.x = x // this指针,类中,永远指向当前实例。 this.y = y this.showMe = () => {console.log(this.x,'//');} } // __init__(x,y) } // 新语法,不加new就会异常 let p1 = new Point(4, 5) console.log(p1); // Point { x: 4, y: 5 } // p1.showMe() // 4 构建器中优先 class Point3D extends Point { constructor(x, y, z) { super(x, y) // python中可以将调用父类init在最后一句;而javascript必须先构造,才可以this.z this.z = z // this.showMe = () => { // console.log(this.x, this.y, this.z,'++'); // } } // showMe() { // super.showMe() // console.log(this.x, this.y, this.z,'--'); // } } let p3 = new Point3D(4, 5, 6) // Point3D { x: 4, y: 5, z: 6 } console.log(p3); p3.showMe() // 4 //

父类属性优先

只有父类方法+属性,子仅有方法。父属性优先 (特殊)
class Point { showMe() { // c/java不用 明着传this // python需要明着传this console.log(this.x, this.y,'**'); } constructor(x, y) { this.x = x // this指针,类中,永远指向当前实例。 this.y = y this.showMe = () => {console.log(this.x,'//');} } // __init__(x,y) } // 新语法,不加new就会异常 let p1 = new Point(4, 5) console.log(p1); // Point { x: 4, y: 5 } // p1.showMe() // 4 构建器中优先 class Point3D extends Point { constructor(x, y, z) { super(x, y) // python中可以将调用父类init在最后一句;而javascript必须先构造,才可以this.z this.z = z // this.showMe = () => { // console.log(this.x, this.y, this.z,'++'); // } } showMe() { super.showMe() console.log(this.x, this.y, this.z,'--'); } } let p3 = new Point3D(4, 5, 6) // Point3D { x: 4, y: 5, z: 6 } console.log(p3); p3.showMe() // 4 //

父类属性优先

只有父类方法+属性,子类方法+属性。子属性优先
javascript
class Point { showMe() { // c/java不用 明着传this // python需要明着传this console.log(this.x, this.y,'**'); } constructor(x, y) { this.x = x // this指针,类中,永远指向当前实例。 this.y = y this.showMe = () => {console.log(this.x,'//');} } // __init__(x,y) } // 新语法,不加new就会异常 let p1 = new Point(4, 5) console.log(p1); // Point { x: 4, y: 5 } // p1.showMe() // 4 构建器中优先 class Point3D extends Point { constructor(x, y, z) { super(x, y) // python中可以将调用父类init在最后一句;而javascript必须先构造,才可以this.z this.z = z this.showMe = () => { console.log(this.x, this.y, this.z,'++'); } } showMe() { super.showMe() console.log(this.x, this.y, this.z,'--'); } } let p3 = new Point3D(4, 5, 6) // Point3D { x: 4, y: 5, z: 6 } console.log(p3); p3.showMe() // 4 5 6 ++

静态方法

不是python静态方法

javascript
/** * 静态方法 * java, javascript都是如此:static 定义 静态方法和静态属性,均 只有类访问,静态方法或属性中的this是指向类。 * * 实例方法,不加static. 其中this是类构造实例本身。 * * python中,类的属性,类和实例可以访问。 * 静态方法,类和实例可以访问 * 类方法,类和实例可以访问 * 实例方法,需要传递this, 实例可以访问。 */ class Point { // 类的; javascript中,类的属性不是大家的;python是大家的; // 静态的,只能通过类访问 static z = 123 // 实例化 constructor(x, y) { this.x = x this.y = y console.log('~'.repeat(12)); } // 实例的 showMe() { console.log('+'.repeat(12)); // 实例看不到 类的z console.log(this.x, this.y, this.z) } // 类使用,类调用时,this就是类。 static nowZ() { console.log(this.z, '~@#@#'); // 123 ~@#@# } } console.log(Point.z); // 类的静态属性 Point.nowZ() // 类的静态方法 console.log('_++以上类的属性和方法。以下是实例的方法和属性+'); let p1 = new Point(3, 5) console.log(p1, p1.constructor, p1.x); // Point { x: 3, y: 5 } [class Point] p1.showMe() // 3 5 undefined // Point.showMe() // TypeError: Point.showMe is not a function 没有实例,不能this. 类不能访问实例的方法 // p1.showZ() // TypeError: p1.showZ is not a functio 实例不能访问静态的方法;类的方法; console.log(p1.z); // undefined

this的问题

静态方法中的this,指向当前类。

构造器, 实例方法中的this, 指向实例。

动态绑定

this可以动态变化, 实例调用的方法,方法中的this, 是前面的实例。

单函数动态绑定
javascript
/** * 字面定义 实例 * this, globalThis 表示全局对象。 * 换this,动态绑定:实例调用的方法,方法中的this, 是前面的实例。 */ let tom = { name: 'tome', getName: function() { console.log(this === globalThis, this.name); }, } console.log(tom.name); tom.getName() // false tome 表示this是当前实例,不是全局对象。 ******* 实例调用的方法,方法中的this就是实例。实例与方法绑定 动态绑定 // 换this let jerry = { name: 'jerry', } console.log(jerry.name); /** * 修改方法的实例 */ // jerry.getName() // TypeError: jerry.getName is not a function tom.getName.call(jerry) // false jerry console.log('='.repeat(13)) /** * 全局方法 */ const getName = function() { console.log(this === globalThis, this.name); } // 全局函数,this就是全局 getName() // true undefined name = '123' // 隐式定义,直接挂载在global上 getName() // true 123 console.log('>'.repeat(13)) /** * 实例中放全局方法,方法中的this,是实例的this. * ******* 实例调用的方法,方法中的this就是实例。实例与方法绑定 动态绑定 */ let a = { name: 'a', getName, // 等价 'getName': getName } a.getName() // false a let b = { name: 'b', getName } b.getName() // false b
双层函数动态绑定
javascript
/** * 全局方法 */ const getName = function() { console.log(1, this === globalThis, this.name); return function() { console.log(2, this === globalThis, this.name); } } // 全局函数,this就是全局 getName()() // true undefined name = 'mykernel' // 隐式定义,直接挂载在global上 getName()() // true 123 console.log('>'.repeat(13)) /** * 实例中放全局方法,方法中的this,是实例的this. * ******* 实例调用的方法,方法中的this就是实例。实例与方法绑定 动态绑定 */ let a = { name: 'a', getName, // 等价 'getName': getName } a.getName()() // 1 false a , 2 true 123 const inner = a.getName() // 1 false a; 返回一个临时的函数 inner() // 函数调用, 没有实例调用, 第2次的globalThis就是全局函数 console.log('@'.repeat(30)); let b = { name: 'b', getName: function() { console.log(1, this === globalThis, this.name); return function() { console.log(2, this === globalThis, this.name); } }, // 等价 'getName': getName } b.getName()() // 第2次是函数调用,不是实例调用,所以this就是全局的实例
非动态绑定,修改this call, apply
javascript
/** * 解决非动态绑定 */ var getName = function() { console.log(1, this === globalThis, this.name); return function() { console.log(2, this === globalThis, this.name); } } // 全局函数,this就是全局 getName()() // true undefined name = 'mykernel' // 隐式定义,直接挂载在global上 getName()() // true 123 console.log('>'.repeat(13)) /** * 缺什么补什么 * that法 */ getName = function() { console.log(1, this === globalThis, this.name); return function(that) { console.log(2, this === globalThis, that.name); } } let a = { name: 'a', getName, // 等价 'getName': getName } a.getName()(a) // 1 false a , 2 true 123 var inner = a.getName() // 1 false a; 返回一个临时的函数 inner(a) // 函数调用, 没有实例调用, 第2次的globalThis就是全局函数 console.log('@'.repeat(30)); /** * call(this) apply(this) Function类型,由function定义的函数。均有call/apply方法。 * fn() => fn.call(this); fn.call(this,...array) 列表 常用, 方便写。 * fn() => fn.apply(this); fn.apply(this, array) 数组 */ getName = function() { console.log(1, this === globalThis, this.name); return function(x,y) { console.log(2, this === globalThis, this.name,x,y); } } a = { name: 'a', getName, // 等价 'getName': getName } a.getName().call(a,4,3) // fn() => fn.call(this) ,前者this是非动态加载的this, 全局this; fn.call(this) 将可以替换其中的this为送进来的实例 var inner = a.getName() inner.apply(a,new Array(3,3)) console.log('*'.repeat(30)); let b = { name: 'b', getName: function() { console.log(1, this === globalThis, this.name); return function() { console.log(2, this === globalThis, this.name); } }, // 等价 'getName': getName } b.getName()() // 第2次是函数调用,不是实例调用,所以this就是全局的实例
非动态绑定, 修改this, bind

函数bind之后,修改this, 并返回函数

javascript
/** * fn() = 动态绑定this => fn.bind(this)() */ let b = { name: 'b', getName: function() { console.log(1, this === globalThis, this.name); return function(x,y) { console.log(2, this === globalThis, this.name,x,y); } }, // 等价 'getName': getName } b.getName()() // 第2次是函数调用,不是实例调用,所以this就是全局的实例 let x = b.getName().bind(b) console.log(x, typeof x); x(3,4) // 2 false b 3 4
替换方法的this
内外function (外层动态绑定,内层全局this)

nodejs中

javascript
const getName = function() { console.log(1, this === globalThis, this.name); // 1 false a return function(x, y) { console.log(2, this === globalThis, this.name, x, y); } } let a = { name: 'a', getName } let b = { name: 'b', } a.getName()() // 1 false a ; 2 true undefined undefined undefined let inner = a.getName() // 1 false a inner.bind(b)(6, 6) // 2 false b 6 6
外function, 内箭头 (推荐) 外层动态绑定,内层创建时继承当前作用域this

nodejs中,内层函数变箭头函数

箭头函数的this, 是创建函数的一刹那决定的。

内层函数是临时创建的, 环境中的this,利用了当前作用域的this。

javascript
name = 'mykernel.cn' const getName = function () { console.log(1, this === globalThis, this.name); // 1 false a return (x, y) => { console.log(2, this === globalThis, this.name, x, y); } } let a = { name: 'a', getName } let b = { name: 'b', } a.getName()() // 1 false a ; 2 false a undefined undefined // let inner = a.getName() // 1 false a // inner.bind(b)(6, 6) // 2 false b 6 6
外箭头, 内function 浏览器中生效 , this定死,不能动

nodejs中,不能用

javascript
globalThis.name = 'mykernel' const getName = () => { console.log(1, this === globalThis, this.name); return function (x, y) { console.log(2, this === globalThis, this.name, x, y); } } let a = { name: 'a', getName } let b = { name: 'b', } a.getName()() // 1 false undefined; 2 true mykernel undefined undefined

浏览器中

javascript
globalThis.name = 'mykernel' const getName = () => { console.log(1, this === globalThis, this.name); return function (x, y) { console.log(2, this === globalThis, this.name, x, y); } } let a = { name: 'a', getName } let b = { name: 'b', } a.getName()() // 1 false mykernel; 2 true mykernel undefined undefined
内外均箭头,浏览器中生效 , this定死,不能动

nodejs中有问题, 箭头函数在浏览器中使用

javascript
globalThis.name = 'mykernel' const getName = () => { console.log(1, this === globalThis, this.name); return (x, y) => { console.log(2, this === globalThis, this.name, x, y); } } let a = { name: 'a', getName } let b = { name: 'b', } a.getName()() // 1 false undefined; 2 false undefined undefined undefined

浏览器中

javascript
globalThis.name = 'mykernel' const getName = () => { console.log(1, this === globalThis, this.name); return (x, y) => { console.log(2, this === globalThis, this.name, x, y); } } let a = { name: 'a', getName } let b = { name: 'b', } a.getName()() // 1 true "mykernel"; 2 true "mykernel" undefined undefined

替换this, 创建一刹那 this定死了, 改不了。call, apply ,bind均改不了。

原型链

构造器 类.prototype 与 实例.__proto__ 一样

相同类,不同实例。可以通过类.prototype.属性,所有实例共享数据。

不同类,不同实例。可以通过Object.prototype.属性,任何类任何实例共享数据。

javascript
let tom = { name: 'tom' } // new Object tom.__proto__ // [[prototype]] Object.prototype console.dir(tom.__proto__ === Object.prototype) // true class Person { constructor(name) { this.name = name } } let p1 = new Person('ben') console.log(p1.__proto__ === Person.prototype); // true
bash
Person {name: "ben"} # 实例访问属性, name有;没有自动在__proto__下面查找。 name: "ben" __proto__: age: 20 constructor: class Person __proto__: constructor: ƒ Object() hasOwnProperty: ƒ hasOwnProperty() isPrototypeOf: ƒ isPrototypeOf() propertyIsEnumerable: ƒ propertyIsEnumerable() toLocaleString: ƒ toLocaleString() toString: ƒ toString() valueOf: ƒ valueOf() __defineGetter__: ƒ __defineGetter__() __defineSetter__: ƒ __defineSetter__() __lookupGetter__: ƒ __lookupGetter__() __lookupSetter__: ƒ __lookupSetter__() get __proto__: ƒ __proto__() set __proto__: ƒ __proto__()

js高阶

前端:

  1. 传统,模板,整几个网页。
  2. JS框架

解构

展开语法

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax

javascript
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax /** * 列表解构 */ var parts = [1, 2] var lyrics = [0, ...parts, 3, 4, 5] console.log(lyrics); // [ 0, 1, 2, 3, 4, 5 ] console.log([...parts]); // [ 1, 2 ] /** * 参数解构 */ function test(a, b) { return a + b } console.log(test()); // undefined + undefined = NaN function f(x, y, z) { console.log(x + y + z); } f(4, 5, 6, 7) // 15 var args = [2, 3, 4] f(...args) // 9 /** * 数组解构 * * 与python不一样,逗号优先级高; c/java/c++中逗号优先级低于=号,所以赋值先执行。 * * js解构,要求两边写一样 * js解构,...args只能放最后一个 */ let arr = [1, 3, 5] let x, y, z, n = arr // 与python不一样,逗号优先级高; c/java/c++中逗号优先级低于=号,所以赋值先执行。 console.log(x, y, z, n); // undefined undefined undefined [ 1, 3, 5 ] // 写多了 let [a, b, c, d] = arr // let d是悬空的,undefined console.log(a, b, c, d); // 1 3 5 undefined // 写少了 let [e] = arr console.log(e); // 1 解构第1个参数; python中不能这样解构 // 正常解构数组 let [ff, gg, hh] = arr // python也可以这样解构 console.log(ff, gg, hh); // 1 3 5 // 忽略变量 let [, ee, ] = arr console.log(ee); // 3 let [, , eee, ] = arr console.log(eee); // 5 // js默认值, 没有关键字传参 let [aa = 111, bb, cc, dd, ddd = 300] = arr // dd, ddd 悬空,但是ddd有默认值 console.log(aa, bb, cc, dd, ddd); // 1 3 5 undefined 300 // 解构,聚合 let [aaa, ...args2] = arr console.log(aaa, args2); // 1 [3,5] /** * python支持这样解构数组 In [1]: arr = [1,3,5,7] In [2]: x,*args,y = arr In [3]: x Out[3]: 1 In [4]: y Out[4]: 7 In [5]: args Out[5]: [3, 5] */ // js 不支持这样解构数组; // ...args 只能在最后一个参数 // // let [aaaa, ...arg4, b] = arr // SyntaxError: Rest element must be last element // console.log(aaaa,args4,b); console.log('复杂的数组解构'); let arr1 = [1, [2, 3], 4] let [xx, yy, zz, xyz] = arr1 console.log(xx, yy, zz, xyz); // 1 [ 2, 3 ] 4 undefined let [xxx, [yyy, zzz], xyzz] = arr1 console.log(xxx, yyy, zzz, xyzz); // 1 2 3 4 const [ca, cb] = arr1 console.log(ca, cb); // 1 [ 2, 3 ] const [cm, , , , , cn] = arr1 console.log(cm, cn); // 1 undefined const [cx, ...cargs] = arr1 console.log(cx, cargs); //1 [ [ 2, 3 ], 4 ] /** * 对象解构 * * python中没有这样的概念, 传参时,**kwargs */ let o1 = { oa: 1, ob: 2, oc: 3 } console.log(o1); // { a: 1, b: 2, c: 3 } // 获取a,b, c console.log(o1.oa, o1.ob, o1.oc); // 1 2 3 console.log(o1['oa'], o1[`ob`], o1["oc"]); // 1 2 3 // 获取没有的 悬空 console.log(o1.oz, o1['oz']); // undefined // 别名解构 var { oa: ox, ob: oy, oc: oz } = o1 console.log(ox, oy, oz); // 1 2 3 // 不存在key 的解构 var { ox, oy, oz } = o1 console.log(ox, oy, oz); // undefined undefined undefined // 同属性名 的解构 var { oa, ob, oc } = o1 console.log(oa, ob, oc); // 1 2 3 // 更少key var { oa } = o1 console.log(oa); // 1 // 更多key var { oa, ob, oc, oe } = o1 console.log(oa, ob, oc, oe); // 1 2 3 undefined // key顺序乱序, 按名称对应 var { ob, oa, oc, oe } = o1 console.log(oc, ob, oa, oe); // 3 2 1 undefined // key 默认值, 存在不使用默认值。不存在使用默认值。 var { ob = 222, oa, oc, oe = 300 } = o1 console.log(oc, ob, oa, oe); // 3 2 1 300 // 别名解构 默认值 var { oa: ox, ob: oy, oc: oz, ot: ott = 300 } = o1 console.log(ox, oy, oz, ott); // 1 2 3 300 /** * 复杂解构 */ let o2 = { a: 1, 'b': [{ a: 11 }, { a: 111 }], "o2c": 3 } // 不解构,取3个a console.log(o2.a, o2.b[0].a, o2.b[1].a); // 1 11 111 // 利用解构,一次提取出3个a var { a: o2a1, b: [{ a: o2a2 }, { a: o2a3 }], o2c } = o2 console.log(o2a1, o2a2, o2a3, o2c); // 1 11 111 3

对象操作

javascript
/** * 对象的操作 * 类似Python方法 * * * keys是标准方法; values/entries是实验性方法; * Objects.keys => python: d.keys * Object.values => python: d.values * Object.entries => python: d.items * * Object.assign */ let obj = { a: 1, b: 2, c: 3 } // 取属性, for in, in取属性 ; for of 元素; for (let i in obj) { console.log(i, obj[i]); // a 1; b 2; c 3 } // Object.keys 取对象属性名数组 console.log(Object.keys(obj)); // [ 'a', 'b', 'c' ] console.log(Object.values(obj)); // [ 1, 2, 3 ] console.log(Object.entries(obj)); // [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ] // Object.assign // 把obj对象弄到o2, o2的对象返回出来 let o2 = {} let o1 = Object.assign(o2, obj) console.log(obj); // { a: 1, b: 2, c: 3 } console.log(o1); // { a: 1, b: 2, c: 3 } console.log(o1); // { a: 1, b: 2, c: 3 } console.log(obj == o1); // false; 自定义对象比较,就是内存地址比较 console.log(obj === o1); // false console.log(o1 == o2); // true /** * 配置 * 越在后面,配置会覆盖 */ let obj1 = { port: 8000, } let o3 = { port: 9901 } let o4 = Object.assign(o3, obj1, { port: 9000, domain: 'www.magedu.com' }) console.log(o4); // { port: 9000, domain: 'www.magedu.com' }

数组操作

5.2.4 字符串操作,通用

javascript
/** * 数组操作 * push => python: append+extend * pop * slice 切片 查询 * splice 切片 查询并删除, 删除后索引不在了; delete删除后索引还在,值不在。 * splice(start,stop) 删除 [start, stop] 索引均包含 * splice(start,stop,'replace') 删除, 插入1个到索引start * splice(1,0,'replace') 不删除, 插入到索引1 * splice(start,stop,'replace1', 'replace2') 删除, 插入多个到索引start * * 数组迭代 * for 数字索引 * for in 字符属性 * for of 元素 * * map 拿出每个元素, 修改, 直接返回新的数组 => python: map 拿出每个元素, 修改, 生成惰性迭代器 * filter 拿出元素,过滤, 直接返回新的数组 => python: filter 拿出元素,过滤, 生成惰性迭代器 * foreach 遍历数据索引和值 */ let arr = [1, 3, 5, 8] console.log(5 in arr); // false // push console.log(arr.push(9, 11)); // ...items 返回当前长度 console.log(arr); // [ 1, 3, 5, 8, 9, 11 ] // pop console.log(arr.pop()); // 11 从结束弹出来一个数据 console.log(arr); // [ 1, 3, 5, 8, 9 ] // slice 切片 查询 // splice 切片 查询并删除, console.log(arr.slice(0, 2), '-=', arr); // [ 1, 3 ] -= [ 1, 3, 5, 8, 9 ] console.log(arr.splice(0, 2), '-=', arr); // [ 1, 3 ] -= [ 5, 8, 9 ] /** * delete删除索引还在,值不在。而splice删除,索引也动了。 0 5 1 8 2 9 */ for (let i in arr) { console.log(i, arr[i]); } // 取删除,替换 console.log(arr); // [ 5, 8, 9 ] console.log(arr.splice(0, 2, 'a')); // [ 5, 8 ] console.log(arr); // [ 'a', 9 ] // 插入 arr.push(1, 2, 3, 4) console.log(arr); // [ 'a', 9, 1, 2, 3, 4 ] console.log(arr.splice(1, 0)); // [] console.log(arr); // [ 'a', 9, 1, 2, 3, 4 ] console.log(arr.splice(1, 0, 'x')); // [] console.log(arr); // [ 'a', 'x', 9, 1, 2, 3, 4] // 删除items, 插入元素 console.log(arr.splice(1, 2, 'm', 'n', 'o')); // [ 'x', 9 ] console.log(arr); // [ 'a', 'm', 'n', 'o', 1, 2, 3, 4 ] /** * 数组迭代 [ 'a', 'm', 'n', 'o', 1, 2, 3, 4 ] */ console.log(arr); // for 数字索引 for (let x = 0; x < arr.length; ++x) { console.log(x, typeof x, arr[x]); } // for 字符属性 for (let x in arr) { console.log(x, typeof x, arr[x]); } // for item for (let x of arr) { console.log(x); } // map 返回值为新列表的元素 let arr1 = [1, 3, 4] console.log(arr1.map(x => x + 'abc')); // [ '1abc', '3abc', '4abc' ] //虽然map支持2个参数,但是js 可以只给1个元素。 console.log(arr1.map((item, index) => item + index), '^'.repeat(12)); // [ 1, 4, 6 ] // filter 返回值为true保留 console.log(arr1.filter(x => x - 3)); // [ 1, 4 ] // foreach 无返回值, 原数据不变 const newArr = [] // 常量,内存地址不变 arr1.forEach((item, index) => { console.log(item, index, '------------'); newArr.push(item + index) }) console.log(arr1); //[ 1, 3, 4 ] console.log(newArr); // [ 1, 4, 6 ] console.log('~'.repeat(50)); let a1 = [] console.log(a1); a1[5] = 20 a1[8] = 10 console.log(a1, a1.length); // [ <5 empty items>, 20, <2 empty items>, 10 ] 9 let arr2 = [2, 4, 5] const newArr1 = [] // 常量,内存地址不变 arr2.forEach((item, index) => { newArr1[index] = item + index }) console.log(arr2); // [ 2, 4, 5 ] console.log(newArr1); // [ 2, 5, 7 ]

数组练习

数组 const arr = [1,2,3,4,5] 算出元素平方值, 输出平方值是偶数且大于10的值

需求

javascript
const arr = [1, 2, 3, 4, 5] console.log(arr.map(item => item ** 2).filter(item => item > 10 && item%2 === 0));

这样写不合适

map(item => item ** 2) 遍历,再计算。

先大量计算前,过滤不合格

filter提前

javascript
const arr = [1, 2, 3, 4, 5] console.log(arr.filter(x => ! (x%2)).map(x=>x**2).filter(x => x > 10) );

filter之前

sqrt

x ** 0.5

javascript
const arr = [1, 2, 3, 4, 5] console.log(arr.filter(x => ! (x%2)).filter(x => x > Math.sqrt(10)).map(x=>x**2) );

filter聚合

javascript
const arr = [1, 2, 3, 4, 5] const point = 10 console.log(arr.filter(x => ! (x%2) && x > Math.sqrt(point)).map(x=>x**2) );

%比位慢 %2, x&1 奇数

javascript
const arr = [1, 2, 3, 4, 5] const point = 10 console.log(arr.filter(x => ! (x&1) && x > Math.sqrt(point)).map(x=>x**2) );

短路, 比较大小,比&快

javascript
const arr = [1, 2, 3, 4, 5] const point = 10 console.log(arr.filter(x => x > Math.sqrt(point) && ! (x&1)).map(x=>x**2) );

再高一点,2次循环,改单循环

javascript
const arr = [1, 2, 3, 4, 5] const point = 10 const target = [] arr.forEach( item => { if (item > Math.sqrt(point) && !(item & 1)) { target.push(item**2) } } ) console.log(target);

模块化

代码多了,写一起不行。

ES6之前,没有模块化。

html引入 js

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标签 JS引擎, 解析为js脚本 --> <script> console.log('abc'); let obj = { abc: 1000000 } </script> <!-- 引入 外部脚本,将自动追加到Html之下 --> <script src="./32.js"></script> <!-- <script> console.log('xyz~~~~~~~~~~'); console.log(obj.abc); </script> --> </body> </html>

分离html, js

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标签 JS引擎, 解析为js脚本 --> <!-- 引入 外部脚本,将自动追加到Html之下 --> <script src="./32.js"></script> <!-- <script> console.log('xyz~~~~~~~~~~'); console.log(obj.abc); </script> --> </body> </html>

32.js

javascript
console.log('abc'); let obj = { abc: 1000000 } console.log('xyz~~~~~~~~~~'); console.log(obj.abc);

这样html, js编写人员就可以分工

多个js使用相同变量

<!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标签 JS引擎, 解析为js脚本 --> <!-- 引入 外部脚本,将自动追加到Html之下 --> <script src="./32.js"></script> <script src="./33.js"></script> </body> </html>

32.js

obj = { abc: 1000000 } console.log(obj.abc);

33.js

console.log(obj); obj = 'aaaaa' console.log(obj);

全局变量污染冲突

js模块化

2009年js开发, 2015年es6之后,js标准推出包含了模块化。区别于CommonJS(nodejs使用CommonJS).

我们使用es6之后的标准模块化方法。

自动严格模式

import语句,导入另一个模块导出的绑定

visual code中

33.js

/** * ES6定义 * 导出模块A */ class A { constructor(x) { this.x = x } showX() { console.log(this.x); } } const a = new A(3) console.log(a); // A { x: 3 } a.showX() // 3

32.js

import A from './33.js' /** * F8 使用node-exec插件,调用nodejs执行 * * SyntaxError: Cannot use import statement outside a module * 不支持导入,nodejs内部使用的CommonJS方法导入,导出;需要最新的ES6语法; * * 需要把当前源码转换为老的语法 */ console.log(A);

现在我们使用最新的代码, 但是nodejs, 浏览器中不认,需要源代码转换成旧语法,从而适用于更多的浏览器。

语法转换工具环境搭建 (新语法太新了,浏览器,nodejs不支持)

tanspiler转译工具,新语法 ES6+转换为旧语法, 可以在nodejs, 浏览器上运行。流行的是babel

http://babeljs.io 点开try it out

语法转换

在旧语法转换界面 https://old.babeljs.io/repl/#?babili=false&browsers=&build=&builtIns=false&code_lz=MYGwhgzhAEAKD2BLAdgF2gbwFDQJDHmQlQCcBXYVeEgCgA8BKTHaV3VAC0QgDo7oAvNDotWrTtx4QO8AO4BZAKaDoNJgIB8maASLwQiniHgBzGhN78A1NADMTAL6joTh0A&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&lineWrap=true&presets=es2015%2Creact%2Cstage-2&prettier=false&targets=&version=6.26.0&envVersion=

image-20220502124151641

填补空白

新功能 Promise , 老的里面补充上, 需要额外增加, polyfill 或 corejs

使用babel

https://babeljs.io/docs/en/usage

初始化项目
shell
$ node --version v16.13.0 install -dv devops/src cd devops/ #初始化 $ npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help init` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (devops) version: (1.0.0) description: devops mykernel.cn entry point: (index.js) test command: test.js git repository: git@github.com/slcnx/devops.git keywords: devops mykernel blog author: slcnx license: (ISC) MIT About to write to D:\文档\devops\devops\package.json: { "devDependencies": { "@babel/cli": "^7.17.10", "@babel/core": "^7.17.10", "@babel/preset-env": "^7.17.10" }, "name": "devops", "version": "1.0.0", "description": "devops mykernel.cn", "main": "index.js", # 入口包 "scripts": { "test": "test.js" }, "repository": { "type": "git", "url": "git+ssh://git@github.com/slcnx/devops.git" }, "keywords": [ "devops", "mykernel", "blog" ], "author": "slcnx", "license": "MIT", "bugs": { "url": "https://github.com/slcnx/devops/issues" }, "homepage": "https://github.com/slcnx/devops#readme" } Is this OK? (yes) yes

入口包 index.js

测试文件 test.js

配置镜像源

在项目根目录 .npmrc

bash
registry=https://registry.npm.taobao.org
安装babel
shell
npm install --save-dev @babel/core @babel/cli @babel/preset-env $ ls -l total 213 drwxr-xr-x 1 21923 197609 0 5月 2 12:49 node_modules/ -rw-r--r-- 1 21923 197609 128 5月 2 12:49 package.json -rw-r--r-- 1 21923 197609 187063 5月 2 12:49 package-lock.json drwxr-xr-x 1 21923 197609 0 5月 2 12:48 src/ $ du -sh * 18M node_modules 4.0K package.json 184K package-lock.json 0 src

--save-dev babel编译js时使用,将新语法转义为老语法,和填坑。编译后生成js文件,可以部署, 这个时候babel就可以不要了。

npm help install

--save 编译后,js中带这些包

babel配置

在项目根目录,准备文件 babel.config.json

json
{ "presets": [ [ "@babel/preset-env", { "targets": { "edge": "17", "firefox": "60", "chrome": "67", "safari": "11.1" }, "useBuiltIns": "entry", // "useBuiltIns": "usage", "corejs": "3.6.5" } ] ] }

详情说明 https://babeljs.io/docs/en/babel-preset-env

usage 使用什么css/依赖的函数/类,就打包什么;

js有版本问题,打包时(webpack包完成)利用babel转换语法,进行折行压缩js, 生成一个js文件。

转换代码
shell
./node_modules/.bin/babel src --out-dir lib 或 npx babel src --out-dir lib # npx 相当于 npm execute, 即执行$(npm bin)目录下的文件
bash
$ ls -l total 214 -rw-r--r-- 1 21923 197609 272 5月 2 12:58 babel.config.json drwxr-xr-x 1 21923 197609 0 5月 2 13:08 lib/ # 编译后的脚本 drwxr-xr-x 1 21923 197609 0 5月 2 13:03 node_modules/ -rw-r--r-- 1 21923 197609 598 5月 2 13:03 package.json -rw-r--r-- 1 21923 197609 187159 5月 2 13:03 package-lock.json drwxr-xr-x 1 21923 197609 0 5月 2 12:48 src/ # 编译源脚本

执行$(npm bin)目录下的文件,另一种方法 编辑 package.json

json
"scripts": { "test": "test.js", "builder": "babel src --out-dir lib" },

调用

shell
$ npm run builder > devops@1.0.0 builder # 名@版本 命令名 > babel src --out-dir lib # 命令值 Successfully compiled 2 files with Babel (1265ms).

js模块化转换

在src/目录下放模块化语

src/33.js

shell
/** * ES6定义 * 导出模块A */ class A { constructor(x) { this.x = x } showX() { console.log(this.x); } } const a = new A(3) console.log(a); // A { x: 3 } a.showX() // 3

src/32.js

shell
import A from './33.js' /** * F8 使用node-exec插件,调用nodejs执行 * * SyntaxError: Cannot use import statement outside a module * 不支持导入,nodejs内部使用的CommonJS方法导入,导出;需要最新的ES6语法; * * 需要把当前源码转换为老的语法 */ console.log(A);
shell
$ npx babel src --out-dir lib Successfully compiled 2 files with Babel (1122ms). # 现在可以导入了 $ node lib/32.js A { x: 3 } 3 {} # 不对

使用官方的语法导出

src/33.js

diff
/** * ES6定义 * 导出模块A */ +export class A { constructor(x) { this.x = x } showX() { console.log(this.x); } } const a = new A(3) console.log(a); // A { x: 3 } a.showX() // 3
shell
$ npx babel src --out-dir lib Successfully compiled 2 files with Babel (1128ms). 21923@slc-pc-home MINGW64 /d/文档/devops/devops $ node lib/32.js A { x: 3 } 3 undefined # 现在导出是对缺省语法

src/33.js

diff
/** * ES6定义 * 导出模块A */ +export default class A { constructor(x) { this.x = x } showX() { console.log(this.x); } } const a = new A(3) console.log(a); // A { x: 3 } a.showX() // 3
shell
$ npx babel src --out-dir lib Successfully compiled 2 files with Babel (1148ms). 21923@slc-pc-home MINGW64 /d/文档/devops/devops $ node lib/32.js A { x: 3 } 3 [class A] # 现在拿到 A类了 $ node src/32.js (node:18172) Warning: To load an ES module, set "type": "module" in the package. json or use the .mjs extension. (Use `node --trace-warnings ...` to show where the warning was created) D:\文档\devops\devops\src\32.js:1 import A from './33.js' ^^^^^^

nodejs,只能执行转换后的js, 对ES6语法导入导出不支持。

导出

缺省只能有一个, 导入 import A

非缺省可以多个, 导入 import {b}

缺省导出 export default -> import A; 1个js文件中只能有一个

src/33.js

/** * ES6定义 * 导出模块A */ export default class A { constructor(x) { this.x = x } showX() { console.log(this.x); } } const a = new A(3) console.log(a); // A { x: 3 } a.showX() // 3

src/32.js

import A from './33.js' /** * F8 使用node-exec插件,调用nodejs执行 * * SyntaxError: Cannot use import statement outside a module * 不支持导入,nodejs内部使用的CommonJS方法导入,导出;需要最新的ES6语法; * * 需要把当前源码转换为老的语法 */ console.log(A);
$ npx babel src --out-dir lib && node lib/32.js Successfully compiled 2 files with Babel (1201ms). A { x: 3 } 3 [class A]
非缺省 (命名)导出 export -> import {b}; 1个js文件中可以有多个
导出一个

src/33.js

/** * ES6定义 * 导出模块A */ export default class A { constructor(x) { this.x = x } showX() { console.log(this.x); } } const a = new A(3) console.log(a); // A { x: 3 } a.showX() // 3 export const b = 100;

src/32.js

import A, { b } from './33.js' /** * F8 使用node-exec插件,调用nodejs执行 * * SyntaxError: Cannot use import statement outside a module * 不支持导入,nodejs内部使用的CommonJS方法导入,导出;需要最新的ES6语法; * * 需要把当前源码转换为老的语法 */ console.log(A); console.log(b, '~'.repeat(12));
$ npx babel src --out-dir lib && node lib/32.js Successfully compiled 2 files with Babel (1374ms). A { x: 3 } 3 [class A] 100 ~~~~~~~~~~~~
导出多个

src/33.js

javascript
/** * ES6定义 * 导出模块A */ export default class A { constructor(x) { this.x = x } showX() { console.log(this.x); } } const a = new A(3) console.log(a); // A { x: 3 } a.showX() // 3 const b = 100; let c = 300 var d = 200 export { b, d } export function test(a, b) { return a + b }

src/32.js

javascript
import A, { b, d, c, test } from './33.js' /** * F8 使用node-exec插件,调用nodejs执行 * * SyntaxError: Cannot use import statement outside a module * 不支持导入,nodejs内部使用的CommonJS方法导入,导出;需要最新的ES6语法; * * 需要把当前源码转换为老的语法 */ console.log(A); console.log(b, d, '~'.repeat(12)); console.log(c); // 未导出 console.log(test(100, 300));
shell
$ npx babel src --out-dir lib && node lib/32.js Successfully compiled 2 files with Babel (1350ms). A { x: 3 } 3 [class A] 100 200 ~~~~~~~~~~~~ undefined 400
as语法。修改变量

32.js

import A, { b, d as D, c } from './33.js' /** * F8 使用node-exec插件,调用nodejs执行 * * SyntaxError: Cannot use import statement outside a module * 不支持导入,nodejs内部使用的CommonJS方法导入,导出;需要最新的ES6语法; * * 需要把当前源码转换为老的语法 */ console.log(A); console.log(b, D, '~'.repeat(12)); console.log(c); // 未导出
缺省导入,任意名即可。推荐导入同名

32.js

javascript
import Clz, { b, d as D, c } from './33.js' /** * F8 使用node-exec插件,调用nodejs执行 * * SyntaxError: Cannot use import statement outside a module * 不支持导入,nodejs内部使用的CommonJS方法导入,导出;需要最新的ES6语法; * * 需要把当前源码转换为老的语法 */ console.log(Clz); console.log(new Clz(158).x); console.log(b, D, '~'.repeat(12)); console.log(c); // 未导出

缺省导入,任意名即可

shell
$ npx babel src --out-dir lib && node lib/32.js Successfully compiled 2 files with Babel (1232ms). A { x: 3 } 3 [class A] 158 100 200 ~~~~~~~~~~~~ undefined

导入

javascript
/** * 方式一 * * from可以写文件名,可以忽略js后缀 */ // import A, { b, d, c, test } from './33.js' // import A, { b, d, c, test } from '33' /** * 方式二 * 可以将自定义导入和缺省导入分开导入 */ import { b, d, c, test } from './33' import A from './33' /** * 方式三 * 可以将所有合并为一个变量 */ import * as newModule from './33' console.log(newModule, '~'.repeat(33)); // { b: 100, d: 200, default: [class A], test: [Function: test] } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ console.log(newModule.test(1, 3)); // 4 /** * F8 使用node-exec插件,调用nodejs执行 * * SyntaxError: Cannot use import statement outside a module * 不支持导入,nodejs内部使用的CommonJS方法导入,导出;需要最新的ES6语法; * * 需要把当前源码转换为老的语法 */ console.log(A); console.log(b, d, '~'.repeat(12)); console.log(c); // 未导出 console.log(test(100, 300));

Promise

ES6开始支持

js解释器是单线程t1执行的,网络请求会卡住。应该使用异步, 安排回调,做完自动做回调函数。

异步,就把这个函数放在另一个线程t2,处理完成之后,把数据放队列 。

t1会一直看着这个队列, 队列有数据了,就处理队列。

image-20220502153350829

node直接支持,不需要转义

基础使用

javascript
/** * Promise 完成异步的事, 答应你干的事,会自动开新线程; 主线程继续工作; * Promise有三种状态 * 1)pending 还未处理完,即正在处理。 * 2)成功没有显示状态,fullfilled * setTimeout 过几s才执行 setInterval 每几s执行 */ let p1 = new Promise( // executor /** * 谁先执行谁有用 * @param {*} resolve 解决 * @param {*} reject 未解决 */ (resolve, reject) => { // 答应你干的事 setTimeout(() => { // 换成功和失败的顺序 /** * * reject('failed') // rejected 在上 结果: Promise { <pending> } Promise { <pending> } +++++++++++++++++++++++++++++++++ failed +++++++++++++++++++++++++++++++++ failed >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Promise { <rejected> 'failed' } * resolve({ a: 1, b: 2 }) // fulfilled 完成了; 里面是成功的结果 reject('failed') // rejected 结果: Promise { <pending> } Promise { <pending> } +++++++++++++++++++++++++++++++++ { a: 1, b: 2 } ################################# Promise { { a: 1, b: 2 } } Promise { { a: 1, b: 2 } } * */ resolve({ a: 1, b: 2 }) // fulfilled 完成了; 里面是成功的结果 reject('failed') // rejected console.log('+'.repeat(33)); }, 3000) } ) /** * Promise().then() p1返回处理,2个参数必须是单参函数。处理成功和失败; 返回1个新的promise对象; * Promise().catch() 1个单参函数, 只能处理异常; 返回1个新的promise对象; * p2.then().catch().then() promise链,可以逐级处理 */ // let p2 = p1.then() // let p3 = p1.catch() let p2 = p1.then( value => { console.log(value, '#'.repeat(33)); }, // Promise 中先 调用了resolve; 成功调用 reason => { console.log(reason, '+'.repeat(33)); } // Promise 中先 调用了reject; 失败回调 ) let p3 = p1.catch(reason => { console.log(reason, '>'.repeat(33)); }) /** * 看线程是否做完, 可以循环看线程的状态 * 每2s调用函数 * F9 可以取消node执行 * Promise { <pending> } Promise { <pending> } Promise { 'ok' } Promise { 'ok' } Promise { 'ok' } */ setInterval(() => { console.log(p1); }, 1000)

promise实例和then()之后的实例 链,了解即可

then不给参数,穿透,效果和p1一样,成功就是Promise { '123' }, 失败就Promise { <rejected> 'failed' }
javascript
/** * Promise 完成异步的事, 答应你干的事,会自动开新线程; 主线程继续工作; * Promise有三种状态 * 1)pending 还未处理完,即正在处理。 * 2)成功没有显示状态,fullfilled * setTimeout 过几s才执行 setInterval 每几s执行 */ let p1 = new Promise( // executor /** * 谁先执行谁有用 * @param {*} resolve 解决 * @param {*} reject 未解决 */ (resolve, reject) => { // 答应你干的事 setTimeout(() => { reject('failed') // rejected resolve({ a: 1, b: 2 }) // fulfilled 完成了; 里面是成功的结果 console.log('+'.repeat(33)); }, 3000) } ) /** * Promise().then() p1返回处理,2个参数必须是单参函数。处理成功和失败; 返回1个新的promise对象; * Promise().catch() 1个单参函数, 只能处理异常; 返回1个新的promise对象; * p2.then().catch().then() promise链,可以逐级处理 */ let p2 = p1.then() // 不给实参,相当于两个形参,是2个undefined let p3 = p1.catch() /** * 看线程是否做完, 可以循环看线程的状态 * 每2s调用函数 * F9 可以取消node执行 * */ setInterval(() => { console.log(p1, p2); console.log(p1==p2, p1===p2); }, 1000)
then()只给成功回调,then()实例成功状态就是成功回调返回值。
javascript
/** * Promise 完成异步的事, 答应你干的事,会自动开新线程; 主线程继续工作; * Promise有三种状态 * 1)pending 还未处理完,即正在处理。 * 2)成功没有显示状态,fullfilled * setTimeout 过几s才执行 setInterval 每几s执行 */ let p1 = new Promise( // executor /** * 谁先执行谁有用 * @param {*} resolve 解决 * @param {*} reject 未解决 */ (resolve, reject) => { // 答应你干的事 setTimeout(() => { resolve({ a: 1, b: 2 }) // fulfilled 完成了; 里面是成功的结果 reject('failed') // rejected console.log('+'.repeat(33)); }, 3000) } ) /** * Promise().then() p1返回处理,2个参数必须是单参函数。处理成功和失败; 返回1个新的promise对象; * Promise().catch() 1个单参函数, 只能处理异常; 返回1个新的promise对象; * p2.then().catch().then() promise链,可以逐级处理 */ /** * p2 就是undefined了 +++++++++++++++++++++++++++++++++ { a: 1, b: 2 } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Promise { { a: 1, b: 2 } } Promise { undefined } false false Promise { { a: 1, b: 2 } } Promise { undefined } ... */ let p2 = p1.then( value => { console.log(value, '~'.repeat(33)) // return value // 返回值就是p2实例的成功原因 } ) // 不给实参,相当于两个形参,是2个undefined let p3 = p1.catch() /** * 看线程是否做完, 可以循环看线程的状态 * 每2s调用函数 * F9 可以取消node执行 * */ setInterval(() => { console.log(p1, p2); console.log(p1==p2, p1===p2); }, 1000)
then() 只给失败回调,没有成功,默认返回成功
/** * Promise 完成异步的事, 答应你干的事,会自动开新线程; 主线程继续工作; * Promise有三种状态 * 1)pending 还未处理完,即正在处理。 * 2)成功没有显示状态,fullfilled * setTimeout 过几s才执行 setInterval 每几s执行 */ let p1 = new Promise( // executor /** * 谁先执行谁有用 * @param {*} resolve 解决 * @param {*} reject 未解决 */ (resolve, reject) => { // 答应你干的事 setTimeout(() => { reject('failed') // rejected resolve({ a: 1, b: 2 }) // fulfilled 完成了; 里面是成功的结果 console.log('+'.repeat(33)); }, 3000) } ) /** * Promise().then() p1返回处理,2个参数必须是单参函数。处理成功和失败; 返回1个新的promise对象; * Promise().catch() 1个单参函数, 只能处理异常; 返回1个新的promise对象; * p2.then().catch().then() promise链,可以逐级处理 */ /** * p2 就是undefined了 Promise { <pending> } Promise { <pending> } false false Promise { <pending> } Promise { <pending> } false false +++++++++++++++++++++++++++++++++ failed +++++++++++++++++++++++++++++++++ failed > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > Promise { <rejected> 'failed' } Promise { undefined } false false Promise { <rejected> 'failed' } Promise { undefined } false false */ let p2 = p1.then(undefined,reason => { console.log(reason, '+'.repeat(33)); return reason } ) // 不给实参,相当于两个形参,是2个undefined let p3 = p1.catch(reason => { console.log(reason, '> '.repeat(33)); return '123' }) /** * 看线程是否做完, 可以循环看线程的状态 * 每2s调用函数 * F9 可以取消node执行 * */ setInterval(() => { console.log(p1, p2); }, 1000)

示例

由于promise,调用后then/catch均返回promise.

如果成功,所有then -> value 语句均会执行。

如果失败,走then -> reason语句 或 catch语句,默认转成功,一旦显式定义Promise.reject才继续走失败。

/** * Promise 完成异步的事, 答应你干的事,会自动开新线程; 主线程继续工作; * Promise有三种状态 * 1)pending 还未处理完,即正在处理。 * 2)成功没有显示状态,fullfilled * setTimeout 过几s才执行 setInterval 每几s执行 */ let p1 = new Promise( // executor /** * 谁先执行谁有用 * @param {*} resolve 解决 * @param {*} reject 未解决 */ (resolve, reject) => { // 答应你干的事 setTimeout(() => { reject('failed') // rejected resolve({ a: 1, b: 2 }) // fulfilled 完成了; 里面是成功的结果 console.log('++++++++++++++ Promise+++++++++++++++++++'); }, 3000) } ) /** * Promise().then() p1返回处理,2个参数必须是单参函数。处理成功和失败; 返回1个新的promise对象; * Promise().catch() 1个单参函数, 只能处理异常; 返回1个新的promise对象; * p2.then().catch().then() promise链,可以逐级处理 */ // p1成功, then成功, p2显示then的成功的结果;undefined // p1成功, let p2 = p1.then(value => { console.log('++++++++++++++ p1 then +++++++++++++++++++'); return value },reason => { console.log('++++++++++++++ p1 reason +++++++++++++++++++'); return Promise.reject(reason) } ) // 不给实参,相当于两个形参,是2个undefined p2.then(value => { console.log('++++++++++++++ p2 then +++++++++++++++++++'); return value },reason => { console.log('++++++++++++++ p2 reason +++++++++++++++++++'); return Promise.reject(reason) } ) // 不给实参,相当于两个形参,是2个undefined let p3 = p1.catch(reason => { console.log('++++++++++++++ p3 catch +++++++++++++++++++'); return '123' }) p3.then(value => { console.log('++++++++++++++ p3 then +++++++++++++++++++'); // return value },reason => { console.log('++++++++++++++ p3 reason +++++++++++++++++++'); return Promise.reject(reason) } ) let p4 = p2.catch(reason => { console.log('++++++++++++++ p4 catch +++++++++++++++++++'); return '123' }) p4.then(value => { console.log('++++++++++++++ p4 then +++++++++++++++++++'); // return value },reason => { console.log('++++++++++++++ p4 reason +++++++++++++++++++'); return Promise.reject(reason) } ) /** * 看线程是否做完, 可以循环看线程的状态 * 每2s调用函数 * F9 可以取消node执行 * */ setInterval(() => { console.log(p1,p2,p3,p4); }, 1000)

Promise async函数取成功值 必会

javascript
/** * Promise 完成异步的事, 答应你干的事,会自动开新线程; 主线程继续工作; * Promise有三种状态 * 1)pending 还未处理完,即正在处理。 * 2)成功没有显示状态,fullfilled * setTimeout 过几s才执行 setInterval 每几s执行 */ let p1 = new Promise( // executor /** * 谁先执行谁有用 * @param {*} resolve 解决 * @param {*} reject 未解决 */ (resolve, reject) => { // 答应你干的事 setTimeout(() => { resolve({ a: 1, b: 2 }) // fulfilled 完成了; 里面是成功的结果 reject('failed') // rejected console.log('++++++++++++++ Promise+++++++++++++++++++'); }, 3000) } ) /** * Promise().then() p1返回处理,2个参数必须是单参函数。处理成功和失败; 返回1个新的promise对象; * Promise().catch() 1个单参函数, 只能处理异常; 返回1个新的promise对象; * p2.then().catch().then() promise链,可以逐级处理 */ // Promise 对象是awaitable对象 async function test() { // let ret = p1.then(value = console.log(value);) let value = await p1 // await从then->value函数中获取value,返回。await暂停函数执行 console.log(value); } console.log('test start '); test() console.log('test stop'); console.log('~~~~~~~~~~~~~');

本文作者:mykernel

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!