当前位置: 首页 > news >正文

JavaScript高阶班之ES6 → ES11(八)

JavaScript高阶班之ES6 → ES11

  • 1、ES6新特性
    • 1.1、let 关键字
    • 1.2、const关键字
    • 1.3、变量的解构赋值
      • 1.3.1、数组的解构赋值
      • 1.3.2、对象的解构赋值
    • 1.4、模板字符串
    • 1.5、简化对象写法
    • 1.6、箭头函数
    • 1.7、函数参数默认值
    • 1.8、rest参数
    • 1.9、spread扩展运算符
      • 1.9.1、数组合并
      • 1.9.2、数组的克隆
      • 1.9.3、将伪数组转为真正的数组
      • 1.9.4、对象合并
    • 1.9.5、对象的克隆
  • 2、Symbol
    • 2.1、Symbol的创建
    • 2.2、不能与其他数据进行运算
    • 2.3、7种数据类型记忆
    • 2.4、Symbol的应用
      • 2.4.1、Symbol作为属性名
      • 2.4.2、Symbol属性名的遍历
      • 2.4.3、Symbol.for() 和 Symbol.keyFor()
    • 2.5、Symbol 内置值
  • 3、迭代器
    • 3.0、数组的常用方法
    • 3.1、数组的遍历
    • 3.2、对象的遍历
    • 3.3、数组和对象之间的转换
    • 3.4、迭代器
  • 4、生成器函数
  • 5、Promise
    • 5.1、Promise封装读取文件
    • 5.2、Promise封装Ajax
    • 5.3、Promise.then方法
    • 5.4、Promise.catch方法
  • 6、Set
    • 6.1、Set集合实践
  • 7、Map

参考视频: 尚硅谷Web前端ES6教程,涵盖ES6-ES11
配套代码: https://gitee.com/Augenstern-creator/kuang-study-es6
在这里插入图片描述

1、ES6新特性

1.1、let 关键字

let关键字用来声明变量,使用 let声明的变量有几个特点:

  1. 不允许重复声明
//1. 变量不能重复声明
let star = '大林';
let star = '小林';  		// 报错
  1. 块级作用域(包括 if、else、while、for所形成的括号)
//2. 块儿级作用域
{let girl = '秦xx';
}
console.log(gril);		// 报错
  1. 不存在变量提升
//3. 不存在变量提升
console.log(song);		// 报错
let song = '恋爱达人';
  1. 不影响作用域链
//4. 不影响作用域链
{let school = '尚硅谷';function fn(){console.log(school);}fn();	// 尚硅谷
}

应用场景:以后声明变量使用 let 就对了

1.2、const关键字

const 关键字用来声明常量, const声明有以下特点

  1. 声明必须赋初始值
//1. 一定要赋初始值
const A;		// 报错
  1. 标识符一般为大写
//2. 一般常量使用大写(潜规则)
const A = 100;
  1. 不允许重复声明
const SCHOOL = '尚硅谷';
const SCHOOL = 'ZZU';		// 报错
  1. 值不允许修改
//声明常量
const SCHOOL = '尚硅谷';
//3. 常量的值不能修改
SCHOOL = 'ATGUIGU';			// 报错
  1. 块儿级作用域
//4. 块儿级作用域
{const PLAYER = 'UZI';
}
console.log(PLAYER);		// 报错!
  1. 对于数组和对象的元素修改,不算作对常量的修改,不会报错
const TEAM = ['UZI','MXLG','Ming','Letme'];
TEAM.push('Meiko');				// 不报错

注意: 对象属性修改和数组元素变化不会触发 const错误

应用场景:声明对象类型使用const,非对象类型声明选择 let

1.3、变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。

1.3.1、数组的解构赋值

  • 语法:数据的解构使用方括号 []
//1. 数组的结构
const F4 = ['小沈阳','刘能','赵四','宋小宝'];
let [xiao, liu, zhao, song] = F4;
console.log(xiao);	//小沈阳
console.log(liu);	//刘能
console.log(zhao);	//赵四
console.log(song);	//宋小宝

1.3.2、对象的解构赋值

  • 语法:对象的解构使用大括号 {}
//2. 对象的解构
const zhao = {name: '赵本山',age: '不详',xiaopin: function(){console.log("我可以演小品");}
};let {name, age, xiaopin} = zhao;
console.log(name); // 赵本山
console.log(age); // 不详
console.log(xiaopin); // [Function: xiaopin]
xiaopin(); // 我可以演小品// 复杂解构
let wangfei = {name: "王菲",age: 18,songs: ['红豆','流年','暧昧','传奇'],history: [{name : '窦唯'},{name: '李亚鹏'},{name: '谢霆锋'}]
};let {songs: [one,two,three], history: [first,second,third]} = wangfei;console.log(one);   // 红豆
console.log(two);   // 流年
console.log(three); // 暧昧
console.log(first); // { name: '窦唯' }
console.log(second); // { name: '李亚鹏' }
console.log(third); // { name: '谢霆锋' }

在这里插入图片描述

  • 我们一般解构对象中的属性比较少,更多的是解构对象中的方法,使用如下:
let {xiaopin} = zhao;
xiaopin();

注意:频繁使用对象方法、数组元素,就可以使用解构赋值形式

1.4、模板字符串

