目录
3、用动object.defineProperty()对象态添加 get,set
一、js代码位置
-
放在script标签之间
<script> // js 代码 </script>
-
引入js脚本
<script src="js脚本路径"></script>
-
注意,到了框架之后,引入方式会有不同
-
二、变量与数据类型
1、声明变量
-
let
⭐let 变量名 = 值;
-
let 声明的变量可以被多次赋值
let a = 100; // 初始值是100 a = 200; // ok,被重新赋值为200
-
-
const
⭐const 常量 = 值;
-
const 修饰的叫常量,只能赋值一次
const b = 300; //初始值是300 b = 400; //error,不能再赋值
-
const 并不意味着它引用的内容不可修改,例如
const c = [1,2,3]; c[2] = 4; //ok,数组内容被修改成[1,2,4] c = [5,6]; // error.不能再次赋值
-
-
var
var声明的变量可以被多次赋值,例如
let a = 100; // 初始值是100 a = 200; // ok,被重新赋值为200
2、基本类型(7种基本类型)
1、undefined和null
-
执行表达式或函数,没有返回结果,出现undefined
-
访问数组不存在的元素,访问对象不存在的属性,出现undefined
-
定义变量,没有初始化,出现undefined
二者共同点
-
都没有属性、方法
-
Nullish
(undefined和null共同的称呼)
二者区别
-
undefined 由 js 产生
-
null 有程序员提供
-
2、String ⭐
html 代码如下,用java和js种的字符串如何表示?
<a href="1.html">超链接</a>
java
String s1 = "<a href=\"1.html\">超链接</a>"; String s2 = """<a href="1.html">超链接</a> """;
js
let s1 = '<a href="1.html">超链接</a>'; let s2 = `<a href="1.html">超链接</a>`;
-
模板字符串(Template strings)
需求:拼接URI的请求参数,如
/test?name=zhang&age=18 /test?name=li&age=20
传统方法拼接:可读性低
let name = ; //zhang li ... let age = ; // 18 20 ... let uri = "/test?name" + name + "&age=" + age;
模板字符串方式:可读性高
let name = ; //zhang li ... let age = ; // 18 20 ... // 模板字符串方式 需要使用反引号使用 let uri = `/test?name=${name}&age=${age}`
3、number和bigint ⭐
-
number 类型表示的是双精度浮动小数,例如
10 / 3; //结果 3.3333333333333335
既然是浮点小数,那么可以除零
10 / 0; // 结果 Infinity 正无穷大 -10 / 0; // 结果 -Infinity 负无穷大
浮点小数都有运算精度问题,例如
2.0 - 1.1 // 结果 0.899999999999999
-
字符串转数字
parseInt("10"); // 结果是数字 10 parseInt("10.5"); // 结果是数字 10,去除了小数部分 parseInt("10") / 3; // 结果仍是为 number 浮点数,因此结果为 3.3333333333333335 parseInt("abc"); // 转换失败,结果是特殊值 NaN (Not a Number)
-
需要表示真正的整数,需要用 bigint,数字的结尾用 n 表示它是一个 bigint 类型
10n / 3n; // 结果 3n,按整数除法处理
4、boolean ⭐
-
Truthy
-
Falsy
在js种,并不是 boolean 才能用于条件判断,你可以在if语句种使用【数字】、【字符串】…自拍为判断条件
let b = 1; if(b){ // true console.log("进入了"); }
这时就有一个规则,当需要条件判断时,这个值被当作 true 还是 false,当作 true 的值归类为
truthy
,当作 false的值归类为
falsy
-
falsy
-
false
-
Nullish(null,undefined)
-
0 或 0n 或 NaN(0和 非数字)
-
“” 或 ” 或 “ (长度为零的空字符串)
-
5、symbol
3、对象类型
1、Function ⭐⭐
定义
function 函数名(参数){ // 函数体 return 结果; // 不是必须的 }
例子
function add(a,b){ return a + b; }
调用函数
函数名(实参);
例子
add(1,2); // 返回 3 add('a','b'); // 返回 ad add(4,5,6); // 返回 9,第三个参数没有被用到,不会报错 add(1); // 返回 NaN,这是 b 没有定义是 undefined,undefined做数学运算结果就是 NaN
1、默认参数
java中(spring)要实现默认参数的效果
@RestController public class MyController { @RequestMapping("/page") @ResponseBody public void page( @RequestParam(defaultValue="1") int page, @RequestParam(defaultValue="10") int siza ){ // ... } }
js
function pagination(page = 1,size = 10){ console.log(page,size) } // 显示默认值 pagination() // 1 10 // page 显示默认值 pagination(undefined,20) // 1 20 // size 显示默认值 pagination(2) // 2 10
2、匿名函数
语法
(function(参数){ // 函数体 return 结果; })
例
(function(a,b){ return a + b; })
第一种场景:定义完毕后立刻调用
(function(a,b){ return a + b; })(1,2)
第二种场景:作为其它对象的方法,例如
页面有元素
<p id = "p1">点我啊</p>
此元素有一个onclick方法,会在鼠标单击这个元素后被执行,onclick方法刚开始是null,需要赋值后才能使用
document.getElementById("p1").onclick = (function(){ console.log("鼠标单机了...") });
3、箭头函数
(参数) => { // 函数体 return 结果; }
-
如果没有参数,()还是要保留
-
如果只有一个参数,()可以省略
-
如果函数体内只有一行代码,{}可以省略
-
如果函数体内的一行代码是返回代码,那么return也可以省略
例:
document.getElementById("p1").onclick = () => console.log("鼠标单机了...箭头函数")function abc(){ console.log("bb"); } document.getElementById("p1").onclick = abc;
4、函数是对象
以下形式在 js 中非常常见!
-
可以参与赋值,例,具名函数也能参与赋值
function abc(){ console.log("bb"); } document.getElementById("p1").onclick = abc; // 如果console.log(abc) 看不到对象的内部结构 // 就是用console.dir() 查看对象的内部结构 console.dir(abc)
-
有属性、有方法
f abc() arguments: null caller: null length: 0 name: "abc" ➡prototype: {constructor: f} [[FunctionLocation]]: VM1962:1 ➡[[Prototype]]: f() ➡[[Scopes]]: Scopes[1]
-
其中带有 f 标记的是方法,不带的是属性
-
带有➡符号的可以继续展开,限于篇幅省略了
-
带有 [[ ]] 的是内置属性,不能访问,只能查看
-
相对重要的是 [[Prototype]] 和 [[Scopes]] 会在后面继承和作用域时讲到
-
-
可以作为方法参数
function a(){ console.log('a'); } // 接受了函数作为参数的函数叫做 "高阶函数" function b(fn){ //fn 将来可以是一个函数对象 console.log('b'); fn(); // 调用函数对象 } // 将来调用b的时候可以把a传进去 b(a)
-
可以作为方法返回值
// c函数把b函数当成了自己的返回值,那么c函数就是高阶函数 function c(){ console.log("c"); function d(){ console.log("d"); } return d; } c(); // 返回结果 c f d(){ console.log("d"); } c()(); // 返回函数对象 c d
5、函数作用域
函数可以嵌套( js 代码中很常见,只是嵌套的形式更多是匿名函数,箭头函数)
function a(){ function b(){ } }
看下面的例子
function c(){ var z = 30; } var x = 10; function a(){ var y = 20; function b(){ // 看这里 console.log(x,y); } b(); } a();
-
以函数为分界线划定作用域,所有函数之外是全局作用域
-
查找变量时,由内向外查找
-
在内层作用域找到变量,就会停止查找,不会再找外层
-
所用作用域都找不到变量,报错
-
-
作用域本质上时函数对象的属性,可以通过 console.dir 来查看调式
6、闭包
var x = 10; function a(){ var y = 20; function b(){ console.log(x,y); } return b; } a()(); // 在外面执行了 b
-
函数定义时,他的作用域已经确定好了,因此无论函数将来去了哪,都能从它的作用域中找到当时哪些变量
-
别被概念忽悠了,闭包就是指
函数能够访问自己的作用域中变量
7、let、var与作用域
-
如果函数外层引用的是let变量,那么外层普通的{}也会作为作用域边界,最外层的let 也占一个 script 作用域
let x = 10; if(true){ let y = 20; function b(){ console.log(x,y); } console.dir(b); } // 3个作用域(不包含自己):1、if() 2、let x = 10 3、Global
-
如果函数外层引用的是 var 变量,外层普通的 {} 不会被视为边界
var x = 10; if(true){ var y = 20; function b(){ console.log(x,y) } console.dir(b); } // 1个作用域(不包含自己) 1、Global
-
如果 var 变量出现了重名,则他俩会被视为同一作用域中的同一个变量
var e = 10; if(true){ var e = 20; console.log(e); // 打印 20 } console.log(e); // 因为是同一个变量,还是打印 20
-
如果是let,则视为两个作用域中的两个变量
let e = 10; if(true){ let e = 20; console.log(e); // 打印 20 } console.log(e); // 打印10
-
要想里面的 e 和外面的 e 能区分开来,最简单的办法时改成let,或者用函数来界定作用域范围
var e = 10; if(true){ function b(){ var e = 20; console.log(e); } } console.log(e);
2、Array ⭐
语法
// 创建数组 let arr = [1,2,3]; // 获取数组元素 console.log(arr[0]); // 输出 1 // 修改数组元素 arr[0] = 5; // 数组元素变成了 [5,2,3] // 遍历数组元素,其中 length 是数组属性, 代表数组长度 for(let i = 0; i < arr.length; i++){ console.log(arr[i]) }
API
1、push、shift、unshift、splice
let arr = [1,2,3] arr.push(4); // 向数组尾部(右侧)添加元素,结果 [1,2,3,4] arr.shift(); // 从数组头部(左侧)移除元素,结果 [2,3,4] arr.splice(1,1) // 删除【参数1】索引位置的【参数2】个元素,结果[2,4] arr.splice(1,0,1) // 在【参数1】索引位置的添加【参数3】元素并且【参数3】的索引为【参数1】 // 结果[2,1,4] 【参数2】的意思是删除的意思0是删除0个元素 arr.unshift(100) // 向数组头部(左侧)添加元素,结果[100,2,4] arr.slice(start,end)// slice()通过索引位置获取新的数组,该方法不会修改原数组,只是返回一个新的子数组。 左闭右开 [start,end) // 【参数1】:start - 必填,设定新数组的起始位置;如果是负数,则表示从数组尾部开始算起(-1指最后一个元素,-2 指倒数第二个元素,以此类推)。 // 【参数2】end - 可选;设定新数组的结束位置;如果不填写该参数,默认到数组结尾;如果是负数,则表示从数组尾部开始算起(-1 指最后一个元素,-2指倒数第 二个元素,以此类推)。 Array.splice(start,delete_count,value,...) // 插入、删除、替换数组 // (1) start:开始插入和(或)删除的数组元素的下标。 // (2) delete_count:结束截取的数组下标,如果end是负数,表明从数组尾部开始计算. // (3)要插入数组的元素。value,-..: // 返回:如果从数组中删除了元素,则返回的是被删除的元素的数组
2、join
let arr = ['a','b','c']; arr.join(); // 默认使用【,】作为连接符,结果'a,b,c' arr.join(''); // 结果 'abc' arr.join('-'); // 结果 'a-b-c'
3、map、filter、forEach
map 例子
let arr = [1,2,3,6]; // [10,20,30,60] function a(i){ // 代表的新旧元素之间的变化规则 return i * 10; } arr.map(a); // 具名函数,结果 [10,20,30,60] // ↓ 进一步简化 arr.map( (i)=>{return i * 10}); // 箭头函数 // ↓ 进一步简化 arr.map( i => i * 10); // 箭头函数
-
传给 map 的函数,参数代表旧元素,返回值代表新元素,map的内部实现(伪代码)
function map(a){ // 参数是一个函数 let narr = []; for(let i = 0; i < arr.length; i++){ let o = arr[i]; // 旧元素 let n = a(o); // 新元素 narr.push(n); } return narr; }
filter 例子
let arr = [1,2,3,6]; arr.filter( i => i % 2 == 1); // 结果 [1,3]
-
传给 filter 的函数,参数代表旧元素,返回值 true 表示要留下的元素
forEach例子
let arr = [1,2,3,6]; for(let i = 0; i < arr.length; i++){ console.log(arr[i]) } arr.forEach( i => console.log(i)); arr.forEach((v,i) => {console.log(`n[${i}]=${v}`)})
-
高阶函数:map,filter,forEach
-
回调函数: 例如作为参数传入的函数
4、split
字符串转数组
let arr4 = '中国人'.split('') console.log(arr4) // 输出结果 ['中','国','人']
5、升序,降序,洗牌
注意:num是一个非空数字数组
-
升序:num.sort((a,b) => a-b)
-
降序:num.sort((a,b) => b-a)
-
洗牌:num.sort(() => Math.random() > .5 ? a : b)
6、.find()
根据元素查找元素
let n = [1,2,3,4,5,6,7,8,9,10,2,4,2,1] console.log(n.find(e => e === 10)) // 10
7、去重
// 去重 console.log('-------------去重') let nn = [1,2,3,4,5,6,5,7,5,8,6,9,4,6] console.log(nn) // 方法1 过滤 let arr = nn.filter((v,i)=>nn.indexOf(v)===i) console.log(arr) // 方法2 set方法 let arr2 = [...new Set(nn)] console.log(arr2)
8、数组和 (解构)
let nn = [1,2,3,4,5,6,5,7,5,8,6,9,4,6] let n2 = [1,2,3,4] console.log(nn) console.log(n2) console.log('-------------数组和') nn.push(...n2) console.log(nn)
9、差集、交集、并集
let a1 = [1, 2, 3] let a2 = [11, 22, 33, 1, 2, 3] // 差集 let a4 = a2.filter(e => !a1.includes(e)) console.log(a4) // 交集 let a3 = a1.filter(e => a2.includes(e)) console.log(a3) // 并和 去重 a1.push(...a2.filter(e => !a1.includes(e))) console.log(a1)
3、Object ⭐⭐
-
属性
-
方法
-
get、set
1、语法
let obj = { 属性名: 值, 方法名: 函数, get 属性名() {}, set 属性名(新值) {} }
例1 写法1
let stu1 = { name: "小明", age: 18, study: function(){ console.log(this.name + "爱学习"); } }
例2 写法2
let name = "小黑"; let age = 20; let study = function(){ console.log(this.name + "爱学习"); } let stu2 = { name, age, study }
例3 (例1的简写方式 重点)⭐
let stu3 = { name: "小明", age: 18, study(){ console.log(this.name + "爱学习"); } }
-
注意:对象方法这么写,仅限于对象内部
例4
let stu4 = { _name: null, // 类似于java中私有成员变量 get name(){ console.log("进入了get"); return this._name; }, set name(name){ console.log("进入了set"); this._name = name; } }
调用 get,set
stu4.name = "小白"; // 调用set 赋值语句 console.log(stu4.name) // 调用get
2、
特殊:属性增删
对比以下 Java 中的 Object
-
Java 的 Object 是以类作为模板来创建,对象不能脱离类模板的范围,一个对象的属性,能用的方法都是确定好的
-
js 的对象,不需要什么模板,它的属性和方法可以随时加减
let stu = {name: '张三'}; stu.age = 18; // 这个age属性是创建stu后加上的 delete stu.age; // 删除 stu这个对象中的age属性 stu.study = function() { console.log(this.name + "在学习"); // 这个study方法是后加的 }
3、
用动object.defineProperty()对象态添加 get,set
let stu = { _name:null }; // 第一个参数 给哪一个对象定义属性 // 第二个参数 属性名 不要和_name冲突 // 第三个参数 包含了get,set的定义 object.defineProperty(stu,"name",{ get(){ return this._name }, set(name){ this._name = name; } });
4、特殊:this (this的三种情况,一种特例)
先来对 Java 中的 this 有个理解
public class TestMethod{ static class Student{ private String name; public Student(String name){ this.name = name; } // 隐式参数Student this public void study(Student this,String subject){ System.out.println(this.name + ": 在学习" + subject); } } public static void main(String[] args){ Student stu = new Student("小明"); // 下面的代码,本质上是执行 study(stu, "java"),因此 this 就是 stu stu.study("java"); } }
js 中的 this 也是隐式参数,但是它与函数运行时上下文相关
①、一个”落单“的函数
function study(subject){ console.log(this.name + "在学习" + subject); }测试以下
study("js"); // 输出 在学习 js
这是因为此时函数执行,全局对象 window 被当作了 this, window 对象的 name 属性是空串
②、同样的函数,如果作为对象的方法
let stu = { name: "小白", study }
这种情况下,会将当前对象作为 this
③、.call 还可以动态改变this
let stu = {name:"小黑"}; // 第一个参数:你要把this视为谁? // 第二个参数:传入study方法需要的形参 study.call(stu,"js"); // 输出 小黑在学习 js
这回 study 执行时,就把 call 的第一个参数 stu 作为 this
例外
:在
箭头函数
内出现的 this,以外层 this 理解
用匿名函数
let stu = { name: "小花", friends: ["小白","小黑","小明"], play:function(){ // play:function() == play() this.friends.forEach(function(e){ console.log(this.name + "与" + e + "在玩耍"); }); } } stu.play(); // 第一个this指的时stu 第二个this指的是window(因为第二个函数时落单的函数)
-
this.name 所在的函数时【落单】的函数,因此 this 代表 window
输出结果为
与小白在玩耍 与小黑在玩耍 与小明在玩耍
用箭头函数
let stu = { name: "小花", friends: ["小白","小黑","小明"], play(){ this.friends.forEach(e =>{ console.log(this.name + "与" + e + "在玩耍"); }); } } //在箭头函数内出现的 this,以外层 this 理解
-
this.name 所在的函数是箭头函数,因此 this 要看它外层的 play 函数, play 又是属于 stu 的方法,因此 this 代表 stu 对象
输出结果为
小花与小白在玩耍 小花与小黑在玩耍 小花与小明在玩耍
不用箭头函数的做法
let stu = { name: "小花", friends: ["小白","小黑","小明"], play(){ let me = this; this.friends.forEach(function(e){ console.log(me.name + "与" + e + "在玩耍"); }); } }
5、特殊:原型继承(对象之间)
let father = { f1: '父属性', m1: function(){ console.log("父方法"); } } // .create:以父对象为原型创建一个子对象 let son = Object.create(father); console.log(son.f1); // 打印 父属性 son.m1 // 打印 父方法
-
father 是父对象,son 去调用 .m1 或 .f1 时,自身对象没有,就到父对象找
-
son 自己可以添加自己的属性和方法
-
son 里有特殊属性
__proto__
代表它的父对象,js 术语:son 的原型对象 -
不同浏览器对打印 son 的
__proto__
属性时显示不同-
Edge 打印 console.dir(son) 显示
[[prototype]]
-
Firefox 打印 console.dir(son) 显示
<protorype>
-
6、特色:基于函数的原型继承
出于方便的原因,js 又提供了一种基于函数的原型继承
函数职责
负责创建子对象,给子对象提供属性,方法,功能上相当于构造方法
函数有个特殊的属性 prototype,它就是函数创建的子对象的父对象
注意!
名字有差异,这个属性的作用就是为新对象提供原型
function cons(f2){ // 创建子对象(this),给子对象提供属性和方法 this.f2 = f2, this.m2 = function (){ console.log("子方法"); } } // cons.prototype 就是父对象 cons.prototype.f1 = "父属性"; cons.prtotype.m1 = function(){ console.log("父方法"); }
配合 new 关键字,创建子对象
let son = new cons("子属性");
子对象的
__proto__
就是函数的
prototype
属性
4、JSON
之前我们将 http 请求格式时,讲过 json 这种数据格式,他的语法看起来与 js 对象非常相似,例如:
一个 json 对象可以张这样:
{ "name":"张三", "age":18 }
一个 js 对象长这样
{ name:"张三", age:18 }
1、 json对象 与 js对象 的区别在哪儿呢???
本质不同
json 对象本质上就是个字符串,它的职责是作为客户端和服务器之间传递数据的一种格式,它的属性只是样子货
js 对象是切切实实的对象,可以有属性方法
语法细节不同
json 中只能有null、true|false、数字、字符串(只有双引号)、对象、数组
json 中不能有除以上的其他 js 对象的特性、如方法等
json 中的属性必须用双引号引起来
2、json 字符串与js对象的转换
// 把 json 字符串转化为 js 对象 返回对象js对象 JSON.parse(json字符串); // 把 js 对象转换成 json 字符串 返回json字符串 JSON.stringify(js对象);
3、JSON语法
let json = `{ "name":"张三", "age":18 }`; let obj = JSON.parse(json);
5、动态类型
静态类型语言,如 Java,值有类型,变量也有类型、赋值给变量时,类型要相符
int a = 10; String b = "abc"; int c = "abc"; // 错误
而 js 属于动态类型语言,值有类型,但变量没有类型,赋值给变量时,没要求
例如
let a = 200; let b = 100; b = 'abc'; b = true;
动态类型看起来比较灵活,但变量没有类型,会给后期维护带来困难,例如
function test(obj){ // obj 的类型未知,必须根据不同类型做出各种容错处理 }
三、运算符与表达式 ⭐
+ - * / % **
+= -= *= /= %= **=
++ --
位移算、移位运算
(估计大家用不着,用到时候上网搜索)
== != > >= < <=
=== !==
⭐
&& || !
⭐
?? ?.
⭐
...
⭐
解构赋值
[]{}⭐
**
:乘方
**=
:乘方等
1、
===
(严格相等)
===
严格相等运算符,用作逻辑判等。
1 == 1 // 返回 true 1 == '1' // 返回 true,会先将右侧的字符串转为数字,再做比较 1 === '1' // 返回 false。类型不等,直接返回 false
补充:typeod 查看某个值的类型
typeof 1; // 返回 'number' typeof 'a'; // 返回 'string'
2、
||
(逻辑或)
||
需求,如果参数 n 没有传递,给它一个 【男】
推荐做法
function test(n = '男'){ console.log(n); }
你可能的做法
function test(n){ if(n === undefined){ n = '男'; } console.log(n) }
还可能时这样
function test(n){ n = (n === undefined) ? '男' : n; console.log(n); }
一些老旧代码中可能的做法(
不推荐,有潜在问题
)
function test(n){ n = n || '男'; console.log(n); }
它的语法时
值1 || 值2
如果值1 时 Truthy,返回值1,如果值1 时 Falsy 返回值2
3、
?? 与 ?.
?? 与 ?.
?.
可选链操作符用于访问可能为空或未定义的属性或方法,它允许我们安全地访问嵌套对象的属性
??
空值合并操作符用于检查一个变量是否为 null 或 undefined,如果是,则返回一个默认值,否则返回该变量的值。与传统的逻辑运算符
||
不同,
??
只会在左侧的值为 null 或 undefined 时返回右侧的默认值,对于其他假值(如空字符串、0、false 等)并不会返回默认值,而是会返回它本身。
需求,如果参数 n 没有传递值或是 null,给它一个【男】
如果用传统办法
function test(n){ if(n === undefined || n === null){ n = '男'; } console.log(n); }
用 ??
function test(n){ n = n ?? '男'; console.log(n) }
需求,函数参数是一个对象,可能包含有子属性
例如,参数可能是
let stu1 = { name:"张三", address:{ city:'北京' } } let stu2 = { name:"李四", } let stu3 = { name:"李四", address: null }
现在要访问子属性
function test(stu){ console.log(stu.address.city) }
现在希望当某个属性是 nullish 时,短路并返回 undefined
function test(stu){ console.log(stu.address?.city) }
用传统办法
function test(stu){ if(stu.address === undefined || stu.address === null){ console.log(undefined); return; } console.log(stu.address.city); }
4、
...
...
展开运运算符
作用1:打散数组传递给多个参数
let arr = [1,2,3]; function test(a,b,c){ console.log(a,b,c); }
-
传统的打散写法
test(arr[0],arr[1],arr[2]); // 输出 1,2,3
-
展开运算符写法
test(...arr); // 输出 1,2,3
-
打散可以理解为【去掉了】数组外侧的中括号,只剩下数组元素
-
作用2:复制数组或对象
数组
let arr1 = [1,2,3]; let arr2 = [...arr1]; // 复制数组
对象
let obj1 = {name:'张三',age:18}; let obj2 = {...obj1}; // 复制对象
注意
:展开运算符复制属于浅拷贝(只能复制一层,多层的话就是引用了),例如
let o1 = {name:'张三',address:{city:'北京'}} let o2 = {...o1};
作用3:合并数组或对象
合并数组
let a1 = [1,2]; let a2 = [3,4]; let b1 = [...a1,...a2]; // 合并数组 [1,2,3,4] let b2 = [...a2,5,...a1] // 输出 [3,4,5,1,2]
合并对象
let o1 = {name:'张三'}; let o2 = {age:18}; let o3 = {name:'李四'}; let n1 = {...o1, ...o2}; // 结果 {name:'张三',age:18} let n2 = {...o1, ...o2, ...o3}; // 结果 {name:'李四',age:18}
5、
[]{}
[]{}
解构赋值
[]
用在声明变量是
let arr = [1,2,3]; // 我们把中括号叫做数组的解构赋值 let [a,b,c] = arr // 结果 a=1,b=2,c=3
用在声明参数时
let arr = [1,2,3]; function test([a,b,c]){ console.log(a,b,c); } test(arr); // 结果 a=1,b=2,c=3
{}
用在声明变量时
let obj = {name:"张三",age:18}; // 声明的变量名称要和obj的对象属性一致 let {name,age} = obj;
用在声明参数时
let obj = {name:"张三",age:18}; function test({name,age}){ console.log(name,age); } test (obj);
四、控制语句
if ... else
switch
while
do ... while
for
for ... in
⭐
for ... of
⭐
try ... catch
⭐
1、for in
主要用来遍历对象
let father = {name:'张三',age:18,study:function(){}}; for(const n in father){ console.log(n); } // 结果 name age study
-
其中 const n 代表遍历出来的属性名
-
注意1:方法名也能被遍历出来(它其实也算一种特殊属性)
-
注意2:遍历子对象时,父对象的属性会跟着遍历出来
let son = object.create(father); son.sex = "男"; for(const n in son){ console.log(n); } // 结果 sex name age study
-
注意3:在 for in 内获取属性值,要使用 [] 语法,而不能用 . 语法
for(const n in son){ console.log(n,son[n]); } // 结果 // sex 男 // name 张三 // age 18 // study f (){}
2、for of
主要用来遍历数组,也可以时其它可迭代对象,如Map,Set等
let a1 = [1,2,3]; for(const i of a1){ console.log(i); } let a2 = [ {name:'张三',age:18}, {name:'李四',age:20}, {name:'王五',age:22} ]; for(const obj of a2){ console.log(obj.name,obj.age); } for(const {name,age} of a2){ console.log(name,age); }
3、try catch
let stu1 = {name:'张三',age:18,address:{city:'北京'}}; let stu2 = {name:'张三',age:18}; function test(stu){ try{ console.log(stu.address.city); } catch(e){ console.log('出现了异常',e.message); } }
五、Fetch API
Fetch API 可以用来获取远程数据,他有两种方式接受结果,同步方式与异步方式
格式
fetch(url,options) // 返回 Promise对象
同步方式
// const 结果 = await fetch(url,options); const 结果 = await Promise; // 后续代码
-
await 关键字必须在一个标记了 async 的 function 内来使用
-
后续代码不会在结果返回前执行
异步方式
fetch(url,options).then(结果 => {...}) // 后续代码
-
后续代码不必等待结果返回就可以执行