ES5
1.严格模式
1.全局严格模式
-
严格模式修复了一些导致
JavaScript引擎难以执行优化的缺陷:有时候,相同的代码,严格模式可以比非严格模式下运行得更快 -
如果浏览器不支持, 只解析为一条简单的语句, 没有任何副作用
a.开启全局严格模式
<script>
"use strict"
//在全局开启严格模式
b.变量必须声明才能使用
<script>
"use strict"
a = 1;
console.log(a)
//Uncaught ReferenceError: a is not defined
//未捕获的ReferenceError:未定义
</script>
c.函数自调用this是window
// 严格模式下,如果函数自己调用,this是undefined
function fn(){
console.log(this)
}
fn()//undefined
window.fn()//window
d.创建了eval作用域
// 严格模式下,创建了eval作用域
/* eval("alert(1)")
eval可以把一串字符串代码运行 */
eval("var a = 1; console.log(a)"); //1
console.log(a)
//ReferenceError: a is not defined
e.禁止调用栈
<script>
"use strict"
// 禁止调用栈
function fn() {
console.log(arguments)
//Arguments [callee: (...), Symbol(Symbol.iterator): ƒ]
console.log(arguments.callee)
// Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
// 如果不是严格模式,这里指向fn这个函数
}
fn()
</script>
f.严格模式下禁止删除变量
- 禁止删除变量
<script>
"use strict"
a = 1;
delete a;
console.log(a)
// Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
</script>
<script>
a = 1;
delete a;
console.log(a)
// Uncaught ReferenceError: a is not defined
</script>
<script>
"use strict"
const a = 100; var let const都如此
delete a
// Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
未捕获的SyntaxError:删除严格模式下的非限定标识符。
</script>
-
var/const/let 声明变量 经测试都无法删除
-
并且const/let声明的变量不在window中
<script>
var a = 100;
console.log(window)
console.log(a)
// 100
delete a
console.log(window)
console.log(a)
// 100
</script>
delete a
- 直接声明变量
<script>
a = 100;
console.log(window)
//见图
console.log(a)
// 100
delete a
console.log(window)
console.log(a)
//Uncaught ReferenceError: a is not defined
</script>
delete a
- 注意区别
<script>
var a = {
b : 100
}
console.log(a)
// {b:100}
delete a.b
console.log(a)
// {}
</script>
<script>
"use strict"
var a = {
b : 100
}
console.log(a)
// {b:100}
delete a.b
console.log(a)
// {}
</script>
2.局部严格模式
<script>
a = 1;
function fn(){
"use strict"
//在当前作用域中开启严格模式
b = 2;
console.log(b);
//ReferenceError: b is not defined
}
console.log(a);//1会正常打印
fn();
</script>
2.JSON
JSON的格式和JS对象基本一致,但是有两点需要注意:
-
JSON的属性名必须使用双引号
-
最后一个属性后绝对不能有逗号
<script>
var json = '{"name":"孙悟空", "age":18, "gender":"男", "haha":null, "abc":{}, "bcd":[]}';
var jsonArr = '[1, 2, 3]';
console.log(typeof json); //string
console.log(typeof jsonArr); //string
</script>
JSON类型
-
JSON对象
- {}
-
JSON数组
- []
JSON所支持的属性的类型
-
数字
-
字符串(使用双引号)
-
布尔值
-
空值(null)
-
对象
-
数组
JSON深复制
可以通过JSON来完成对象的深复制
slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end
决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N3sXwJhi-1605369770483)(media/54c7bc2edceb839fe246c666c1f984f2.png)]
1.eval把json字符串转换为json对象(了解)
<script>
var message = '{"name":"rolls","age":"99","color":"orange"}';
console.log(typeof message)
//string
// eval把json字符串转换为json对象
console.log(eval("("+message+")"))
//{name: "rolls", age: "99", color: "orange"}
</script>
2.parse()把JSON字符串转换成JS对象
//JSON.parse()把json字符串转换成json对象
console.log(typeof JSON.parse(message))
// object
//{name: "rolls", age: "99", color: "orange"}
<script>
json = '{"name":"孙悟空", "age":18, "gender":"男"}';
console.log(JSON.parse(json)) //Object
//{name: "孙悟空", age: 18, gender: "男"}
</script>
3.stringify()把JS对象转换为JSON字符串
// // JSON.stringify() 把JSON对象转换为JSON字符串
let message = {
"name" : "rolls",
"age" : 90,
"color" : "orange"
};
console.log(message)
//{name: "rolls", age: 90, color: "orange"}
// 这是对象
console.log(JSON.stringify(message))
//{"name":"rolls","age":90,"color":"orange"}
// 这是JSON字符串
<script>
var arr = [
{name:"孙悟空", age:18, gender:"男"},
{name:'猪八戒', age:28, gender:'男'},
{name:'沙和尚', age:38, gender:'男'}
];
console.log(JSON.stringify(arr))
//[{"name":"孙悟空","age":18,"gender":"男"},{"name":"猪八戒","age":28,"gender":"男"},{"name":"沙和尚","age":38,"gender":"男"}]
</script>
3.object扩展
1.Object.create()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rlJKf7gR-1605369770487)(media/495cfbf6f3d9c7998435740bae9c03d5.png)]
properties:属性
1.继承
var obj1 = {
name: "xiaowang",
sex: "nan"
}
//1.创建一个新的对象,把新对象的隐式原型指向了obj1,这个也被称作为继承
var obj2 = Object.create(obj1);
console.log(obj2);
//{}
console.log(obj2.name); //xiaowang
//只给obj2扩展,obj1是没有
obj2.age = 12;
console.log(obj1.age);
//xiaowang,因为它的隐式原型指向obj1
2.创建干净对象
//2.可以使用create创建一个干净的对象 (直接隐式原型指向null)
var obj3 = Object.create(null);
console.log(obj3);
//{ No properties }
3.创建正常对象
//3.使用create创建一个正常的对象(就像使用字面量创建一个)
var obj4 = Object.create(Object.prototype);
console.log(obj4)
2.create创建对象属性描述
1.create方法第二个参数
create方法的第二个参数是一个对象
对象内格式是 key:{value:xxxx,xxx:xxx}
value:当前key的值
writable:当前属性是否可以被写入 默认是false
enumerable:当前属性是否可以被枚举 默认是false
configurable:当前属性的描述是否可以被修改 和 当前属性是否能够被删除 默认是false
2.演示
var obj1 = Object.create(null, {
name: {
value: "xiaowang",
writable: false,
enumerable: false,
configurable: false
}
});
console.log(obj1)
//{name: "xiaowang"}
//尝试修改属性的值
obj1.name = "xiaoli";
console.log(obj1);
//{name: "xiaowang"}
//不能修改,因为writable: false
//尝试枚举
for (var key in obj1) {
console.log(key);
}
// 不能遍历,因为enumerable false
//尝试删除
delete obj1.name;
console.log(obj1);
//{name: "xiaowang"}
//不能删除,因为configurable:false
//当打印出来的系统提供的对象属性颜色 为浅紫色的时候 代表这个属性不可以枚举
for (var key2 in Object.prototype) {
console.log(key2)
}
//如果直接给这个create创建的对象 设置属性的时候,此时扩展的属性是不受描述影响的
obj1.age = 18;
console.log(obj1)
//可以被枚举
for (var key in obj1) {
console.log(key);
}
//可以被删除
delete obj1.age;
console.log(obj1)
3.defineProperty设置对象属性
//创建一个普通的对象
var obj1 = {
name: "小王",
age: 12
}
//使用Object.defineProperty设置对象属性
//Object.defineProperty(obj,key,{des})
//如果修改的是普通属性,则只修改你要修改的秒速,其他默认都是true
Object.defineProperty(obj1, "age", {
value: 18,
//没有添加的描述默认是true
})
//age依然可以被修改
obj1.age = 20;
console.log(obj1);
// {name: "小王", age: 20}
//当对象是使用create创建的时候,修改属性或描述的情况
var obj2 = Object.create(null, {
name: {
value: "xiaowang",
writable: true,
enumerable: false,
// configurable: false
}
});
Object.defineProperty(obj2, "name", {
value: "xiaohong",
enumerable: true, //需要创建name属性的时候,设置的描述configurable 为true 才能修改name的描述属性
})
console.log(obj2)
//{name: "xiaohong"}
//writable: true
for (var key in obj2) {
console.log(key)
//name enumerable: true
}
4.defineProperties设置对象属性
//创建一个普通的对象
var obj1 = {
name: "小王",
age: 12
}
//使用Object.defineProperties 设置对象属性
//Object.defineProperties(obj,{des})
//其他和defineProperty一样,除了一个书写多个 一个是书写一个
Object.defineProperties(obj1, {
name: {
value: "laowang"
},
age: {
value: 200
},
sex: {
value: "nv" //如果添加新属性,则默认描述都是false
}
})
console.log(obj1)
//{name: "laowang", age: 20, sex: "nv"}
for (var key in obj1) {
console.log(key);
// name age sex
}
5.getter和setter
<script>
//当对对象中多个属性进行读取和设置的时候,就可以使用getter和setter
//getter只能读 setter只能写
var obj1 = {
firstName: "lao",
lastName: "wang",
get fullName() {
return this.firstName + " " + this.lastName;
},
set setName(val) {
// var arr = val.split(" ");
// this.firstName = arr[0];
// this.lastName = arr[1];
[this.firstName, this.lastName] = val.split(" ");
}
}
// console.log(obj1.firstName + obj1.lastName);
console.log(obj1.fullName);
//lao wang
console.log(obj1);
//{firstName: "lao", lastName: "wang"}
//设置内容
obj1.setName = "lao li"
</script>
ES6
1.关键字扩展
1.块作用域,可以作用域嵌套
<script>
// 块作用域是代码块{}所构成的作用域
{
let a = 1;
console.log(a);
//1
{
let b = 2;
console.log(a,b);
//1 2
{
let c = 3;
console.log(a,b,c)
//1 2 3
}
}
}
</script>
2.let声明的变量,只在代码块中生效,所以就拥有了块级作用域
var a = 1;
if (a > 0) {
var b = 2;
}
console.log(b)
//2
var a = 1;
if (a > 0) {
let b = 2;
}
console.log(b)
//ReferenceError: b is not defined
3.let特点(其次)
1.没有声明提升
<script>
// 没有声明提升
{
console.log(a)
let a = 1;
}
//Uncaught ReferenceError: Cannot access 'a' before initialization
</script>
2.不允许重复声明
// 不允许重复声明
{
let a = 1;
let a = 2;
}
//ReferenceError: Cannot access 'a' before initialization
3.块级作用域使得IIFE没有必要存在
{
let a = 1;
console.log(a);
//1
}
4.const常量(优先使用)
1.常量不允许被修改
{
const PI = 3.1415926;
console.log(PI)
//常量不允许被修改(不允许修改栈中 常量保存的值)
// PI = 3.14159265352344265253423;
// TypeError: Assignment to constant variable.
}
2.改常量保存地址值内数据无碍
{
const obj = {
name: "lucy",
sex: "nv"
}
//obj常量 保存的地址值没有被修改 所以可以正常执行
obj.age = 14;
console.log(obj)
// {name: "lucy", sex: "nv", age: 14}
}
3.const声明的时候必须赋值操作
{
//常量在声明的时候 必须赋值操作
// const a; //Uncaught SyntaxError: Missing initializer in const declaration
// a = 1;
}
4.不能提升,并且不能重复声明
{
//常量是块作用域 并且不能提升 并且不能重复声明
// console.log(a);
//ReferenceError: Cannot access 'a' before initialization
}
{
const a = 1;
//const a = 1;
//Uncaught SyntaxError: Identifier 'a' has already been declared
}
5.let const 声明变量不再是window的属性了
//使用const let 声明的全局变量 不再是window的属性了
// var a = 1;
// let a = 1;
const a = 1;
console.log(window.a);
//undefined
2.变量的解构赋值
1.数组的解构赋值
1.解构赋值的方法
//1.解构赋值方法
{
const arr = [3, 5, 7, 9];
let [a, b, c, d] = arr;
//声明了 a b c d 4个变量 放在数组结构中,去接受数组的值
console.log(a, b, c, d);
// 3 5 7 9
}
2.解构失败 返回undefined
//2.解构失败 返回undefined
{
let [a, b] = [1];
console.log(a, b)
// 1 undefined
}
3.不完全解构 也可以完成
//3.不完全解构 也可以完成
{
let [a] = [1, 2];
console.log(a)
//1
}
4.可以给解构赋值的变量设置默认值(可设可不设)
//4.可以给解构赋值的变量设置默认值(可设可不设)
{
const [a = 2, b = 1] = [9];
console.log(a, b)
//9 1
}
5.可以使用rest参数(…) 必须写在最后一个 是一个数组,包含了剩余没有解构的元素
//5.可以使用rest参数(...) 必须书写在最后一个 是一个数组,包含了剩余没有解构的元素
{
const [a, b, ...c] = [1, 2, 3, 4, 45, 6, 7, 8, 99];
console.log(a, b, c) //1 2 [3, 4, 45, 6, 7, 8, 99]
}
6.多维数组也可以进行匹配
//6.多维数组也可以进行匹配
{
const arr = [1, [2, 3, [4, [5]], 6], 7];
const [a, [b, c, [d, [e]], f], g] = arr;
console.log(a, b, c, d, e, f, g);
//1 2 3 4 5 6 7
}
7.交换两个变量练习
{
let a = 1;
let b = 2;
[a,b] = [b,a];
console.log(a,b);
// 2 1
}
8.解构赋值练习2
- 变量未声明之前不能使用
//解构赋值练习2:
{
let [foo = hoo, hoo = 2] = [];
console.log(foo, hoo)
//ReferenceError: Cannot access 'hoo' before initialization
//在初始化之前无法访问'hoo'
}
9.解构赋值练习3
//练习1:如果想要获取数组的第一个和最后一个值怎么办(使用解构赋值)
let arr = [1, 2, 3];
// 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构
let { 0: first, [arr.length - 1]: last } = arr;
console.log(first)
console.log(last)
2.对象的解构赋值
1.对象解构赋值方法
const obj = {
name: "laoli",
age: 19,
sex: "nan",
fn1: function () {
}
}
{
//解构对象,对象的key和value(变量名) 相等的时候 可以简写
//对象的解构主要也是掌握 key的一一对应关系
const {
name,
age,
sex,
} = obj;
console.log(name, sex, age);
//laoli nan 19
}
2.对象解构赋值也可以给默认值
<script>
const obj = {
name: "laoli",
age: 19,
sex: "nan",
fn1: function () {
}
}
{
const{
name = "rolls",
age,
score = 90
} = obj;
console.log(name,age,score)
//laoli 19 90
}
</script>
3…可以嵌套解构
{
//可以嵌套解构
const obj = {
name: "laoli",
score: [100, 90, 80]
}
const {
name,
score: [ch, ma, en]
} = obj;
console.log(name, ch, ma, en) //laoli 100 90 80
}
4.解构赋值应用1
{
//解构赋值的应用1
const {
log,
dir
} = console;
log(1);//1
dir(1);//1
const {
create
} = Object;
log(create(null)) //{}
}
5.解构赋值应用2-函数传参
{
// 解构赋值的应用2
const fn = function ([a, b, c, d]) {
console.log(a, b, c, d)
}
fn([1, 2, 3, 4])
}
6.函数的返回值接收
{
//函数的返回值接受
const fn = function () {
return {
left: 10,
right: 20
}
}
const {
left,
right
} = fn();
}
3.字符串的扩展
1.模板字符串
//模板字符串
//模板字符串使用反引号,变量嵌套使用${} 里边可以书写基础运算
const oBox = document.querySelector(".box");
oBox.innerHTML = `
<p>我的姓名是 <span>${obj.name==="lily"?obj.name:"你不配"}</span></p>
<p>我的性别是 <span>${setSex(obj.sex)}</span></p>
<p>我的年龄是 <span>${obj.age + 4}</span></p>
`;
2.方法–去空格
{
const str = " rolls royce ";
let newStr = "";
for (let i = 0; i < str.length ; i++){
if (str[i] === " ") {
continue;
}
newStr += str[i];
}
console.log(newStr)
let newStr = str.replace(/\s+/g,"");
console.log(newStr)
let say = "你TMD就是个hp";
console.log(say.replace(/TMD|hp/g,"***"))
}
4.数组扩展
4-1.扩展运算符
1.展开数组
<script>
const arr = [1, 2, 3, 4];
console.log(arr);
//[1, 2, 3, 4] 原来
console.log(...arr);
//1 2 3 4 展开
const arr2 = [1, 2, 2, ...arr, 5, 6];
console.log(arr2);
//(9) [1, 2, 2, 1, 2, 3, 4, 5, 6]
</script>
2.使用在传参上
const arr3 = [1, 2, 3, 4]
function fn(a, b, c, d) {
console.log(a + b + c + d);
}
fn(...arr3);
//10
3.复制数组
const arr4 = [1, 2, 3, 4, 5];
// const arr5 = arr4;
// 上面这个只是地址的复制 arr5和arr4都指向一个数组
// 复制数组
const arr5 = [...arr4];
console.log(arr5);
//[1, 2, 3, 4, 5]
console.log(arr5 === arr4)
//false
4.合并数组
const arr4 = [1, 2, 3, 4, 5];
const arr6 = [1, 2, 3, 4, 5];
//合并数组
const arr5 = [...arr4, ...arr6];
console.log(arr5)
//[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
5.展开字符串
const str = "hello";
const arr7 = [...str];
console.log(...str)
//h e l l o
console.log(arr7)
// ["h", "e", "l", "l", "o"]
6.解构赋值
//生成一个数组 (此时扩展运算符必须在最后一个)
let [a, b, ...newarr] = [1, 2, 3, 4, 5, 5, 6, 8, 9];
console.log(newarr);
//(7) [3, 4, 5, 5, 6, 8, 9]
4-2.数组的新方法
1.from()
- 从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
{
const obj1 = {
0: "a",
1: "b",
2: "c",
length: 3
}
const obj2 = {
0: "a",
1: "b",
2: "c"
}
//类数组的条件:1.key值从0开始依次自然递增,2.拥有length属性
console.log(Array.from(obj1))
//["a", "b", "c"]
console.log(Array.from(obj2))
//[]
}
2.of()
-
创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型
-
如果传递一个参数并且是数字的时候,那么就会创建一个新数组,长度为这个数字
弥补new Array的不足
{
const arr1 = new Array(4, 5);
console.log(arr1); //[4,5]
const arr2 = new Array(4);
console.log(arr2); //[,,,,]
console.log([, , , , ].length)
//4 如果最后一个逗号后为空,则这个逗号是结尾
const arr3 = Array.of(4);
console.log(arr3);
//[4]
const arr4 = Array.of(4, 5);
console.log(arr4);
//[4, 5]
}
3.copyWithIn()
{
/* copyWithIn();
复制当前数组中的某些值, 覆盖当前数组中的某些值
-
参数1: 开始替换的位置 -
参数2: 开始读取复制的位置 -
参数3: 读取复制的结束位置(不包含), 如果不写 则默认到末尾 */
const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const reArr1 = arr1.copyWithin(1, 6, 8);
console.log(arr1, reArr1)
//(9) [1, 7, 8, 4, 5, 6, 7, 8, 9] (9) [1, 7, 8, 4, 5, 6, 7, 8, 9]
}
4.fill()
- 填充数组
{
/* fill():填充数组
- 第一个参数就是填充的内容
- 第二个和第三个参数:填充的起始和结束位置 */
const arr1 = [1, 2, 3, 4, 5, 6];
const reArr1 = arr1.fill("a"); //全部填充
console.log(arr1, reArr1) //改变原数组 返回改变后的数组
const arr2 = [1, 2, 3, 4, 5, 6];
const reArr2 = arr2.fill("a", 3, 6); //全部填充
console.log(arr2, reArr2) //改变原数组 返回改变后的数组
//(6) ["a", "a", "a", "a", "a", "a"] (6) ["a", "a", "a", "a", "a", "a"]
}
5.find()
- 返回第一个匹配的元素(返回的是回调函数第一次返回true的item)
const arr = ["lao wang", "xiao wang", "li ly", "zhong wang", "da wang", "ni"];
//返回第一个姓li的名字
const re = arr.find(function (item, index) {
/* if (item.startsWith("li ")) {
return true;
} */
return item.startsWith("li ");
})
console.log(re);
//li ly
6.findIndex()
- 返回第一个匹配的下标(返回的是回调函数第一次返回true的index)
const arr = ["lao wang", "xiao wang", "li ly", "zhong wang", "da wang", "ni"];
//返回第一个姓li的名字
const re = arr.findIndex(function (item, index) {
return item.startsWith("li ");
})
console.log(re);
//2
7.flat()
- 拉平数组(数组扁平化)
{
const arr1 = [1, 2, [3, 4]];
console.log(arr1.flat(1))
//(4) [1, 2, 3, 4]
const arr2 = [1, 2, [3, [4, 5]]];
console.log(arr2.flat(Infinity))
//(5) [1, 2, 3, 4, 5]
}
8.entries()
-
拿到了数组的键值对的遍历器对象
-
- 遍历器对象有一个next方法,可以依次遍历iterator中的内容
{
const arr1 = ["a", "b", "c", "d", "e"];
const iter = arr1.entries(); //返回的是一个iterator(遍历器对象)对象
//遍历器对象有一个next方法,可以依次遍历iterator中的内容
console.log(iter);
/* Array Iterator {}
__proto__: Array Iterator
next: ƒ next()
Symbol(Symbol.toStringTag): "Array Iterator"
__proto__: Object */
console.log(iter.next());
//{value: Array(2), done: false}
// Array(2) value: (2) [0, "a"]
console.log(iter.next());
//{value: Array(2), done: false}
console.log(iter.next());
//{value: Array(2), done: false}
console.log(iter.next());
//{value: Array(2), done: false}
console.log(iter.next());
//{value: Array(2), done: false}
console.log(iter.next());
//{value: undefined, done: true}
console.log(iter.next());
// {value: undefined, done: true}
for (let i of arr1.entries()) {
console.log(i) //拿到了 每一次的[key,value]的值
/* (2)[0, "a"]
(2)[1, "b"]
(2)[2, "c"]
(2)[3, "d"]
(2)[4, "e"] */
}
console.log(iter)
//Array Iterator {}
}
9.keys()
{
const arr1 = ["a", "b", "c", "d", "e"];
const iter = arr1.keys();
console.log(iter)
//Array Iterator {}
console.log(iter.next())
// {value: 0, done: false}
console.log(iter.next())
// {value: 1, done: false}
console.log(iter.next())
// {value: 2, done: false}
console.log(iter.next())
// {value: 3, done: false}
console.log(iter.next())
// {value: 4, done: false}
console.log(iter.next())
// {value: undefined, done: true}
console.log(iter.next())
// {value: undefined, done: true}
for (let i of arr1.keys()) {
console.log(i)
//拿到了 每一次的[key,value]的值
// 0 1 2 3 4
}
console.log(iter)
//Array Iterator {}
}
10.values()
{
const arr1 = ["a", "b", "c", "d", "e"];
const iter = arr1.values(); //返回的是一个iterator(遍历器对象)对象
//遍历器对象有一个next方法,可以依次遍历iterator中的内容
console.log(iter);
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
for (let i of arr1.values()) {
console.log(i) //拿到了 每一次的[key,value]的值
}
console.log(iter)
//Array Iterator {}
}
5.函数的扩展
5-1.函数的默认值
ES5
function fn(a, b) {
//b是可选的,如果b没有被传递,则默认是0;
b = b === undefined ? 0 : b;
return a + b;
}
console.log(fn(1)) //1
console.log(fn(1, 5)) //6
console.log(fn(1, "h")) //1h
ES6
直接给参数一个默认值即可
function fn1(a, b = 0) {
return a + b;
}
console.log(fn1(1)) //1
console.log(fn1(1, 5)) //6
console.log(fn1(1, "h")) //1h
5-2.rest参数
- 使用rese参数,获取的是数组类型
{
//...相当于整合了后边没有接受的值,只能放在最后一个
const [a, ...b] = [1, 2, 3, 4, 5, 6];
console.log(b);
//[2,3,4,5,6];
}
{
function fn1(...rest) {
//arguments获取所有实参 是类数组类型
// console.log(arguments)
//Arguments(5) [1, 2, 3, 4, 5, callee: (...), Symbol(Symbol.iterator): ƒ]
//使用rest参数 是数组类型
console.log(rest);
//(5) [1, 2, 3, 4, 5]
}
fn1(1, 2, 3, 4, 5)
}
{
function fn1(a, b, ...rest) {
//arguments获取所有实参 是类数组类型
// console.log(arguments)
//使用rest参数 是数组类型
console.log(rest);
//[3,4,5]
}
fn1(1, 2, 3, 4, 5)
}
{
// 封装一个函数,让函数计算所有实参的和
function sum(...rest) {
/* const re = rest.reduce(function (p, c) {
return p + c;
},0)
return re; */
return rest.reduce(function (p, c) {
return p + c;
}, 0)
}
console.log(sum(1, 2, 3, 4, 5, 6)) //21
}
{
var fn = (...rest) => {
return rest.reduce((p, c) => p + c)
}
console.log(fn(1, 2, 3, 4, 5, 6))
}
5-3.箭头函数
1.箭头函数格式
const {
log
} = console;
//1. 只有一个参数,并且函数体只有一个return
//参数写在 =>前 函数体写在=>后 如果函数体只有一个return 则直接书写return后的语句 并且省略大括号
/* function (a) {
return a + 1;
} */
const fn1 = a => a + 1;
console.log(fn1(1));
//2
//2.函数多个形参 或者没有形参
const fn2 = (a, b) => a + b;
log(fn2(1, 2));
//3
//3.当函数体有多句话 需要书写完整的函数体
const fn3 = () => console.log(1);
fn3();
const fn4 = () => {
let a = 1;
let b = 2;
console.log(a + b);
}
fn4();
//练习
/* function sum1(...rest) {
return rest.reduce(function (p, c) {
return p + c;
}, 0)
} */
const sum1 = (...rest) => rest.reduce((p, c) => p + c, 0);
console.log(sum1(1, 2, 3, 4, 5, 6)) //21
2.箭头函数this
/*
箭头函数:
this:箭头函数没有自己的this(他的this不能在不同的环境中发生改变),
箭头函数的this在定义的时候就已经确定了,在箭头函数中使用this,其实是定义的时候他所在父级函数的this
*/
const fn1 = () => console.log(this);
fn1(); //w
document.onclick = fn1; //w
const obj = {
name: "lily",
do: fn1
}
obj.do(); //w
const obj1 = {
name: "lily",
do: function () {
fn1();
}
}
obj1.do(); //w
const obj2 = {
name: "lily",
do: () => {
fn1();
}
}
obj2.do(); //w
const obj1 = {
name: "lily",
do: () => {
// this-->window
const fn1 = () => {
console.log(this); //window
}
fn1();
}
}
obj1.do()
const obj2 = {
name: "lily",
do: function () {
// this--obj2
const fn1 = () => {
console.log(this); //
}
fn1()
}
}
// obj2.do()
const fn3 = obj2.do;
fn3();
3.箭头函数其他注意
-
箭头函数不能当做构造函数
-
箭头函数没有arguments对象
//1.箭头函数不能当作构造函数
const fn1 = (name) => {
this.name = name
}
// new fn1(); //fn1 is not a constructor
//2.箭头函数没有arguments对象
const fn2 = (...rest) => {
console.log(rest)
// console.log(arguments); //arguments is not defined
}
fn2(1, 2, 3, 4, 5)
6.Math的扩展
** 次方
/*
Math的扩展
1.n次方 旧方法:Math.pow(); 新方法 : **运算符
*/
console.log(Math.pow(3, 3))
//27
console.log(3 ** 3)
//27
console.log(2 ** 10)
//1024
console.log(2 ** 1000)
//1.0715086071862673e+301
console.log(2 ** 2 ** 3) //2的8次方 从右向左计算
//256
进制
/*
进制表示:
二进制: 以 0b为开头
八进制:以0o开头
*/
let num1 = 0b110; //二进制
console.log(num1); //打印的时候是转换成了10进制
//6
let num2 = 010; //旧版本提供了定义八进制的写法 前边加一个0
console.log(num2);
//8
let num3 = 0o10; //新版本提供了定义八进制的写法 前边加一个0o
console.log(num3);
//8
Math.trunc()
- 将数字的小数部分去掉,只保留整数部分
/*
Math.trunc()方法会将数字的小数部分去掉,只保留整数部分
*/
console.log(Math.trunc(1.21)) //1
console.log(Math.trunc(-1.21)) //-1
console.log(Math.trunc("-1.21a")) //NaN
Math.sign()
- 判断一个数字是正数 负数 还是NaN
Math.sign() 判断一个数字的正数还是负数 还是0 或者是NaN
-返回值是-1 则代表负数
- 返回值是0 代表0
- 返回值是1 代表正数
console.log(Math.sign(-3))//-1
console.log(Math.sign(0))//0
console.log(Math.sign(4))//1
Math.sqwt()
- 平方根
Math.sqrt()平方根
console.log(Math.sqrt(2))//1.4142135623730951
Math.cbrt()
- 立方根
Math.cbrt()立方根
console.log(Math.cbrt(27))//3
Math.hypot()
- 求所有参数平方根的和
Math.hypot() 求所有参数平方和的平方根
console.log(Math.hypot(3, 4)) //5
7.Number扩展
Number.isFinite(i)
- 判断是否有最大的数
console.log(Number.isFinite(3)) //true
console.log(Number.isFinite(Infinity)) //false
Number.isNaN(i)
- 判断是否是NaN
console.log(isNaN("a")); //true 会转换成number 然后判断
console.log(Number.isNaN("a")); //false 如果是NaN就返回true
console.log(Number.isNaN(NaN)); //true 如果是NaN就返回true
Number.isInteger(i)
- 判断是否是整数
<script>
console.log(Number.isInteger(3));//true
console.log(Number.isInteger(3.1));//false
</script>
Number.parseInt(str)
- 将字符串转换为对应的数值
8.对象的扩展
8-1.对象的简写
1.属性的简写
let [name, age, sex] = ["xiaowang", 20, "女"];
let p1 = {
name: name,
age: age,
sex: sex
}
console.log(p1);
//在es6中,对象的key和value如果相同,则可以简写
let p2 = {
name,
age,
sex
}
console.log(p2);
2.方法的简写
//如果对象的key 和 value(必须是变量) 相同,则可以简写一个key即可
//函数不建议简写为箭头函数,而是省略function的简写
let [name, age, sex] = ["xiaowang", 20, "女"];
let p1 = {
name: name,
age: age,
sex: sex
}
console.log(p1);
let p3 = {
name,
age,
sex,
do: function () {
console.log("eat")
}
}
p3.do();
let p4 = {
name,
age,
sex,
do() {
console.log("eat")
}
}
p4.do();
8-2属性表达式
//假设变量a 保存的是obj的key值,
const a = "age";
//要把a保存的key值放入对象中
const obj = {
//对象不会把key解析为一个变量,因为key都是字符串
a: 18,
//当对象的key用变量保存的时候,使用时添加中括号,可以把变量解析
[a]: 19
}
console.log(obj)
//{a: 18, age: 19}
// 在ES6中,支持key发生变化
let a = "name";
let b = "sex";
let p6 = {
[a]: "laowang",
[b + "1"]: "nv"
}
console.log(p6)
1.特殊例子
//表达式还可以用于定义方法名
//属性名可以写变量了,但是对象的key值解析后永远是一个字符串
const o1 = {};
const o2 = {};
const obj1 = {
[o1]: 12,
[o2]: 13
}
console.log(obj1[o1]) //13
8-3.对象的扩展运算符
let { a, b, ...c } = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
}
console.log(c)
8-4.对象新增的方法
1.Object.is()
//Object.is 相当于 === 只不过修复了NaN不等NaN
console.log(Object.is(1, 1)) //true
console.log(Object.is(1, 2)) //false
console.log(Object.is(1, "1")) //false
console.log(Object.is({}, {})) //false
console.log(Object.is({}, [])) //false
console.log(Object.is(true, true)) //true
console.log(Object.is(undefined, null)) //false
console.log(Object.is(NaN, NaN)) //true
2.Object.assign()
const obj1 = {
a: 1,
b: 2,
}
const obj2 = {
c: 3,
d: 4
}
const obj3 = {
a: 5,
e: 6
}
//Object.assign是把后边的所有对象合并到第一个参数中去了,并没有创建一个新的对象
const re1 = Object.assign(obj1, obj2);
//{a: 1, b: 2, c: 3, d: 4}
console.log(re1 === obj1) //true
console.log(re1 === obj2) //false
//合并对象的时候,如果有重名的则会覆盖
const re2 = Object.assign(obj1, obj2, obj3);
//{a: 5, b: 2, c: 3, d: 4, e: 6}
console.log(re2);
3.赋值一个对象(浅拷贝)
//原始深拷贝和浅拷贝(让你复制一个对象)
const obj4 = {
a: 1,
b: 2,
c: {
d: 1
}
}
//浅拷贝一份obj4
const obj5 = {};
for (let key in obj4) {
obj5[key] = obj4[key]; //如果是基本类型值,则直接赋值,如果是引用类型值,则把地址赋值过去了
}
console.log(obj5 === obj4) //false
console.log(obj5.c === obj4.c) //true
4.assign()的拷贝作用
//Object.assign()的拷贝作用
const obj6 = {
a: 1,
b: 2,
c: {
d: 1
}
}
const obj7 = Object.assign({}, obj6); //把Obj6合并到空对象中,就得到一次拷贝(浅拷贝)
console.log(obj7 === obj6); //false
console.log(obj7.c === obj6.c); //true
9.新增数据类型
/*
js数据类型:
基本:String Boolean Number Null Undefined Symbol BigInt
引用:Object
*/
const obj1 = {
name: "laowang",
age: 18,
sex: "nv",
do: "eat",
think: "PhP是不是世界上最好的语言",
}
//obj1对象可能你不知道里边会有哪些属性
//当你需求给对象设置一些属性和方法的时候,可能重名覆盖其他的属性,或者可能被其他人覆盖你的属性
obj1.do = "drink";
//你可以能覆盖原有属性,也可能被人覆盖
{name: "laowang", age: 18, sex: "nv", do: "drink", think: "PhP是不是世界上最好的语言"}
//为了避免上边的情况,我们希望设置一个独一无二的值,永远不可能覆盖别人,也永远不可能被人覆盖
//所以symbol类型诞生,symbol类型每次创建的值都是独一无二的
9-1.Symbol
创建Symbol()
//1.使用symbol创建一个值(不需要new)
//Symbol的参数,没有任何作用,只是为了方便我们识别是哪一个值
const sy1 = Symbol("sy1");
const sy2 = Symbol("sy2");
console.log(sy1);
// Symbol(sy1)
console.log(sy2);
// Symbol(sy2)
console.log(sy1 == sy2); //false
console.log(typeof sy1) //'symbol'
使用Symbol()
//给obj1扩展一个属性(不能覆盖别人 也不能被人覆盖)
/* obj1[Symbol("think")] = "hello"; //如果这样设置的话,你永远都获取不到设置的这个值了
obj1[Symbol("say")] = "world";
console.log(obj1) */
const sy3 = Symbol("think");
const sy4 = Symbol("say");
obj1[sy3] = "hello";
obj1[sy4] = "world";
obj1[Symbol()] = "baibai";
console.log(obj1)
//使用
console.log(obj1[sy3]);
//hello
console.log(obj1[sy4]);
//world
// 1.Symbol传入的参数 没有意义 方便识别
//2.Symbol不能使用new调用,而是直接使用
//3.Symbol不能转数字
//4.要用变量保存这个Symbol 否则以后就拿不到了
//5.Symbol默认不能被遍历出来
for (let key in obj1) {
console.log(key);
}
Object.getOwnPropertySymbol()
const SymbolArr = Object.getOwnPropertySymbols(obj1); //拿到Symbol的值 组成一个数组
console.log(SymbolArr)
//[Symbol(think), Symbol(say), Symbol()]
console.log(SymbolArr[0])
//Symbol(think)
console.log(obj1[SymbolArr[0]])
//hello
//获取symbol 的值
console.log(obj1[SymbolArr[1]])
//world
console.log(obj1[SymbolArr[2]])
//baibai
//只有这样的遍历才能拿到 没有设置变量保存的Symbol的值
</script>
9-2.BigInt
- 大整形.定义方法:在数字后面添加一个n即可
//BigInt 大整型 一定是整数
console.log((2 ** 53)) //计算不精确
console.log((2 ** 53) + 1) //计算不精确
console.log((2 ** 53) + 3) //计算不精确
console.log(2 ** 1023) //计算不了
//大整型 定义方法 在数字后添加一个n即可
const bi1 = 1n;
console.log(bi1) //1n
console.log(typeof bi1); //"bigint"
console.log((2n ** 53n) + 1n) //计算精确
console.log(1n == 1) //true
console.log(1n === 1) //false
//类型转换和number区别不大
console.log(Number(1n)) //number 1
console.log(String(1n)) //string 1
console.log(Boolean(1n)) //true
console.log(Boolean(0n)) //false
10.新增数据结构
Set
new Set(arr)
/*
Set类型,类似于数组,里边的值没有重复的
需要使用new 实例化,实例化参数必须是一个拥有iterator接口的数据
*/
// 数组
const set1 = new Set([1, 2, 1, 2, 1, 2, 4, 3, 4, 5, 6, 2, 3, 4]);
console.log(set1);
//Set(6) {1, 2, 4, 3, 5, …}
new Set(string)
//字符串
const set2 = new Set('1212123566');
console.log(set2);
//Set(5) {"1", "2", "3", "5", "6"}
new Set(object)
//对象
/* const set3 = new Set({
//TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
name: 1,
age: 2
}) */
//
new Set(伪数组)
const oLis = document.querySelectorAll("ul li");
const set3 = new Set(oLis);
//NodeList(4) [li, li, li, li]
console.log(set3);
//Set(4) {li, li, li, li}
使用-数组去重
//使用:数组去重
const arr = [1, 2, 1, 2, 1, 2, 4, 3, 4, 5, 6, 2, 3, 4];
const set4 = new Set(arr);
console.log(set4) //set的格式
//Set(6) {1, 2, 4, 3, 5, …}
//set也是一个拥有iterator属性的类型,可以使用三点运算符展开
console.log(...set4)
//1 2 4 3 5 6
const newArr = [...set4];
console.log(newArr)
//(6) [1, 2, 4, 3, 5, 6]
使用-字符串去重
//字符串去重 set不能转字符串的话 可以借助于数组来进行转换
const str = "ababcdeehfhgd";
const set5 = new Set(str);
console.log(set5);
Set(8) {"a", "b", "c", "d", "e", …}
const strArr = [...set5];
console.log(strArr);
// ["a", "b", "c", "d", "e", "h", "f", "g"]
console.log(strArr.join(""));
//abcdehfg
console.log(String(set5))
//[object Set]
Set的方法
size
const {
log
} = console;
const arr = [1, 2, 1, 2, 1, 2, 4, 3, 4, 5, 6, 2, 3, 4];
const set4 = new Set(arr);
console.log(set4);
//Set(6) {1, 2, 4, 3, 5, …}
//size:长度
log(set4.size);
//6
add()
//add添加 返回添加后的set类型
set4.add(11);
const re1 = set4.add(2);
log(set4)
//Set(7) {1, 2, 4, 3, 5, …}
log(re1)
//Set(7) {1, 2, 4, 3, 5, …}
delete()
//delete 删除
const re2 = set4.delete(2);
console.log(re2)
//true
//返回值是 布尔值 代表是否删除成功
console.log(set4)
//Set(6) {1, 4, 3, 5, 6, …}
has()
//has()判断是否存在
console.log(set4.has(9)) //false
clear()
//clear清空
log(set4.clear())
//undefined clear没有返回值
log(set4) //被清空了
//Set(0) {}
entries()/key()/value()
//entries //set类型的key和value都是相等的
const re3 = set4.entries();
log(re3)
//SetIterator {1 => 1, 4 => 4, 3 => 3, 5 => 5, 6 => 6, …}
log(re3.next())
// {value: Array(2), done: false}
log(re3.next())
// {value: Array(2), done: false}
log(re3.next())
// {value: Array(2), done: false}
log(re3.next())
// {value: Array(2), done: false}
log(re3.next())
// {value: Array(2), done: false}
log(re3.next())
// {value: Array(2), done: false}
log(re3.next())
//{value: undefined, done: true}
for (let keys1 of re3) {
console.log(keys1)
/*
(2) [1, 1]
(2) [4, 4]
(2) [3, 3]
(2) [5, 5]
(2) [6, 6]
(2) [11, 11]
*/
}
//keys
const re4 = set4.keys();
log(re4)
//SetIterator {1, 4, 3, 5, 6, …}
//values
const re5 = set4.values();
log(re5)
//SetIterator {1, 4, 3, 5, 6, …}
for…of…
//set除了自身的entries keys values可以被forof遍历,自身也可以被遍历 得到一个value值
for (let values1 of set4) {
console.log(values1)
// 1 4 3 5 6 11
}
console.log(set4)
forEach()
//set也可以被forEach遍历
set4.forEach((item, index) => {
console.log(item, index);
/*
1 1
4 4
3 3
5 5
6 6
11 11
*/
})
小练习
//遍历100次 每次随机生成0-9的数字,看能不能把所有的1-10数字全部输出
const set5 = new Set();
for (let i = 0; i < 100; i++) {
set5.add(Math.floor(Math.random() * 10))
}
if (set5.size === 10) {
console.log("ok~")
} else {
console.log("no~")
}
console.log(set5)
Map
-
解决了对象中key必须被解析成字符串的问题
-
Map是一种类似于Object的数据结构,但是key可以使任意类型的值
new Map()
/*
Map类型:解决了对象中 key必须被解析成字符串的问题
Map是一种类似于Object的数据结构,但是key可以是任意类型的值
*/
const obj1 = {};
const obj2 = {
a: 1
};
const map1 = new Map([
["name", "lily"],
["age", 18],
[obj1, "haha"],
[obj2, "hehe"],
[true, "heihei"],
[2, "gege"]
])
console.log(map1);
/*
Map(6) {"name" => "lily", "age" => 18, {…} => "haha", {…} => "hehe", true => "heihei", …}
[[Entries]]
0: {"name" => "lily"}
1: {"age" => 18}
2: {Object => "haha"}
3: {Object => "hehe"}
4: {true => "heihei"}
5: {2 => "gege"}
size: (...)
__proto__: Map
*/
size
//size:长度
console.log(map1.size);
//6
set()
//set设置
const arr = [1, 2, 3]
map1.set(arr, "shuzu")
console.log(map1)
/* Map(7) {"name" => "lily", "age" => 18, {…} => "haha", {…} => "hehe", true => "heihei", …}
[[Entries]]
0: {"name" => "lily"}
1: {"age" => 18}
2: {Object => "haha"}
3: {Object => "hehe"}
4: {true => "heihei"}
5: {2 => "gege"}
6: {Array(3) => "shuzu"}
size: (...)
__proto__: Map */
get()
//get 获取
const re1 = map1.get(obj1);
const re2 = map1.get(true);
console.log(re1);
//haha
console.log(re2);
//heihei
has()
//has 判断key是否存在
const re3 = map1.has([1, 2, 3]);
console.log(re3)
//false 地址值的比较
const re4 = map1.has(obj1);
console.log(re4)
//true 变量,保存的是地址
delete
//delete删除
map1.delete(obj2);
console.log(map1)
/*
Map(6) {"name" => "lily", "age" => 18, {…} => "haha", true => "heihei", 2 => "gege", …}
[[Entries]]
0: {"name" => "lily"}
1: {"age" => 18}
2: {Object => "haha"}
3: {true => "heihei"}
4: {2 => "gege"}
5: {Array(3) => "shuzu"}
size: (...)
__proto__: Map
*/
clear()
//clear清空
/* map1.clear();
console.log(map1)
//Map(0) {}
*/
entries()/key()/value()
//entries
const re5 = map1.entries();
console.log(re5);
//MapIterator {"name" => "lily", "age" => 18, {…} => "haha", true => "heihei", 2 => "gege", …}
for (let values1 of re5) {
console.log(values1)
}
//keys
const re6 = map1.keys();
//MapIterator {"name", "age", {…}, true, 2, …}
for (let values1 of re6) {
console.log(values1)
/*
name
age
{}
true
2
(3) [1, 2, 3]
*/
}
//values
const re7 = map1.values();
for (let values1 of re7) {
console.log(values1)
/*
lily
18
haha
heihei
gege
*/
}
for…of…
//map也可以自己使用forof
for (let values1 of map1) {
console.log(values1);
}
forEach
//forEach
map1.forEach((item, index) => {
console.log(item, index)
/*
(2) ["name", "lily"]
(2) ["age", 18]
(2) [{…}, "haha"]
(2) [true, "heihei"]
(2) [2, "gege"]
(2) [Array(3), "shuzu"]
*/
})
11.iterator
1.手写iterator
<script>
const arr = ["a", "b", "c", "d"];
Array.prototype.myIterator = function () {
//声明一个累加器,用来判断遍历是否完成
let index = 0;
//原型对象的方法this指向实例化对象
//返回一个对象,对象中有next方法,可以依次拿到值
// console.log(this)
const _this = this; //保存当前的this指向,用来在其他地方使用
return {
// 调用next方法后返回一个对象:{value:XXX,done:false}
next: function () {
// console.log(this) //指向的是当前next所在的对象,不是当前的数组
if (index < _this.length) {
return {
value: _this[index++],
done: false
}
} else {
return {
value: undefined,
done: true
}
}
}
}
}
const re = arr.myIterator();
console.log(re)
console.log(re.next())
console.log(re.next())
console.log(re.next())
console.log(re.next())
console.log(re.next())
console.log(re.next())
console.log(re.next())
</script>
2.数据类型的iterator
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<script>
const oLis = document.querySelectorAll("ul li");
console.log(oLis)
// NodeList(4) [li, li, li, li]
//nodeList对象拥有Iterator接口
function fn1() {
console.log(arguments);
}
fn1(1, 2, 3, 4)
//Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//arguments 对象拥有Iterator接口
console.log([]); //Array 对象拥有Iterator接口
console.log(new Set()); //set 对象拥有Iterator接口
console.log(new Map([])); //Map 对象拥有Iterator接口
console.log(new String("123")) //String 对象拥有Iterator接口
console.log(new Number(1)); //number 没有Iterator接口
console.log({}); //Object 没有Iterator接口
//其实for of 就是对Iterator接口的消费
//手动获取它们的Iterator接口 模拟for of运行过程
const arr = ["a", "b", "c", "d"];
//凡是拥有iterator接口的对象,都有一个Symbol(Symbol.iterator)方法,调用这个方法即可得到遍历当前对象的迭代器对象
//直接通过arr的Symbol.iterator属性,获取获取到这个方法
const re = arr[Symbol.iterator](); //获取到了数组的迭代器对象
console.log(re);
//Array Iterator {}
console.log(re.next());
// {value: "a", done: false}
console.log(re.next());
// {value: "b", done: false}
console.log(re.next());
// {value: "c", done: false}
console.log(re.next());
// {value: "d", done: false}
console.log(re.next());
// {value: undefined, done: true}
console.log(re.next());
//{value: undefined, done: true}
</script>
3.for…of…
遍历NodeList
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<script>
/*
for of 是ES6提供的对数据结构统一的遍历方式
只要是部署了Iterator接口了类型,全部都可以使用for of 进行遍历迭代
for of遍历拿到的是 value 而不是key
*/
const oLis = document.querySelectorAll("ul li");
console.log(oLis) //nodeList对象拥有Iterator接口
//NodeList(4)
for (let value of oLis) {
console.log(value);
}
/* for (let i in oLis) {
console.log(i);
0
1
2
3
length
item
entries
forEach
keys
values
} */
遍历arguments
function fn1() {
console.log(arguments);
// Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
for (let value of arguments) {
console.log(value); // 1 2 3 4
}
}
fn1(1, 2, 3, 4) //arguments 对象拥有Iterator接口
遍历Array
const arr = ["a", "b", "c", "d"]
console.log(arr); //Array 对象拥有Iterator接口
//(4) ["a", "b", "c", "d"]
for (let value of arr) {
console.log(value);
/*
a
b
c
d
*/
}
for (let value of arr.entries()) {
console.log(value);
/*
(2) [0, "a"]
[1, "b"]
[2, "c"]
[3, "d"]
*/
}
遍历Set
const set = new Set(["a", "b", "c", "e"])
console.log(set); //set 对象拥有Iterator接口
//Set(4) {"a", "b", "c", "e"}
for (let value of set) {
console.log(value);
// a b c e
}
遍历Map
const map1 = new Map([
[{}, "haha"],
[true, "hehe"]
])
console.log(map1);
//Map(2) {{…} => "haha", true => "hehe"}
//Map 对象拥有Iterator接口
for (let value of map1) {
console.log(value);
/*
(2) [{…}, "haha"]
(2) [true, "hehe"]
*/
}
遍历String
const str = "123";
console.dir(new String("123")) //String 对象拥有Iterator接口
for (let value of str) {
console.log(value);
// 1 2 3
}
number和object没有
// console.log(new Number(1)); //number 没有Iterator接口
const obj = {
name: "laoli",
age: 18
}
console.log(obj); //Object 没有Iterator接口
for (let value of obj) {
console.log(value); //obj is not iterable
}
//
12.class
<script>
/*
ES5定义类
*/
/* function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.eat = function () {
console.log("吃饭");
} */
/*
ES6语法糖
使用class 定义类
*/
class Person {
//constructor:当new的时候,会自动调用这个方法,必须存在(书写公有属性)
constructor(name, age) {
//其实写在构造函数中的属性 都放在了constructor中
this.name = name;
this.age = age;
}
//直接书写在class中的方法 其实就是原型对象上的公有方法
eat() {
console.log("吃饭");
}
//如果直接在class中书写属性,则还是实例化对象所有的(这样写无法传参)
sex = "男";
// static定义的属性和方法 其实都是静态属性和方法 是构造函数对象上的
static hi = "hello";
}
//也可以通过原型对象扩展原型方法
Person.prototype.drink = function () {
console.log("大乌苏");
}
const p1 = new Person("laowang", 20)
const p2 = new Person("xiaowang", 10)
console.log(p1, p2)
//Person {sex: "男", name: "laowang", age: 20}age: 20name: "laowang"sex: "男"__proto__: Object Person {sex: "男", name: "xiaowang", age: 10}
console.log(p1.eat === p2.eat)
//true
console.dir(Person)
// class Person
</script>