模板字符串是增强版的字符串,用反引号 ` 标识,特点:

  1. 字符串中可以出现换行符
//1. 声明
let str1 = `我也是一个字符串哦!`;
console.log(str1, typeof str1);
// 我也是一个字符串哦! string//2. 内容中可以直接出现换行符
let str2 = `<ul><li>沈腾</li><li>玛丽</li><li>魏翔</li><li>艾伦</li></ul>`;
console.log(str2);
  1. 可以使用 ${xxx} 形式输出变量
//3. 变量拼接
let lovest = '魏翔';
let out = `${lovest}是我心目中最搞笑的演员!!`;
console.log(out);
// 魏翔是我心目中最搞笑的演员!!

在这里插入图片描述

注意:遇到字符串与变量拼接的情况使用模板字符串

1.5、简化对象写法

**ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。**这样的书写更加简洁

let name = '尚硅谷';
let age = 20;// 原始写法
const school1 = {name: name,age: age,change: function() {console.log('我们可以改变你!!');},improve: function() {console.log('我们可以提高你!!');}
}// ES6 写法
const school2 = {name,age,change() {console.log('我们可以改变你!!');},improve() {console.log("我们可以提高你的技能");}
}

注意:对象简写形式简化了代码,所以以后用简写就对了

1.6、箭头函数

ES6 允许使用 箭头 => 定义函数

// 声明一个函数原始写法
let fn = function(){}
// 声明函数箭头函数写法
let fn = (a,b) => {return a + b;
}// 调用函数
let result = fn(1, 2);
console.log(result);

箭头函数的注意点

  1. 如果形参只有一个,则小括号可以省略
let add = (n) => {return n + n;
}
console.log(add(9));// 省略小括号
let add = n => {return n + n;
}
  1. 函数体如果只有一条语句,则花括号可以省略(省略花括号, return 语句也必须要省略),函数的返回值为该条语句的执行结果
// 函数体如果只有一条语句,则省略花括号和return语句
let pow1 = (n) => {return n * n;
}
console.log(pow1(9));// 省略花括号
let pow2 = n => n * n;console.log(pow2(9));
  1. 箭头函数 this 指向声明时所在的作用域下 this 的值
//1. this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值
function getName() {console.log(this.name);
}
let getName2 = () => {console.log(this.name);
}//设置 window 对象的 name 属性
window.name = '尚硅谷';
const school = {name: "ATGUIGU"
}//直接调用
getName();
getName2();//call 方法调用
getName.call(school);
getName2.call(school);

在这里插入图片描述

  1. 箭头函数不能作为构造函数实例化
//4. 箭头函数不能作为构造实例化对象
let Person = (name, age) => {this.name = name;this.age = age;
}
let me = new Person('xiao',30);
console.log(me);	 // Person is not a constructor
  1. 不能使用 arguments
//5. 不能使用 arguments 变量
let fn = () => {console.log(arguments);
}
fn(1,2,3);	// arguments is not defined

注意:箭头函数不会更改 this 指向,用来指定回调函数会非常合适

1.7、函数参数默认值

ES6允许给函数参数赋值初始值

  1. 形参初始值,具有默认值的参数,一般位置要靠后(潜规则)
// 1. 形参初始值 具有默认值的参数, 一般位置要靠后(潜规则)
function add(a,c=10,b) {return a + b + c;
}
let result = add(1,2);
console.log(result);
  1. 与解构赋值结合
//原始写法
function connect (options){let host = options.host;let username = options.username;let password = options.password;let port = options.password;
}// 调用 connect 方法,向里面传个对象
connect({host: 'atguigu.com',username: 'root',password: 'root',port: 3306
})
// 与解构赋值结合写法
function connect({host="127.0.0.1", username,password, port}){console.log(host)console.log(username)console.log(password)console.log(port)
}// 调用 connect 方法,向里面传个对象
connect({username: 'root',password: 'root',port: 3306
})

1.8、rest参数

ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments

  1. rest 作用与 arguments 相似
function add(...args){console.log(args);
}
add(1,2,3,4,5);
  1. rest 参数必须是最后一个形参
function minus(a,b,...args){console.log(a,b,...args);
}
minus(100,1,2,3,4,5,19);

注意:rest参数非常适合不定个数参数函数的场景

1.9、spread扩展运算符

没有扩展运算符的时候,只能组合使用 push,splice,concat 等方法,将已有数组元素变成新数组的一部分。 有了扩展运算符, 构造新数组会变得更简单、更优雅。扩展运算符也是三个点(…)。 它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。

// 展开数组
console.log(...[1,2,3]);
// 1 2 3
console.log(1,...[2,3,4],5)
// 1 2 3 4 5
console.log([1,...[2,3,4],5])
// [1, 2, 3, 4, 5]

1.9.1、数组合并

//1. 数组的合并
const kuaizi = ['王太利', '肖央'];
const fenghuang = ['曾毅', '玲花'];// ES5数组合并写法
const zuixuanxiaopingguo1 = kuaizi.concat(fenghuang);
console.log(zuixuanxiaopingguo1);
// [ '王太利', '肖央', '曾毅', '玲花' ]// ES6扩展运算符数组合并
const zuixuanxiaopingguo2 = [...kuaizi, ...fenghuang];
console.log(zuixuanxiaopingguo2);
// [ '王太利', '肖央', '曾毅', '玲花' ]

在这里插入图片描述

1.9.2、数组的克隆

let arr = [1, 2, 3];
let arr2 = [...arr]; // [1, 2, 3]
arr2.push(4);
console.log(arr2); // [1, 2, 3, 4]// 数组含空位
let arr3 = [1, , 3],arr4 = [...arr3];
console.log(arr4); // [1, undefined, 3]
  • 这里是浅拷贝

1.9.3、将伪数组转为真正的数组

<body><div></div><div></div><div></div><script>//3. 将伪数组转为真正的数组const divs = document.querySelectorAll('div'); //获取到的是一个伪数组console.log(divs);const divArr = [...divs];console.log(divArr);</script>
</body>

在这里插入图片描述

1.9.4、对象合并

let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name};
console.log(person);  // {age: 15, name: "Amy"}

1.9.5、对象的克隆

var obj1 = { foo: 'bar', x: 42 };
var clonedObj = { ...obj1 };
console.log(clonedObj); // { foo: "bar", x: 42 } 

2、Symbol

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值,它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。

  1. Symbol 的值是唯一的,用来解决命名冲突的问题
  2. Symbol 值不能与其他数据进行运算
  3. Symbol 定义的对象属性不能使用 for…in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名

2.1、Symbol的创建

  • Symbol()
    • Symbol 前面不能加new关键字,直接调用即可创建一个独一无二的 symbol 类型的值。
let s = Symbol();
console.log(s,typeof s);
// Symbol() symbol
  • Stmbol(‘字符串’)
    • 这里的字符串只是一个描述,对于返回的结果也不是固定的(有两个张三,但是两个张三的编号是不一样的)
// 创建 Symbol 的时候,可以添加一个描述
const sym = Symbol('foo');
// sym.description 可以直接返回 Symbol 的描述
console.log(sym.description); // foolet s2 = Symbol('张三');
let s3 = Symbol('张三');
// 没有两个 Symbol 的值是相等的
console.log( s2 === s3);	//false
  • Symbol.for(‘字符串’)
    • 通过这样的方式创建 Symbol,可以通过字符串返回一个固定的 Symbol 值
let s4 = Symbol.for('尚硅谷');
let s5 = Symbol.for('尚硅谷');console.log(s4 === s5);	// true

2.2、不能与其他数据进行运算

//不能与其他数据进行运算
//    let result = s + 100;
//    let result = s > 100;
//    let result = s + s;

2.3、7种数据类型记忆

口诀:USONB == you are so niubiility

U == undefined

S == string symbol

o == object

n == null number

b == boolean

2.4、Symbol的应用

2.4.1、Symbol作为属性名

在 ES6 中,对象的属性名支持表达式,所以你可以使用一个变量作为属性名,这对于一些代码的简化很有用处,但是表达式必须放到方括号内

let prop = "name";
const obj = {// 使用表达式作为属性名,需要加方括号[prop]: "liao"
};
console.log(obj.name); // 'liao'

了解了这个新特性后,我们接着学习。symbol 值可以作为属性名,因为 symbol 值是独一无二的,所以当它作为属性名时,不会和其他任何属性名重复:

let name = Symbol();
let obj = {[name]: "liao"
};
console.log(obj); // { Symbol(): 'liao' }

打印出来的对象有一个属性名是 symbol 值。如果我们想访问这个属性值,不能使用 . 点的方式,而是必须使用方括号的形式:

console.log(obj[name]); // 'liao'
console.log(obj.name); // undefined
  • Symbol 作为属性名的时候,需要把 Symbol 使用 [] 包裹

2.4.2、Symbol属性名的遍历

使用 Symbol 类型值作为属性名,这个属性不会被for…in遍历到,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()获取到

  • Object.keys() :获取所有的属性名 key
  • Object.getOwnPropertyNames() :获取所有的属性名 key
  • JSON.stringify() :获取所有的属性名key和属性值value
const obj1 = {name: "林晓",age: 18,salary: 30000,
};for (const key in obj1) {// 遍历属性名 keyconsole.log(key);/***   nameagesalary*/
}// 获取所有的属性名 key
console.log(Object.keys(obj1));
// [ 'name', 'age', 'salary' ]// 获取所有的属性名 key
console.log(Object.getOwnPropertyNames(obj1));
// [ 'name', 'age', 'salary' ]// 获取所有的属性名key和属性值value
console.log(JSON.stringify(obj1));
// {"name":"林晓","age":18,"salary":30000}
  • 我们可以使用下面两个方法获取对象的所有symbol类型的属性名
    • Reflect.ownKeys 新的API
    • Object.getOwnPropertySymbols
/*** 但是如果是 Symbol 属性名*/
const salary = Symbol("salary");
const name = Symbol("name");
const obj = {[name]: "林晓",age: 18,[salary]: 30000,
};// age 只能拿到 key,拿不到Symbol类型的 name 属性名
for (const key in obj) {console.log(key);
}// 获取到obj对象里面的所有 Symbol 属性名
const SymbolPropNames = Object.getOwnPropertySymbols(obj);
console.log(SymbolPropNames); // [ Symbol(name), Symbol(salary) ]
// 获取第一个 Symbol 类型的属性值
console.log(obj[SymbolPropNames[0]]); // 林晓
// 获取第二个 Symbol 类型的属性值
console.log(obj[SymbolPropNames[1]]); // 30000// 新的api: Reflect.ownKeys()
console.log(Reflect.ownKeys(obj)); // [ 'age', Symbol(name), Symbol(salary) ]

2.4.3、Symbol.for() 和 Symbol.keyFor()

Symbol 包含两个静态方法,forkeyFor

const s1 = Symbol("liao");
const s2 = Symbol("liao");
const s3 = Symbol.for("liao");
const s4 = Symbol.for("liao");
console.log(s1 === s3); // false
console.log(s3 === s4); // true
  • 直接使用 Symbol 方法,即便传入的字符串是一样的,创建的 symbol 值也是互不相等的
  • 而使用 Symbol.for方法传入字符串,会先检查有没有使用该字符串调用 Symbol.for 方法创建的 symbol 值,如果有,返回该值,如果没有,则使用该字符串新创建一个。
// Symbol.keyFor() 方法传入一个 symbol 值,返回该值在全局注册的键名
const sym = Symbol.for("liao");
console.log(Symbol.keyFor(sym)); // 'liao'

2.5、Symbol 内置值

除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。

Symbol.hasInstance当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法
Symbol.isConcatSpreadable对象的 Symbol.isConcatSpreadable属性 等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。
Symbol.species创建衍生对象时,会使用该属性
Symbol.match当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。
Symbol.replace当该对象被 str.replace(myObject) 方法调用时,会返回该方法的返回值。
Symbol.search当该对象被 str. search (myObject) 方法调用时,会返回该方法的返回值。
Symbol.split当该对象被 str. split (myObject) 方法调用时,会返回该方法的返回值。
Symbol.iterator对象进行 for…of 循环时,会调用 Symbol.iterator方法,返回该对象的默认遍历器
Symbol.toPrimitive该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
Symbol. toStringTag在该对象上面调用 toString 方法时 ,返回该方法的返回值
Symbol. unscopables该对象指定了使用 with 关键字时,哪些属性会被 with环境排除。

3、迭代器

迭代器(Iterator) 就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。

  1. ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
  2. 原生具备 iterator 接口的数据(可用 for of 遍历)
    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypedArray
    • NodeList

3.0、数组的常用方法

这里先简单介绍下数组的常用方法:

  1. 改变原数组的方法:
// 1、push() : 数组末尾添加数据,返回数组的长度
var arr = [10, 20, 30, 40]
res = arr.push(20)
console.log(arr);//[10,20,30,40,20]
console.log(res);//5// 2、pop():数组末尾弹出数据
var arr = [10, 20, 30, 40]
res =arr.pop()
console.log(arr);//[10,20,30]
console.log(res);//40// 3、unshift(): 数组头部添加数据,返回数组的长度
var arr = [10, 20, 30, 40]
res=arr.unshift(99)
console.log(arr);//[99,10,20,30,40]
console.log(res);//5// 4、shift():数组头部删除数据,返回删除的那个数据
var arr = [10, 20, 30, 40]
res=arr.shift()
console.log(arr);[20,30,40] // [ 20, 30, 40 ]
console.log(res);// 10// 5、reverse():翻转数组,返回翻转的数据
var arr = [10, 20, 30, 40]
res=arr.reverse()
console.log(arr);//[40,30,20,10]
console.log(res);//[40,30,20,10]// 6、sort(): 排序
var arr = [1,3,5,7,9,10]
console.log(arr.sort()); // 默认排序顺序为按字母升序,所以通常不准确
// 正序排列
arr.sort(function(a,b){return(a-b)})
console.log(arr); // [1,3,5,7,9,10]
// 倒序排列
arr.sort(function(a,b){return(b-a)})
console.log(arr);// [ 10, 9, 7, 5, 3, 1 ]// 7、splice(开始的索引,截取几个): 截取数组,返回截取出来的数据
var arr = [1,3,5,7,9,10]
res = arr.splice(1,2) // 从索引1开始,截取2个数据
console.log(arr); // [ 1, 7, 9, 10 ]
console.log(res); // [ 3, 5 ]//splice(开始的索引,截取几个,你要插入的数据) : 删除并插入数据
var arr = [1,3,5,7,9,10]
res = arr.splice(1,1,999,888) // 从索引1开始,截取1个数据删除,并插入999,888
console.log(arr);  // [1, 999, 888, 5,7,9,10]
console.log(res);  // [ 3 ]
  1. 不改变原数组的方法
// 1、concat(): 合并数据
var arr = [10, 20, 10, 30, 40, 50, 60]
res = arr.concat(20,"小敏",50)
console.log(arr) // [10, 20, 10, 30, 40, 50, 60,20,"小敏",50]
console.log(res);// [10, 20, 10, 30, 40, 50, 60,20,"小敏",50]//2、join(): 数组转字符串
var arr = [10, 20, 10, 30, 40, 50, 60]
res = arr.join("+")
console.log(arr) // 数组不改变 [10, 20, 10, 30, 40, 50, 60]
console.log(res); // 10+20+10+30+40+50+60
console.log(typeof res); //string//3、slice(开始索引,结束索引): 截取数组的一部分数据,返回截取的数据,前闭后开 [ ),
var arr = [10, 20, 10, 30, 40, 50, 60]
res = arr.slice(1,4)
console.log(arr) // 数组不改变 [10, 20, 10, 30,40, 50, 60]
console.log(res);// [ 20, 10, 30 ]//4、indexOf(数值):从左边开始检查数组中有没有这个数值,如果有就返回该数据第一次出现的索引
var arr = [10, 20, 10, 30, 40, 50, 60]
res = arr.indexOf(10)
console.log(arr) // 数组不改变 [10, 20, 10, 30,40, 50, 60]
console.log(res); // 返回第一次出现的索引 0//indexOf(数值,开始的索引)
var arr = [10, 20, 10, 30, 40, 50, 60]
res = arr.indexOf(10,1)
console.log(arr) // 数组不改变 [10, 20, 10, 30,40, 50, 60]
console.log(res); // 2//5、lastIndexOf(数值):从右边开始检查数组中有没有这个数值,如果有就返回该数据第一次出现的索引
  1. ES6新增的数组方法
//1、forEach(): 循环遍历数组
var arr = ['盖伦','德玛','大风车']
arr.forEach((item,index) => {// index 是数组下标,item是数组值console.log(index);console.log(item);
});// 2、map 加工数组
var arr = ['盖伦','德玛','大风车'];
var newArr = arr.map((item,index) => {console.log(index);console.log(item);return item + '111'
});
console.log(newArr); // [ '盖伦111', '德玛111', '大风车111' ]// 3、filter() 过滤数组
var arr = [1,2,3,4,5];
var newArr = arr.filter((item,index) => {return item > 2;
});
console.log(newArr); // [ 3, 4, 5 ]// 4、every() 判断数组是不是满足所有条件
var arr = [1, 2, 3, 4, 5]
var res = arr.every((item,index) => {return item > 0;
})
console.log(res);//打印结果  true// 6、find() 用来获取数组中满足条件的第一个数据
var arr = [1, 2, 3, 4, 5]
var res = arr.find((item,index) => {return item > 3;
})
console.log(res);//打印结果  4

3.1、数组的遍历

我们先看一下数组的遍历方式:

//声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];//使用 for...in 遍历数组
for (let i in xiyou) {// i 是数组的下标console.log(i);console.log(xiyou[i]);
}//使用 for...of 遍历数组
for (let v of xiyou) {console.log(v);/***   唐僧孙悟空猪八戒沙僧*/
}//forEach(): 循环遍历数组
var arr = ['盖伦','德玛','大风车']
arr.forEach((index,item) => {// index 是数组下标,item是数组值console.log(index);console.log(item);
});

3.2、对象的遍历

//对象
var test = {name : "zs",age: "18"
}// 遍历属性名和属性值
for(let key in test) {// key 是属性名console.log(key);console.log(test[key]);
}// 获取所有的属性名
console.log(Object.keys(test)); // [ 'name', 'age' ]// 获取所有的属性值
console.log(Object.values(test)); // [ 'zs', '18' ]

3.3、数组和对象之间的转换

  • 数组转换为对象
// 数组转对象
// 方法一:使用 spread 扩展运算符
const arr1 = ['one','two','three'];
const obj1 = {...arr1};
console.log(obj1);    // { 0: 'one', 1: 'tow', 2: 'three' }// 方法二:使用 foreach
const arr = [1,2,3,4,5];
let obj = {};arr.forEach((item,index) => {// index 是下标, item 是数组元素obj[index] = item;
})console.log(obj);     //{ 0: 1, 1: 2, 2: 3, 3: 4, 4: 5 }
  • 对象转换为数组

3.4、迭代器

为什么数据可以使用 for… of 遍历呢?因为数组具有一个属性 Symbol.iterator

//声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
console.log(xiyou);

在这里插入图片描述

注意:需要自定义遍历数据的时候,要想到迭代器

// 原理
//声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];//创建数组的迭代器
let iterator = xiyou[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next());//{ value: '唐僧', done: false }
console.log(iterator.next());//{ value: '孙悟空', done: false }
console.log(iterator.next());//{ value: '猪八戒', done: false }
console.log(iterator.next());//{ value: '沙僧', done: false }
console.log(iterator.next());//{ value: undefined, done: true }

在这里插入图片描述

4、生成器函数

生成器函数是 ES6 提供的一种异步编程解决方案,语法行为和传统函数完全不同。

/*** generator 生成器函数,可以通过 yield 关键字 , 将函数挂起* 和普通函数的区别* 1. function 后面,函数名之前有个星号 ** 2. 只能在函数内部使用 yield 表达式* 3. generator函数是分段执行的, yield 语句是赞同执行, next() 是恢复执行*/
function* func(){yield 2; // 调用一次 next 会执行到这yield 3; // 调用二次 next 会执行到这
}// 调用生成器函数,会返回一个迭代器对象,可以使用 next() 方法
let fn = func();
console.log(fn.next()); // { value: 2, done: false }
console.log(fn.next()); // { value: 3, done: false }
console.log(fn.next()); // { value: undefined, done: true }

代码说明:

  • * 星号的位置没有限制
  • 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到 yield 语句后的值
  • yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next 方法,执行一段代码
  • next 方法可以传递实参,作为 yield 语句的返回值

5、Promise

Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

//实例化 Promise 对象
// 参数是一个函数,函数的形参是 resolve 和 reject,resolve 可以改变 Promise的状态为成功,reject 可以改变Promise的状态为失败
const p = new Promise(function(resolve, reject) {//异步操作定时器setTimeout(function() {let data = '数据库中的用户数据';resolve(data);}, 1000);
});/*** 调用 promise 对象的 then 方法,then 方法接收两个参数,两个参数都是函数,成功的函数形参是value,失败函数的形参是reason* 上方 resolve 成功后,下面的 then 方法就是执行第一个函数的方法*/p.then(function(value) {console.log(value); // 数据库中的用户数据
}, function(reason) {console.error(reason);
})

在这里插入图片描述

我们在异步操作定时器里面获得数据之后,就可以调用 resolve 函数来改变 Promise 对象的状态,使得Promise 对象的状态为成功,成功之后我们可以调用 Promise 对象的 then 方法,then 方法接收两个参数,都是函数类型,成功的形参我们叫做 value,失败的形参我们叫做 reason,检测到 Promise 对象状态为成功,则执行 then 方法里面的第一个方法。

<script>//实例化 Promise 对象const p = new Promise(function(resolve, reject) {// 使用定期器来做一个异步任务的模拟setTimeout(function() {// let data = '数据库中的用户'// resolve(data)let err = '数据读取错误';reject(err);}, 1000);});//调用 promise 对象的 then 方法p.then(function(value) {console.log(value);}, function(reason) {console.error(reason);})
</script>

我们在异步操作定时器里面未能获得数据之后,调用 reject 函数来改变 Promise 对象的状态,使得 Promise 对象的状态为失败,失败之后我们可以调用 Promise 对象的 then 方法,检测到 Promise 对象状态为失败,则执行 then 方法里面的第二个方法。

在这里插入图片描述

如果Promise对象获取数据成功,则执行第一个回调函数,输出 value

如果Promise对象获取数据失败,则执行第二个回调函数,输出 reason

5.1、Promise封装读取文件

//1. 引入 fs 模块
const fs = require('fs');//2. 调用方法读取文件
// fs.readFile('./resources/为学.md', (err, data)=>{
//     //如果失败, 则抛出错误
//     if(err) throw err;
//     //如果没有出错, 则输出内容
//     console.log(data.toString());
// });//3. 使用 Promise 封装
const p = new Promise(function(resolve, reject){fs.readFile("./resources/为学.md", (err, data)=>{//判断如果失败if(err) reject(err);//如果成功resolve(data);});
});p.then(function(value){console.log(value.toString());
}, function(reason){console.log("读取失败!!");
});

5.2、Promise封装Ajax

<body><script>// 接口地址: https://api.apiopen.top/getJokeconst p = new Promise((resolve, reject) => {//1. 创建对象const xhr = new XMLHttpRequest();//2. 初始化xhr.open("GET", "https://api.apiopen.top/getJ");//3. 发送xhr.send();//4. 绑定事件, 处理响应结果xhr.onreadystatechange = function () {//判断if (xhr.readyState === 4) {//判断响应状态码 200-299if (xhr.status >= 200 && xhr.status < 300) {//表示成功resolve(xhr.response);} else {//如果失败reject(xhr.status);}}}})//指定回调p.then(function(value){console.log(value);}, function(reason){console.error(reason);});</script>
</body>

5.3、Promise.then方法

调用 then 方法,then 方法的返回结果是 Promise 对象,对象状态由回调函数的执行结果决定

  1. 如果回调函数中的返回结果是非 Promise 类型的属性
<body><script>const p = new Promise((resolve, reject) => {setTimeout(() => {resolve("获取数据成功");}, 1000)});//调用 then 方法  then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定//1. 如果回调函数中返回的结果是 非 promise 类型的属性, 状态为成功, 返回值为对象的成功的值const result = p.then(value => {console.log(value);return 123;}, reason => {console.warn(reason);})console.log(result);</script>
</body>

在这里插入图片描述

  1. 如果回调函数中的返回结果是 Promise 类型的属性
<body><script>const p = new Promise((resolve, reject) => {setTimeout(() => {resolve("获取数据成功");}, 1000)});//调用 then 方法  then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定//2. 如果回调函数中返回的结果是 promise 类型的属性,则then方法的返回状态由 promise 对象决定const result = p.then(value => {return new Promise((resolve, reject) => {resolve('ok');})}, reason => {console.warn(reason);})console.log(result);</script>
</body>

在这里插入图片描述

  1. 抛出错误
<body><script>const p = new Promise((resolve, reject) => {setTimeout(() => {resolve("获取数据成功");}, 1000)});//调用 then 方法  then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定//3.抛出错误const result = p.then(value => {//3. 抛出错误throw new Error('出错啦!');}, reason => {console.warn(reason);})console.log(result);</script>
</body>

在这里插入图片描述

所以 Promise.then 方法是可以链式调用的

p.then(value =>{},reason => {}).then(value =>{},reason => {})// 常用写法如下
p.then(value=>{}).then(value=>{});

5.4、Promise.catch方法

<body><script>const p = new Promise((resolve, reject)=>{setTimeout(()=>{//设置 p 对象的状态为失败, 并设置失败的值reject("出错啦!");}, 1000)});// p.then(function(value){}, function(reason){//     console.error(reason);// });p.catch(function(reason){console.warn(reason);});</script>
</body>

Promise.catch 就是 Promise.then 缺少第一个函数参数的语法糖,用then 就可以。

6、Set

  • Map的属性和方法

    • size 返回Set的元素个数

    • add 增加一个新元素,返回当前Set

    • has 检测Set中是否包含某个元素

    • clear 清空集合,返回 undefined

//声明一个 set集合
let s = new Set();
let s2 = new Set(['大事儿','小事儿','好事儿','坏事儿','小事儿']);
console.log(s2);// { '大事儿', '小事儿', '好事儿', '坏事儿' }
// 注意Set集合会有去重功能,所以s2的元素个数其实是4个// 元素个数
console.log(s2.size); // 4
// 添加新的元素
s2.add('喜事儿');
console.log(s2);  // { '大事儿', '小事儿', '好事儿', '坏事儿', '喜事儿' }
// 删除元素
s2.delete('坏事儿');
// 检测是否存在某个值
console.log(s2.has('糟心事')); // false
// 清空
s2.clear(); 
console.log(s2);// {}

6.1、Set集合实践

  1. 数组去重
let arr = [1,2,3,4,5,4,3,2,1];
//1. 数组去重
let result1 = new Set(arr); //此时result是一个集合,转化为数组只需要使用扩展运算符展开
console.log(result1); // { 1, 2, 3, 4, 5 }let result2 = [...new Set(arr)];
console.log(result2); // [ 1, 2, 3, 4, 5 ]

在这里插入图片描述

  1. 两个集合求交集
let arr = [1,2,3,4,5,4,3,2,1];
let arr2 = [4,5,6,5,6];
// 首先先对数组去重
let result = [...new Set(arr)];
let result2 = [...new Set(arr2)];

7、Map

  • ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。

  • 数据结构。它类似于对象,也是键值对的集合。 但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

  • Map也实现了iterator接口,所以可以使用 扩展运算符for…of…进行遍历。

  • Map的属性和方法

    • size 返回Map的元素个数
    • set 增加一个新元素,返回当前Map
    • get 返回键名对象的键值
    • has 检测Map中是否包含某个元素
    • clear 清空集合,返回 undefined
//创建一个空Map
let m = new Map();
//创建一个非空Map
let m2 = new Map([['name','林晓'],['age','21']
]);
//添加元素
m2.set('salary','30000');
//添加方法
m2.set('fighting', function(){console.log("加油!!");
});
console.log(m2);// 获取
console.log(m2.get('name'));
console.log(m2.get('age'));
console.log(m2.get('salary'));
console.log(m2.get('fighting'));// 删除
m2.delete('age');// 检查是否包含某元素
console.log(m2.has('age'));// 清除
m2.clear();

在这里插入图片描述

相关文章:

JavaScript高阶班之ES6 → ES11(八)

JavaScript高阶班之ES6 → ES11 1、ES6新特性1.1、let 关键字1.2、const关键字1.3、变量的解构赋值1.3.1、数组的解构赋值1.3.2、对象的解构赋值 1.4、模板字符串1.5、简化对象写法1.6、箭头函数1.7、函数参数默认值1.8、rest参数1.9、spread扩展运算符1.9.1、数组合并1.9.2、数…...

网页中嵌套网页制作方法

<!DOCTYPE html> <html> <head> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <meta charset"UTF-8"> <title>网页搜索</title> <style> body { ba…...

系统集成项目管理总结(笔记)

系统集成项目管理总结 基础知识 第一章 信息化知识 第二章 信息系统服务管理 第三章 系统集成专业技术 第四章 项目管理一般知识 第五章 立项管理 第六章 整体管理 第七章 范围管理 第八章 进度管理 第九章 成本管理 第十章 质量管理 第十一章 人力资源管理 第十二…...

如何给Nginx配置访问IP白名单

一、Nginx配置访问IP白名单 有时部署的应用需要只允许某些特定的IP能够访问&#xff0c;其他IP不允许访问&#xff0c;这时&#xff0c;就要设置访问白名单&#xff1b; 设置访问白名单有多种方式&#xff1a; 1.通过网络防火墙配置&#xff0c;例如阿里云/华为云管理平台 2.…...

【VIM】VIM配合使用的工具

6-1 课程总结-vim虐我千百遍&#xff0c;我待 vim 如初恋_哔哩哔哩_bilibili...

git你学“废”了吗?——git本地仓库的创建

git你学“废”了吗&#xff1f;——git本地仓库的创建&#x1f60e; 前言&#x1f64c;初识gitgit 本地仓库的创建1、基于centos7环境下 git的下载2、设置自己的用户名和邮箱 查看.git中的结构区分清楚版本库和工作区 查看git中的相关内容查看仓库的状态 总结撒花&#x1f49e;…...

AWS Lambda Golang HelloWorld 快速入门

操作步骤 以下测试基于 WSL2 Ubuntu 22.04 环境 # 下载最新 golang wget https://golang.google.cn/dl/go1.21.1.linux-amd64.tar.gz# 解压 tar -C ~/.local/ -xzf go1.21.1.linux-amd64.tar.gz# 配置环境变量 PATH echo export PATH$PATH:~/.local/go/bin >> ~/.bashrc …...

【C++】单例模式

文章目录 一. 介绍二. 饿汉模式三. 懒汉模式四. 饿汉模式和懒汉模式对比 一. 介绍 单例模式是属于设计模式的一种&#xff0c;那什么是设计模式呢&#xff1f; 设计模式&#xff08;Design Pattern&#xff09;是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总…...

【kubernetes】使用luakube访问kubernetes api

文章目录 1 kubernetes client2 luakube初体验3 luakube代码分析4 luakube包的调用5 lua相关5.1 self5.2 metatable5.2.1 使用metatable对table新增操作符5.2.2 使用metatable对table新增方法5.2.3 再探luakube 6 参考文档 1 kubernetes client 客户端列出了各种语言对应的访问…...

【算法分析与设计】贪心算法(下)

目录 一、单源最短路径1.1 算法基本思想1.2 算法设计思想1.3 算法的正确性和计算复杂性1.4 归纳证明思路1.5 归纳步骤证明 二、最小生成树2.1 最小生成树性质2.1.1 生成树的性质2.1.2 生成树性质的应用 2.2 Prim算法2.2.1 正确性证明2.2.2 归纳基础2.2.3 归纳步骤2.3 Kruskal算…...

Arm Cache学习资料大汇总

关键词&#xff1a;cache学习、mmu学习、cache资料、mmu资料、arm资料、armv8资料、armv9资料、 trustzone视频、tee视频、ATF视频、secureboot视频、安全启动视频、selinux视频&#xff0c;cache视频、mmu视频&#xff0c;armv8视频、armv9视频、FF-A视频、密码学视频、RME/CC…...

Docker 学习总结(79)—— Dockerfile 编写技巧总结

目标 更快的构建速度 更小的 Docker 镜像大小 更少的 Docker 镜像层 充分利用镜像缓存 增加 Dockerfile 可读性 让 Docker 容器使用起来更简单 总结 编写 .dockerignore 文件 容器只运行单个应用 将多个 RUN 指令合并为一个 基础镜像的标签不要用 latest 每个 RUN 指令后删除多…...

链表经典面试题(二)

返回中间结点 1.中间结点的题目2.中间结点的图文分析3.中间结点的基本代码4.中间结点的优化代码 1.中间结点的题目 2.中间结点的图文分析 方法1&#xff1a;先求整体长度&#xff0c;再除以2&#xff0c;所得到的就是中间结点 方法2&#xff1a;双指针法&#xff0c;快指针走两…...

89、Redis 的 value 所支持的数据类型(String、List、Set、Zset、Hash)---->Zset 相关命令

本次讲解要点&#xff1a; ** Set相关命令&#xff1a;是指value中的数据类型** 启动redis服务器&#xff1a; 打开小黑窗&#xff1a; C:\Users\JH>e: E:>cd E:\install\Redis6.0\Redis-x64-6.0.14\bin E:\install\Redis6.0\Redis-x64-6.0.14\bin>redis-server.exe …...

知识图谱02——使用python将信息录入neo4j

将文档传入chatgpt&#xff0c;生成对应的cypher语句 链接: https://pan.baidu.com/s/1Ny-ttbBSpqYEigwYiCWMeA?pwdc7sc 提取码: c7sc 使用命令行安装对应的包 pip install neo4jchatgpt生成出的txt文档中的内容如下&#xff1a; MERGE (Node1:Entity {name: 原始舱单提运单…...

greenDAO-Android轻量级快速ORM框架

官网 https://github.com/greenrobot/greenDAO 简介 greenDAO is a light & fast ORM for Android that maps objects to SQLite databases. Being highly optimized for Android, greenDAO offers great performance and consumes minimal memory. Home page, documen…...

结构型设计模式——组合模式

摘要 组合模式(composite pattern): 允许你将对象组合成树形结构来表现"整体/部分"层次结构. 组合能让客户以一致的方式处理个别对象以及对象组合。 一、组合模式的意图 将对象组合成树形结构来表示“整体/部分”层次关系&#xff0c;允许用户以相同的方式处理单独…...

40. 组合总和 II

给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含重复的组合。 示例 1: 输入: candidates [10,1,2,7,6,1,5…...

安卓玩机-----给app加注册码 app加弹窗 云注入弹窗

在对接很多工作室业务中有些客户需要在他们自带的有些app中加注册码或者验证码的需求。其实操作起来也很简单。很多反编译软件有自带的注入功能。例如注入弹窗。这个是需要对应的注册码来启动应用。而且是随机id。重新安装app后需要重新注册才可以继续使用&#xff0c;原则上可…...

NLP的不同研究领域和最新发展的概述

一、介绍 作为理解、生成和处理自然语言文本的有效方法&#xff0c;自然语言处理 &#xff08;NLP&#xff09; 的研究近年来迅速普及并被广泛采用。鉴于NLP的快速发展&#xff0c;获得该领域的概述和维护它是困难的。这篇博文旨在提供NLP不同研究领域的结构化概述&#xff0c;…...

1.物联网射频识别,RFID概念、组成、中间件、标准,全球物品编码——EPC码

1.RFID概念 RFID是Radio Frequency Identification的缩写&#xff0c;又称无线射频识别&#xff0c;是一种通信技术&#xff0c;可通过无线电讯号识别特定目标并读写相关数据&#xff0c;而无需与被识别物体建立机械或光学接触。 RFID&#xff08;Radio Frequency Identificati…...

MySQL函数与控制结构

MySQL数据库管理系统在数据存储和检索方面发挥着重要作用。除了基础的数据操作外,MySQL还提供了丰富的函数和控制结构来进行更复杂的数据处理。 本文将详细介绍如何在MySQL中使用begin-end语句块、自定义函数、以及各种控制语句。通过《三国志》游戏数据的实例将更深入地了解…...

【论文极速读】Prompt Tuning——一种高效的LLM模型下游任务适配方式

【论文极速读】Prompt Tuning——一种高效的LLM模型下游任务适配方式 FesianXu 20230928 at Baidu Search Team 前言 Prompt Tuning是一种PEFT方法&#xff08;Parameter-Efficient FineTune&#xff09;&#xff0c;旨在以高效的方式对LLM模型进行下游任务适配&#xff0c;本…...

如何在 Elasticsearch 中使用 Openai Embedding 进行语义搜索

随着强大的 GPT 模型的出现&#xff0c;文本的语义提取得到了改进。 在本文中&#xff0c;我们将使用嵌入向量在文档中进行搜索&#xff0c;而不是使用关键字进行老式搜索。 什么是嵌入 - embedding&#xff1f; 在深度学习术语中&#xff0c;嵌入是文本或图像等内容的数字表示…...

世界第一ERP厂商SAP,推出类ChatGPT产品—Joule

9月27日&#xff0c;世界排名第一ERP厂商SAP在官网宣布&#xff0c;推出生成式AI助手Joule&#xff0c;并将其集成在采购、供应链、销售、人力资源、营销、数据分析等产品矩阵中&#xff0c;帮助客户实现降本增效。 据悉&#xff0c;Joule是一款功能类似ChatGPT的产品&#xf…...

嵌入式Linux应用开发-基础知识-第十八章系统对中断的处理③

嵌入式Linux应用开发-基础知识-第十八章系统对中断的处理③ 第十八章 Linux系统对中断的处理 ③18.5 编写使用中断的按键驱动程序 ③18.5.1 编程思路18.5.1.1 设备树相关18.5.1.2 驱动代码相关 18.5.2 先编写驱动程序18.5.2.1 从设备树获得 GPIO18.5.2.2 从 GPIO获得中断号18.5…...

【Python】返回指定时间对应的时间戳

使用模块datetime&#xff0c;附赠一个没啥用的“时间推算”功能(获取n天后对应的时间 代码&#xff1a; import datetimedef GetTimestamp(year,month,day,hour,minute,second,*,relativeNone,timezoneNone):#返回指定时间戳。指定relative时进行时间推算"""根…...

微服务moleculer03

1. Moleculer 目前支持SQLite&#xff0c;MySQL&#xff0c;MariaDB&#xff0c;PostgreSQL&#xff0c;MSSQL等数据库&#xff0c;这里以mysql为例 2. package.json 增加mysql依赖 "mysql2": "^2.3.3", "sequelize": "^6.21.3", &q…...

[React] react-router-dom的v5和v6

v5 版本既兼容了类组件&#xff08;react v16.8前&#xff09;&#xff0c;又兼容了函数组件&#xff08;react v16.8及以后&#xff0c;即hook&#xff09;。v6 文档把路由组件默认接受的三个属性给移除了&#xff0c;若仍然使用 this.props.history.push()&#xff0c;此时pr…...

Linux命令(91)之mv

linux命令之mv 1.mv介绍 linux命令mv是用来移动文件或目录&#xff0c;并且也可以用来更改文件或目录的名字 2.mv用法 mv [参数] src dest mv常用参数 参数说明-f强制移动&#xff0c;不提示 3.实例 3.1.重命名文件1.txt为ztj.txt 命令&#xff1a; mv 1.txt ztj.txt …...

现在较为常用的网站开发技术/抖音关键词排名查询工具

在平常的开发中&#xff0c;我们经常会遇到JSONObject和Bean的互换&#xff0c;JSONArray和List<Bean>的互换&#xff0c;具体的操作可以看下面的小例子。 1 public class Test2 {3 public static void main(String args[])4 {5 User temp new User();6…...

免费企业建站源代码/百度搜索排名与点击有关吗

http://blog.csdn.net/jdsjlzx/article/details/40823025 https://www.2cto.com/kf/201609/550704.html [java] view plaincopy android的热点功能不可见&#xff0c;用了反射的技术搞定之外。 [java] view plaincopy Eclipse设置语言为utf-8才能查看中文注释 上代码&am…...

肥城 网站建设/关键词排名网站

经过一个多月的整合&#xff0c;作者的第一本电子书&#xff0c;程序人生上线了&#xff0c;读者可通过微信公众号&#xff1a;小小李童鞋回复关键字 程序人生 获取&#xff1b; 最后感谢各位朋友的支持&#xff1b;...

12306网站是学生做的/品牌推广案例

10月12日消息&#xff0c;美股周三平开&#xff0c;股市努力从昨日的大跌中收复失地。投资者在等待美联储最新会议纪要发布。 截止发稿&#xff0c;道琼斯工业平均指数报18,114.35点&#xff0c;下跌14.31点&#xff0c;跌幅为0.08%。标准普尔500指数报2,137.06点&#xff0c;上…...

宠物之家网站开发/武汉标兵seo

Ping这个命令是个使用频率极高的程序&#xff0c;用于确定本地主机是否能与另一台主机交换&#xff08;发送与接收&#xff09;数据报。根据返回的信息&#xff0c;我们就可以推断TCP/IP参数是否设置得正确以及运行是否正常。需要注意的是&#xff1a;成功地与另一台主机进行一…...

虚拟网站多少钱/石家庄百度搜索引擎优化

坐标系是gis的灵魂&#xff0c;坐标系问题在桌面版是个永恒的主题&#xff0c;下面将常见的坐标系问题以问答的形式列出来&#xff0c;希望对大家有所帮助。问&#xff1a;我这有2个不同坐标的shp要素&#xff0c;这2个要素是同一地理位置的&#xff0c;但是在arcmap中打开不能…...