0

0

全面掌握,ECMAScript的新特性

coldplay.xixi

coldplay.xixi

发布时间:2020-10-22 18:34:05

|

2203人浏览过

|

来源于juejin

转载

今天javascript栏目带大家认识ecmascript的新特性。

全面掌握,ECMAScript的新特性

ES6成为JavaScript的下一代标准后,标准委员会(TC39)在每年都会发布一个ES的新版本,每个版本里都引入了很多实用的新特性,在日常的项目开发中,如果我们掌握这些实用的新特性,将大大的提升开发效率,下面让我们全面的掌握这些ES的新特性吧~

Let 和Const

之前使用var来定义变量,为我们提供了新的方式
let用来声明变量,const用来声明常量。

如何使用

const TAG = "我是常量";let a;
a = 2;console.log(TAG, "a=" + a); //我是常量   a=2复制代码

四个特点

一、只在块级作用域内有效

let和const为JavaScript新增了块级作用域,通常情况下,{}包裹的代码拥有的作用域就是块级作用域,声明的变量或常量只在块级作用域内有效,外部不能访问。

if (true) { //外层块级作用域
  let a = 1;  const A = 1;  if (true) {   //内层块级作用域
    let a = 2;
  }  console.log(a,A); //(1)输出:1 , 1}console.log(a); //(2)Uncaught ReferenceError: a is not defined复制代码

上面有两个块级作用域,都声明了变量a,但外层块级作用域与内层块级作用域无关,所以(1)处输出的是外层的变量值1,(2)处访问了不在一个块级作用域定义的变量,所以会报错。

另外一个理解块级作用域的示例。

//for&#24490;&#29615;&#20307;&#20869;&#30340;&#23450;&#26102;&#22120;//&#22312;ES6&#20043;&#21069;&#65292;&#26159;&#27809;&#26377;&#22359;&#32423;&#20316;&#29992;&#22495;&#30340;&#65292;&#21464;&#37327;&#29992;var&#22768;&#26126;&#65292;&#30452;&#25509;&#25346;&#36733;&#22312;&#20840;&#23616;&#20316;&#29992;&#22495;&#19978;for (var i = 0; i < 3; i++) {  setTimeout(function () {    console.log(i); //3&#12289;3&#12289;3
  }, 100);
}//&#20351;&#29992;var&#22768;&#26126;&#65292;for&#21516;&#27493;&#25805;&#20316;&#20248;&#20808;&#20110;setTimeout&#24322;&#27493;&#25805;&#20316;&#65292;&#22312;&#24320;&#22987;&#25191;&#34892;setTimeout&#30340;&#26102;&#20505;&#65292;//for&#24490;&#29615;&#24050;&#32463;&#25191;&#34892;&#23436;&#65292;i&#20026;3&#65292;&#21017;&#21518;&#32493;&#27599;&#27425;setTimeout&#36755;&#20986;&#30340;i&#37117;&#26159;3//&#20351;&#29992;let&#22768;&#26126;&#30340;&#35805;&#65292;&#21017;&#20250;&#22312;&#24490;&#29615;&#20307;&#20869;&#37096;&#24418;&#25104;&#38381;&#21253;&#65292;&#27599;&#27425;for&#24490;&#29615;&#37117;&#20250;&#32473;&#38381;&#21253;&#25552;&#20379;&#27599;&#27425;&#24490;&#29615;i&#30340;&#20540;&#65292;//&#24182;&#19988;&#19981;&#34987;&#37322;&#25918;&#65292;&#26368;&#32456;setTimeout&#37324;&#20250;&#20998;&#21035;&#36755;&#20986;0&#12289;1&#12289;2for (let i = 0; i < 3; i++) {  setTimeout(function () {    console.log(i); //0 1 2
  }, 100);
}&#22797;&#21046;&#20195;&#30721;

二、暂时性死区

不能在变量和常量声明之前使用。
let和const命令会使区块形成封闭作用域,若在声明之前使用,就会报错,这个在语法上,称为“暂时性死区”(简称TDZ)。

if (true) {
  tmp = "abc"; // ReferenceError
  let tmp; 
}&#22797;&#21046;&#20195;&#30721;

三、不能重复声明

let a = 1;let a = 2;//&#25253;&#38169;  SyntaxError: Identifier 'a' has already been declared const B=1;const B=2;//&#25253;&#38169;  SyntaxError: Identifier 'B' has already been declared &#22797;&#21046;&#20195;&#30721;

四、不属于顶层对象

let声明的变量,全局对象(window,global,self)不能访问到

let a = 10;console.log(window.a);  //undefined&#22797;&#21046;&#20195;&#30721;

String

ES6对字符串进行了一些扩展,如下:

模板字符串

ES6新增了模板字符串(字符串)的方式定义字符串,用来解决之前字符串很长要换行、字符串中有变量或者表达式遇到的问题,下面是具体的使用场景

//&#19968;&#12289;&#25171;&#21360;&#38271;&#23383;&#31526;&#20018;&#19988;&#25442;&#34892;&#65292;&#30452;&#25509;&#22312;&#27169;&#26495;&#23383;&#31526;&#20018;&#20013;&#20445;&#30041;&#26684;&#24335;&#21363;&#21487;let welcome=`
  &#20320;&#22909;
    &#27426;&#36814;&#26469;&#21040;ES6
      &mdash;&mdash;&#35874;&#35874;
`console.log(welcome);/*
    &#36755;&#20986;&#32467;&#26524;&#20026;&#65306;
  &#20320;&#22909;
    &#27426;&#36814;&#26469;&#21040;ES6
      &mdash;&mdash;&#35874;&#35874;
*///&#20108;&#12289;&#23383;&#31526;&#20018;&#20013;&#26377;&#21464;&#37327;&#25110;&#32773;&#34920;&#36798;&#24335;&#65292;&#30452;&#25509;&#22312;&#27169;&#26495;&#23383;&#31526;&#20018;&#20013;&#20351;&#29992;${&#21464;&#37327;/&#34920;&#36798;&#24335;}&#21363;&#21487;let type = "ES6";let name1 = "mango";let name2 = "&#21644;goman";let welcome = `&#27426;&#36814;${name1 + name2}&#26469;&#21040;${type}&#19990;&#30028;`;  

console.log(welcome);   //learn1.js?c1a0:7 &#27426;&#36814;mango&#21644;goman&#26469;&#21040;ES6&#19990;&#30028;&#22797;&#21046;&#20195;&#30721;

方法

String.prototype.includes()

判断字符串是否包含一个指定字符串,返回boolean类型。

const str = "ECMAScript"console.log(str.includes("EC")); //true &#25214;&#19981;&#21040;&#36820;&#22238;false  &#22797;&#21046;&#20195;&#30721;

startsWith()和endsWith()

startsWith()用来判断字符串是否以指定字符串作为开头,返回boolean类型。
endsWith()用来判断字符串是否以指定字符串作为结尾,返回boolean类型。

const str = "ECMAScript"console.log(str.startsWith("ECM")); //true console.log(str.endsWith("Script")); //true &#22797;&#21046;&#20195;&#30721;

String.prototype.repeat()

将原有字符串重复n遍,得到一个新的字符串

const str = "ECMAScript";console.log(str.repeat(3)); //ECMAScriptECMAScriptECMAScript&#22797;&#21046;&#20195;&#30721;

Number

ES6开始逐步减少全局性方法,使得语言逐步模块化,所以把一些处理数值的方法转移到了Number对象上,功能行为保持不变。

//&#23558;&#30446;&#26631;&#36716;&#25442;&#20026;&#25972;&#25968;//ES5parseInt("5.6") //5//ES6Number.parseInt("5.6")  //5//&#23558;&#30446;&#26631;&#36716;&#25442;&#20026;&#28014;&#28857;&#25968;//ES5parseFloat("12.45str")  //12.45//ES6Number.parseFloat("12.45str")   //12.45&#22797;&#21046;&#20195;&#30721;

另外,为了便于开发,Number还增加了一些方法和属性

&#19968;&#12289;&#21028;&#26029;&#19968;&#20010;&#25968;&#20540;&#26159;&#21542;&#26159;&#25972;&#25968;Number.isInteger(25) // trueNumber.isInteger(25.1) // false&#20108;&#12289;&#33719;&#21462;JavaScript&#26368;&#22823;&#23433;&#20840;&#20540;&#21644;&#26368;&#23567;&#23433;&#20840;&#20540;Number.MAX_SAFE_INTEGER=9007199254740991Number.MIN_SAFE_INTEGER=-9007199254740991&#19977;&#12289;&#21028;&#26029;&#19968;&#20010;&#25968;&#20540;&#26159;&#21542;&#26159;&#22312;&#23433;&#20840;&#33539;&#22260;Number.isSafeInteger(9007199254740992)  //false&#22797;&#21046;&#20195;&#30721;

Symbol

新引入原始数据类型,用来表示独一无二的值。

声明方式

let sym = Symbol();let sym2 = Symbol();console.log(sym == sym2); //false   &#29983;&#25104;&#30340;&#20540;&#26159;&#29420;&#19968;&#26080;&#20108;&#30340;&#65292;&#25152;&#20197;&#19981;&#30456;&#31561;console.log(typeof sym);  //symbol  typeof&#26597;&#30475;&#20540;&#30340;&#31867;&#22411;&#20026;symbollet symWithDesc = Symbol("name"); //Symbol()&#25324;&#21495;&#20869;&#21487;&#20197;&#28155;&#21152;&#25551;&#36848;console.log(symWithDesc.toString()); //&#36755;&#20986;&#65306;Symbol(name)   &#25171;&#21360;&#25551;&#36848;&#38656;&#35201;&#36716;&#25442;&#25104;&#23383;&#31526;&#20018;&#22797;&#21046;&#20195;&#30721;

项目中应用


一、消除魔术字符串
假如我们需要做一个点击菜单,做不同处理的功能,我们通常会这样实现。

const clickMenu = function (menu) {  switch (menu) {    case "home":      break;    case "me":      break;
  }
};

clickMenu("home")&#22797;&#21046;&#20195;&#30721;

"home"这种可能会多次出现,与代码形成强耦合的字符串就是魔术字符串,在项目中我们应该尽量消除魔术字符串,下面使用Symbol消除魔术字符串

const MENU_TYPE = {  home: Symbol(),  me: Symbol(),
};const clickMenu = function () {  switch (menu) {    case MENU_TYPE.home:      break;    case MENU_TYPE.me:      break;
  }
};

clickMenu(MENU_TYPE.home);&#22797;&#21046;&#20195;&#30721;


二、作为对象独一无二的属性值
假如我们想生成一个公司人名对象,并以每个人名为key值,这时候如果有人名重名便会有问题,而Symbol能解决这个问题

const scores = {
  [Symbol("&#24352;&#19977;")]: {    age: 22,
  },
  [Symbol("&#26446;&#22235;")]: {    age: 21,
  },
  [Symbol("&#24352;&#19977;")]: {    age: 20,
  },
};&#22797;&#21046;&#20195;&#30721;

注意,通过Symbol定义的属性,只能通过下面两种方式进行遍历,否则无法获取属性。

for (let key of Object.getOwnPropertySymbols(scores)) {  console.log(key, key);
}for (let key of Reflect.ownKeys(scores)) {  console.log(key, scores[key]);
}&#22797;&#21046;&#20195;&#30721;

Set和Map


为了更方便地实现数据操作,ES6新增了Set和Map两种数据结构。

Set

Set是类似于数组,但成员的值都是唯一的数据结构。

新建

新建一个存储月份的Set数据结构,可以定义一个空的Set实例,也可以是带有数组形式的默认数据。

let monthSets = new Set();let monthSets2 = new Set(["&#19968;&#26376;","&#20108;&#26376;","&#19977;&#26376;"]);&#22797;&#21046;&#20195;&#30721;

基本使用

//&#28155;&#21152;&#25968;&#25454;monthSets.add("&#19968;&#26376;");
monthSets.add("&#20108;&#26376;").add("&#19977;&#26376;");console.log(monthSets); //Set(3) {"&#19968;&#26376;", "&#20108;&#26376;", "&#19977;&#26376;"}//&#36941;&#21382;&#38598;&#21512;Set//forEach&#65288;&#65289;&#65306;&#20351;&#29992;&#22238;&#35843;&#20989;&#25968;&#36941;&#21382;&#27599;&#20010;&#25104;&#21592;monthSets.forEach((item) => console.log(item)); //&#19968;&#26376; &#20108;&#26376;  &#19977;&#26376;//for...of:&#30452;&#25509;&#36941;&#21382;&#27599;&#20010;&#25104;&#21592;for (const item of monthSets) {  console.log(item);    //&#19968;&#26376; &#20108;&#26376;  &#19977;&#26376;}//&#21024;&#38500;&#25968;&#25454;monthSets.delete("&#20108;&#26376;");console.log(monthSets); // Set(2) {"&#19968;&#26376;", "&#19977;&#26376;"}monthSets.clear(); //console.log(monthSets); // Set(0) {}&#22797;&#21046;&#20195;&#30721;

常见应用

Set数据结构在实际项目中还有很多应用场景。

let monthSets = new Set(["&#19968;&#26376;", "&#20108;&#26376;", "&#19977;&#26376;"]);//&#19968;&#12289;&#24555;&#36895;&#21028;&#26029;&#25968;&#25454;&#20803;&#32032;&#26159;&#21542;&#23384;&#22312;monthSets.has("&#19968;&#26376;"); //true//&#20108;&#12289;&#32479;&#35745;&#25968;&#25454;&#20803;&#32032;&#20010;&#25968;monthSets.size; //3console.log(monthSets.size); //3//&#19977;&#12289;&#25968;&#32452;&#21435;&#37325;let arr = [1, 2, 3, 2, 3, 4, 5];let set = new Set(arr);console.log(set); // {1, 2, 3, 4, 5}//&#22235;&#12289;&#21512;&#24182;&#21435;&#37325;let arr = [1, 2, 3];let arr2 = [2, 3, 4];let set = new Set([...arr, ...arr2]);console.log(set); // {1, 2, 3, 4}//&#20116;&#12289;&#21462;&#25968;&#32452;&#20132;&#38598;let arr1 = [1, 2, 3];let arr2 = [2, 3, 4];let set1 = new Set(arr1);let set2 = new Set(arr2);let resultSet = new Set(arr1.filter((item) => set2.has(item)));console.log(Array.from(resultSet)); // [2, 3]//&#20845;&#12289;&#21462;&#25968;&#32452;&#24046;&#32423;let arr1 = [1, 2, 3];let arr2 = [2, 3, 4];let set1 = new Set(arr1);let set2 = new Set(arr2);let arr3 = arr1.filter((item) => !set2.has(item));let arr4 = arr2.filter((item) => !set1.has(item));console.log([...arr3, ...arr4]);  //[1, 4]&#22797;&#21046;&#20195;&#30721;

WeakSet

WeakSet与Set类似,也是不重复的值的集合,但WeakSet的成员只能是对象。WeakSet引用的对象都是弱引用,如果其他对象不再引用该对象,那么垃圾回收机制就会自动回收这些对象所占用的内存,不考虑该对象还存在于WeakSet之中。
React源码中有很多地方使用到了WeakSet,例如在react-reconciler/src/ReactFiberHotReloading.new.js中。

export function markFailedErrorBoundaryForHotReloading(fiber: Fiber) {  if (__DEV__) {    if (resolveFamily === null) {      // Hot reloading is disabled.
      return;
    }    if (typeof WeakSet !== 'function') {      return;
    }    if (failedBoundaries === null) {
      failedBoundaries = new WeakSet();
    }
    failedBoundaries.add(fiber);
  }
}&#22797;&#21046;&#20195;&#30721;

Map

Map是一种键值对集合,与对象类似,但Object只支持“字符串:值”,而Map支持“各种类型的值:值”,map给我们提供了更合适的“键值对”数据结构。

基本使用

//&#23450;&#20041;let map = new Map();//&#28155;&#21152;&#25968;&#25454;let address = { address: "&#27743;&#33487;" };
map.set("name", "ES6");
map.set(27, "&#24180;&#40836;&#20449;&#24687;");
map.set(address, "&#22320;&#22336;&#20449;&#24687;");console.log(map); //{"name" => "ES6", 27 => "&#24180;&#40836;&#20449;&#24687;", {&hellip;} => "&#22320;&#22336;&#20449;&#24687;"}//&#33719;&#21462;&#25968;&#25454;let name = map.get("name");let age = map.get(27);let addressObj = map.get(address);console.log(name, age, addressObj);//&#33719;&#21462;&#25104;&#21592;&#25968;&#37327;console.log(map.size);  //3//&#21028;&#26029;&#26159;&#21542;&#25351;&#23450;key&#25104;&#21592;console.log(map.has("name")); //true&#22797;&#21046;&#20195;&#30721;

Map的遍历

map通常可以用forEach和for...of的方式进行遍历。

//&#23450;&#20041;let map = new Map();

map.set("id", 1);
map.set("name", "mango");
map.set("address", {  province: "&#27743;&#33487;",  city: "&#21335;&#20140;",
});


map.forEach((key, value) => console.log(key, value));for (const [key, value] of map) {  console.log(key, value);
}//&#36755;&#20986;  id 1      name mango      address {province: "&#27743;&#33487;", city: "&#21335;&#20140;"}&#22797;&#21046;&#20195;&#30721;

WeakMap

WeakMap与Map类似,也是用来生成键值对的集合。但WeakMap只接受对象作为键名,并且键名所指向的对象,属于弱引用对象。

数组的扩展

ES6对数组进行了很多的扩展,具体如下

扩展运算符

扩展运算符是三个点(...),将一个数组转为用逗号分隔的参数序列,通常用在函数参数中。
假如我们需要一个求和函数,并且支持传入任意数量的值。

function sum(...params) {  let sum = arr.reduce(function (prev, cur) {    return prev + cur;
  });  return sum;
}let arr = [1, 2, 3, 4, 5];console.log(sum(arr)); //&#36755;&#20986; 15&#22797;&#21046;&#20195;&#30721;

Array.from()

Array.from()方法从一个类似数组或可迭代对象创建一个新的浅拷贝的数组实例,通常有以下四种实用场景。

//&#19968;&#12289;&#20811;&#38534;&#19968;&#20010;&#25968;&#32452;let num = [1, 2, 3];let newNum = Array.from(num);console.log(newNum, num === newNum);  //[1, 2, 3] false//&#20108;&#12289;&#20351;&#29992;&#25351;&#23450;&#20540;&#65292;&#21021;&#22987;&#21270;&#19968;&#20010;&#25968;&#32452;//&#32473;&#23450;&#38271;&#24230;&#20026;10&#65292;&#40664;&#35748;&#20540;&#26159;&#25968;&#32452;2&#21644;&#23545;&#35937;{key:1}let length = 4;let defaultValue = 2;let defaultObj = { key: 1 };let arrValue = Array.from({ length }, (item,index) => defaultValue);let arrObj = Array.from({ length }, (item,index) => defaultObj);console.log(arrValue); // [2, 2, 2, 2]console.log(JSON.stringify(arrObj)); //[{"key":1},{"key":1},{"key":1},{"key":1}]//&#19977;&#12289;&#29983;&#25104;&#20540;&#33539;&#22260;&#25968;&#32452;function range(end) {  return Array.from({ length: end }, (item, index) => index);
}let arr = range(4);console.log(arr); // [0, 1, 2, 3]//&#22235;&#12289;&#25968;&#32452;&#21435;&#37325;,&#32467;&#21512;set&#20351;&#29992;let arr = [1, 1, 2, 3, 3];let set = new Set(arr);console.log(Array.from(set));&#22797;&#21046;&#20195;&#30721;

创建数组

如何创建一个数组,有下面几种常用方式

//&#19968;&#12289;&#25968;&#32452;&#23383;&#38754;&#37327;const arr1 = [];//&#20108;&#12289;&#26500;&#36896;&#20989;&#25968;const arr2 = Array(3);  //[null,null,null]const arr3 = Array("3");  //["3"]//&#36825;&#26102;&#24819;&#35201;&#29992;&#26500;&#36896;&#20989;&#25968;&#21019;&#24314;&#19968;&#20010;&#25968;&#23383;&#20026;7&#30340;&#25968;&#32452;&#65292;&#21457;&#29616;&#19978;&#38754;&#26041;&#24335;&#26159;&#26080;&#27861;&#28385;&#36275;&#30340;&#65292;&#32780;ES6&#25552;&#20379;&#20102;Array.of()&#33021;&#28385;&#36275;&#25105;&#20204;&#30340;&#38656;&#27714;const arr3 = Array.of(7);  //[7]&#22797;&#21046;&#20195;&#30721;

数组查找


find()方法返回数组中满足提供的测试函数的第一个元素的值,若没有找到对应元素返回undefined
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引,若没有找到对应元素则返回-1。

假如我们想要在一个成绩数组中,找到达到及格分数的最低分。

const score = [34, 23, 66, 12, 90, 88, 77, 40];const passMin = score.find((value) => value > 60);console.log(passMin); //66const pass = score.findIndex((value) => value > 60);console.log(pass); //2&#22797;&#21046;&#20195;&#30721;

数组遍历

ES6新增 for...of 数组遍历方式

const score = [34, 23, 66, 12,];for (let value of score) {  console.log(value); //  34, 23, 66, 12}&#22797;&#21046;&#20195;&#30721;

函数的扩展


ES6对函数进行了很多的扩展,具体如下

函数参数设置默认值

ES6允许为函数的参数设置默认值,即可以直接写在参数定义的后面。

//&#21442;&#25968;b&#35774;&#32622;&#20102;&#40664;&#35748;&#20540;&#20026;2&#65292;&#22312;&#26041;&#27861;&#35843;&#29992;&#30340;&#26102;&#20505;&#24182;&#27809;&#26377;&#20256;&#20540;&#65292;&#25152;&#20197;b&#30452;&#25509;&#20351;&#29992;&#40664;&#35748;&#20540;function sum(a, b = 2) {  return a + b;
}console.log(sum(1)); //3&#22797;&#21046;&#20195;&#30721;

Rest参数

ES6引入reset参数,形式为...变量名,可以用来获取传递给函数的多余参数。

function sum(a, ...values) {  console.log(a, values); //1   [2, 3, 4, 5]}

sum(1, 2, 3, 4, 5);&#22797;&#21046;&#20195;&#30721;

name和length属性

name属性返回函数名,length属性返回没有指定默认值的参数个数。

function sum(a, b, c, d = 1) {  console.log(a, values); //1   [2, 3, 4, 5]}console.log(sum.name);  //sumconsole.log(sum.length);  //3&#22797;&#21046;&#20195;&#30721;

箭头函数

ES6允许使用箭头(=>)的方式定义函数,有下面几种箭头函数实现形式。
想要实现一个加法函数,ES5的形式如下

function sum(a, b) {  return a + b;
}&#22797;&#21046;&#20195;&#30721;

而如果使用箭头函数实现的话,则如下

sumArrow = (a, b) => {  return a + b;
};&#22797;&#21046;&#20195;&#30721;

上面是箭头函数的基本变现形式,不同的场景还有不同的实现形式。

//&#23545;&#20110;&#19978;&#38754;&#30340;sumArrow&#20989;//&#19968;&#12289;&#22914;&#26524;&#21482;&#26377;&#19968;&#20010;&#21442;&#25968;,&#21487;&#20197;&#30465;&#30053;&#25324;&#21495;sumArrow = a => {  return a;
};

&#20108;&#12289;&#22914;&#26524;&#36820;&#22238;&#20540;&#26159;&#34920;&#36798;&#24335;&#65292;&#21487;&#20197;&#30465;&#30053;return&#21644;{}
sumArrow = a => a;

&#19977;&#12289;&#22914;&#26524;&#36820;&#22238;&#20540;&#26159;&#23383;&#38754;&#37327;&#23545;&#35937;&#65292;&#19968;&#23450;&#35201;&#29992;&#23567;&#25324;&#21495;&#21253;&#36215;&#26469;
sumArrow = () => ({ a: 1, b: 2 });&#22797;&#21046;&#20195;&#30721;

箭头函数与普通函数除了实现方式不同外,还有个不同的点就是对this的处理方式。

//&#26222;&#36890;&#20989;&#25968;let math = {  name: "mathName",  sum: function (a, b) {    console.log(this.name); //math
    return a + b;
  },
};

math.sum();//&#31661;&#22836;&#20989;&#25968;globalThis.name = "globalName";let math = {  name: "mathName",  sum: (a, b) => {    console.log(this.name); //globalName
    return a + b;
  },
};

math.sum();&#22797;&#21046;&#20195;&#30721;

从上面示例可以看到,箭头函数和普通函数最终打印的this.name不一致。对于普通函数,this指向的是调用sum方法的math对象,所以this.name打印的是“mathName”。而对于箭头函数,this指向的是定义sum方法的全局对象,所以this.name打印的是“globalName”。

在后续的开发过程中,我们将会经常使用到箭头函数,在使用的过程中,我们需要有以下几点注意

  1. 箭头函数中this指向定义时所在的对象,而不是调用时所在的对象
  2. 不可以当作构造函数
  3. 不可以使用yield命令,不能作用generator函数

解构赋值


解构赋值是一种表达式,可以将属性和值从对象和数组中取出,赋值给其他变量。

如何使用

对象解构赋值

假如我们拿到一个对象,需要获取指定的属性值。则解构赋值让我们无需通过调用属性的方式赋值,而是通过指定一个与对象结构相同模板的方式,获取想要的属性值。

const people = {  name: "ES6",  age: 27,  sex: "male",
};//&#22914;&#26524;&#36890;&#36807;&#35843;&#29992;&#23646;&#24615;&#36171;&#20540;&#65292;&#21017;&#38656;&#35201;&#36825;&#20040;&#20570;let name = people.name;let age = people.age;let sex = people.sex;console.log(name, age, sex); //ES6 27 male//&#32780;&#20351;&#29992;&#35299;&#26500;&#36171;&#20540;&#30340;&#26041;&#24335;&#65292;&#20195;&#30721;&#20250;&#26356;&#21152;&#30340;&#28165;&#26224;&#31616;&#21333;const { name, age } = People;console.log(name, age); //ES6 27 male&#22797;&#21046;&#20195;&#30721;

除了上面这种基本用法,还有其他使用方式

const people = {  name: "ES6",  age: 27,  sex: "male",
};// &#19968;&#12289;&#23646;&#24615;&#39034;&#24207;&#19981;&#38656;&#20445;&#25345;&#19968;&#33268;&#65292;&#21517;&#31216;&#30456;&#21516;&#21363;&#21487;const { age, name, sex } = people;console.log(name, age, sex);  //ES6 27 male//&#20108;&#12289;&#21462;&#20540;&#26102;&#65292;&#37325;&#26032;&#23450;&#20041;&#21464;&#37327;&#21517;const { age: newAge, name: newName, sex: newSex } = people;console.log(name, age, sex); //Uncaught ReferenceError: age is not definedconsole.log(newName, newAge, newSex); //ES6 27 male//&#19977;&#12289;&#36171;&#20540;&#36807;&#31243;&#20013;&#35774;&#32622;&#40664;&#35748;&#20540;const { nickName = "&#26165;&#31216;", age } = people;console.log(nickName, age); //&#26165;&#31216; 27//&#22235;&#12289;reset&#36816;&#31639;&#31526;&#12290;&#21482;&#33719;&#21462;&#24819;&#35201;&#30340;&#23646;&#24615;&#65292;&#20854;&#20182;&#23646;&#24615;&#37117;&#25918;&#22312;&#26032;&#30340;&#21464;&#37327;&#37324;&#12290;const { name, ...peopleParams } = people;console.log(name, peopleParams); //ES6 {age: 27, sex: "male"}//&#20116;&#12289;&#23884;&#22871;&#23545;&#35937;&#21462;&#20540;const people = {  name: "ES6",  address: {    province: "&#27743;&#33487;",
  },
};const { address: { province }} = people;console.log(province); //&#27743;&#33487;&#22797;&#21046;&#20195;&#30721;

数组解构赋值

假如我们拿到一个数组,需要获取指定的元素值。

逍遥内容管理系统(Carefree CMS)1.3.0
逍遥内容管理系统(Carefree CMS)1.3.0

系统简介逍遥内容管理系统(CarefreeCMS)是一款功能强大、易于使用的内容管理平台,采用前后端分离架构,支持静态页面生成,适用于个人博客、企业网站、新闻媒体等各类内容发布场景。核心特性1、模板套装系统 - 支持多套模板自由切换,快速定制网站风格2、静态页面生成 - 一键生成纯静态HTML页面,访问速度快,SEO友好3、文章管理 - 支持富文本编辑、草稿保存、文章属性标记、自动提取SEO4、全

下载
const [a, b, c] = [1, 2, 3];console.log(a, b, c);   //1 2 3&#22797;&#21046;&#20195;&#30721;

除了上面这种基本用法,还有其他使用方式

//&#19968;&#12289;&#24453;&#35299;&#26500;&#30340;&#38500;&#20102;&#26159;&#25968;&#32452;&#65292;&#36824;&#21487;&#20197;&#26159;&#20219;&#24847;&#21487;&#36941;&#21382;&#30340;&#23545;&#35937;const [a, b, c] = new Set([1, 2, 3]);console.log(a, b, c); //1 2 3//&#20108;&#12289;&#34987;&#36171;&#20540;&#30340;&#21464;&#37327;&#36824;&#21487;&#20197;&#26159;&#23545;&#35937;&#30340;&#23646;&#24615;&#65292;&#19981;&#23616;&#38480;&#20110;&#21333;&#32431;&#30340;&#21464;&#37327;const num = {};
[num.a, num.b, num.c] = [1, 2, 3];console.log(num); //{a: 1, b: 2, c: 3}//&#19977;&#12289;&#35299;&#26500;&#36171;&#20540;&#22312;&#24490;&#29615;&#20307;&#20013;&#30340;&#24212;&#29992;const num = {  a: 10,  b: 20,  c: 30,
};for (const [key, value] of Object.entries(num)) {  console.log(key, value); //a 10    b 20    c 30}//&#22235;&#12289;&#36339;&#36807;&#36171;&#20540;&#20803;&#32032;const [a, , c] = [1, 2, 3]; //&#23384;&#22312;&#31354;&#20301;&#30340;&#25968;&#32452;&#21483;&#31232;&#30095;&#25968;&#32452;console.log(a, c);  //1 3//&#20116;&#12289;rest &#21442;&#25968;const [a,...other] = [1, 2, 3];console.log(a, other);  //1    [2, 3]//&#20845;&#12289;&#36171;&#20540;&#36807;&#31243;&#20013;&#35774;&#32622;&#40664;&#35748;&#20540;const [a, , , d = 10] = [1, 2, 3];console.log(d); //10&#22797;&#21046;&#20195;&#30721;

字符串解构赋值

字符串解构赋值可以当成数组解构赋值

const [a, b, c, d] = "ECMAScript2015";console.log(a, b, c, d); //E C M A&#22797;&#21046;&#20195;&#30721;

对象的扩展


ES6对对象进行了很多的扩展,具体如下

属性的简洁表示法

从ES6开始,如果对象的属性名和属性值相同,则有简写的方式。

let province = "&#27743;&#33487;";const address = {
  province, //&#31561;&#21516;&#20110; province: province
  city: "&#21335;&#20140;",
};&#22797;&#21046;&#20195;&#30721;

属性名表达式

从ES6开始,可以使用变量或表达式定义对象的属性。

let key = "province";const address = {
  [key]: "&#30465;&#20221;",  city: "&#21335;&#20140;",
};console.log(address); //{province: "&#30465;&#20221;", city: "&#21335;&#20140;"}&#22797;&#21046;&#20195;&#30721;

Object.is()

判断两个值是否是同一个值。在Object.is()之前,有“==”和“===”两种方式判断值是否相等,但这两个方式都有一定缺陷,如下

//== &#22312;&#21028;&#26029;&#30456;&#31561;&#21069;&#20250;&#23545;&#19981;&#26159;&#21516;&#19968;&#31867;&#22411;&#30340;&#21464;&#37327;&#36827;&#34892;&#24378;&#21046;&#36716;&#25442;&#65292;&#26368;&#32456;&#23548;&#33268;&ldquo;&rdquo;&#19982;false&#30456;&#31561;console.log("" == false);   //true//=== &#20250;&#23558;-0&#19982;+0&#35270;&#20026;&#30456;&#31561;&#65292;&#32780;&#23558;Number.NaN&#19982;NaN&#35270;&#20026;&#19981;&#30456;&#31561;console.log(-0 === +0); //trueconsole.log(Number.NaN === NaN);    //false&#22797;&#21046;&#20195;&#30721;

所以,需要一种运算,在所有场景下,只要两个值是一样的,那么就应该相等,在实际项目开发过程中,推荐使用Object.is()来判断值相等。

console.log(Object.is(-0, +0)); //falseconsole.log(Object.is(Number.NaN, NaN)); //truelet a = { value: 1 };let b = { value: 1 };console.log(Object.is(a, b)); //false  &#23545;&#35937;&#37117;&#26159;&#21516;&#19968;&#20010;&#24341;&#29992;&#25165;&#30456;&#31561;&#22797;&#21046;&#20195;&#30721;

Object.assign()


用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,它将返回目标对象。

语法:

Object.assign(target, ...sources)     参数说明: target:目标对象 sources:源对象 返回值:合并后的目标对象
const target = { a: 1,};const source = { b: "B", c: "C" };const assignObj = Object.assign(target, source);console.log(assignObj); //{a: 1, b: "B", c: "C"}  //&#20854;&#20182;&#24212;&#29992;//&#19968;&#12289;&#22914;&#26524;&#30446;&#26631;&#23545;&#35937;&#19982;&#28304;&#23545;&#35937;&#23646;&#24615;&#20855;&#26377;&#30456;&#21516;&#20540;&#65292;&#21017;&#28304;&#23545;&#35937;&#23646;&#24615;&#20540;&#20250;&#35206;&#30422;&#30446;&#26631;&#23545;&#35937;&#23646;&#24615;&#20540;const target = { a: 1,b: 2};const source = { b: "B", c: "C" };const assignObj = Object.assign(target, source);console.log(assignObj); //{a: 1, b: "B", c: "C"}    //&#30446;&#26631;&#23545;&#35937;&#30340;b&#23646;&#24615;&#20540;&#34987;&#35206;&#30422;//&#20108;&#12289;&#28304;&#23545;&#35937;&#21487;&#20197;&#26377;&#22810;&#20010;&#20540;const target = { a: 1 };const source1 = { b: "B", c: "C" };const source2 = { d: "D", e: "E" };const assignObj = Object.assign(target, source1, source2);console.log(assignObj); //{a: 1, b: "B", c: "C", d: "D", e: "E"}&#22797;&#21046;&#20195;&#30721;

对象遍历

假如我们想要循环遍历一个对象的键与值,则可以使用下面几种方式进行遍历

const score = {  name: "mango",  age: "25",  score: 80,
};//for...infor (let key in score) {  console.log(key, score[key]); // &#20998;&#21035;&#36755;&#20986;&#65306;name mango &#12289; age 25 &#12289;score 80}//Object.keys()&#29992;&#26469;&#33719;&#21462;&#25152;&#26377;key&#32452;&#25104;&#30340;&#25968;&#32452;Object.keys(scoreObj).forEach(key => {  console.log(key, scoreObj[key]) //&#20998;&#21035;&#36755;&#20986;&#65306;name mango &#12289; age 25 &#12289;score 80})//Object.getOwnPropertyNames()&#29992;&#26469;&#33719;&#21462;&#25152;&#26377;key&#32452;&#25104;&#30340;&#25968;&#32452;Object.getOwnPropertyNames(scoreObj).forEach(key => {  console.log(key, scoreObj[key]) //&#20998;&#21035;&#36755;&#20986;&#65306;name mango &#12289; age 25 &#12289;score 80})//Reflect.ownKeys()&#29992;&#26469;&#33719;&#21462;&#25152;&#26377;key&#32452;&#25104;&#30340;&#25968;&#32452;Reflect.ownKeys(scoreObj).forEach(key => {  console.log(key, scoreObj[key]) //&#20998;&#21035;&#36755;&#20986;&#65306;name mango &#12289; age 25 &#12289;score 80})&#22797;&#21046;&#20195;&#30721;

Class

JavaScript是一种基于对象的语言,我们遇到的所有东西几乎都是对象,但ES6之前是没有class的,而在ES6版本中正式引入了class,让JavaScript成为了一种真正的面向对象语言,我们可以像下面这样在JavaScript中进行面向对象编程。

//&#36890;&#36807;class&#20851;&#38190;&#23383;&#23450;&#20041;&#31867;class People{  
  //&#31867;&#30340;&#26500;&#36896;&#20989;&#25968;
  constructor(name, age) {    this.name = name;    this.age = age;
  }  //&#23454;&#20363;&#26041;&#27861;
  getName() {    return this.name;
  }  //&#38745;&#24577;&#26041;&#27861;
  static say() {    console.log("Hello ES6");
  }
}//&#32487;&#25215;class Student extends People {  constructor(name, age) {    super(name, age);
  }
}//&#23545;&#35937;&#21019;&#24314;&#19982;&#35843;&#29992;let student = new Student("mango", "27");
student.getName();
Student.say();&#22797;&#21046;&#20195;&#30721;

通过上面的代码,我们具体说明下JavaScript中进行面向对象编程。

类的声明

通过class关键字声明类,支持构造函数construct做对象初始化。

class People{  
  constructor() {    //&#21021;&#22987;&#21270;
  }
}&#22797;&#21046;&#20195;&#30721;

属性

Class对象中有两种对象属性,分别是实例属性和静态属性。实例属性必须定义在类的方法里,而静态属性必须定义在类的外面。

class People{  constructor() {    //&#23450;&#20041;&#23454;&#20363;&#23646;&#24615;
    this.name = "";    this.age = 0;
  }
}

People.desc="&#31867;&#25551;&#36848;";  //&#23450;&#20041;&#30340;&#38745;&#24577;&#23646;&#24615;//&#35775;&#38382;People people=new People();console.log(people.name);console.log(People.name);&#22797;&#21046;&#20195;&#30721;

类中定义的属性,默认都是可读可写的,但是如果这时候我们想指定属性不可被修改该如何实现呢?那么便要用到set和get了,set和get可以定义一个属性,但是如果只有get而没有set,则属性不可以进行修改。

class People {  get sex() {    return "&#30007;";
  }
}let people = new People();console.log(people.sex);
people.sex="&#22899;" //Uncaught TypeError: Cannot set property sex of #<People> which has only a getter&#22797;&#21046;&#20195;&#30721;

方法

Class对象中有三种方法,分别是构造方法、实例方法还有静态方法。

class People {  //&#26500;&#36896;&#26041;&#27861;
  constructor(name, age) {    this.nameA = name;    this.age = age;
  }  //&#23454;&#20363;&#26041;&#27861;
  getName() {    return this.nameA;
  }  //&#38745;&#24577;&#26041;&#27861;
  static say() {    console.log("Hello " + People.desc);
  }
}

People.desc = "&#31867;&#25551;&#36848;";let people = new People("mango", "27");let name = people.getName();console.log(name); //mangoPeople.say(); //Hello &#31867;&#25551;&#36848;&#22797;&#21046;&#20195;&#30721;

继承

继承是面向对象语言很重要的一大特征,ES6新加入了extends和super关键字来实现继承。

class People {  constructor(name) {    this.name = name;
  }

  getName() {    return this.name;
  }
}//&#32487;&#25215;class Student extends People {  constructor(name, age) {    super(name, age);
  }
}//Student&#31867;&#32487;&#25215;&#20102;People&#31867;&#65292;student&#23545;&#35937;&#20013;super&#35843;&#29992;&#20102;&#29238;&#31867;&#30340;&#26500;&#36896;&#20989;&#25968;&#65292;&#24182;&#20256;&#36882;&#20102;name&#21442;&#25968;&#65292;&#22240;&#20026;&#32487;&#25215;&#30340;&#29305;&#24615;&#65292;student&#20063;&#25317;&#26377;&#20102;&#29238;&#31867;&#30340;getName&#65288;&#65289;&#26041;&#27861;let student = new Student("ES6");console.log(student.getName());&#22797;&#21046;&#20195;&#30721;


通过以上对class的学习,我们得知道其实class并不是新引入的数据类型,其实class只是一种语法糖,它的实质完全可以看作构造函数的另一种写法。

class People {  constructor(name) {    this.name = name;
  }

  getName() {    return this.name;
  }
}console.log(typeof People); //functionconsole.log(People.prototype);  //{constructor: &fnof;, getName: &fnof;}&#22797;&#21046;&#20195;&#30721;

JS是单线程的

异步编程其实就是处理异步任务,在进行异步编程之前,我们需要了解JavaScript是单线程的,在同一时间只能做一件事。

JavaScript之所以设计成单线程,是与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动以及操作DOM。这决定了它只能是单线程,否则会带来很多复杂的同步问题。例如,如果JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器就不晓得以哪个线程为准。所以,为了避免复杂,从一诞生,JavaScript就是单线程的。

单线程就意味着,所有任务都需要排队,前一个任务结束,后一个任务才会执行。那么如果前一个任务很长的话,那么后面一个任务不是就一直需要等待了吗?于是乎,JS将所有任务分成了两类,同步和异步。
同步:只有前一个任务执行完毕,才能执行后一个任务
异步:当同步任务执行到某个需要耗时执行的运行环境API时,就会触发异步任务,此时运行环境(浏览器或Node)就会单独开线程去处理这些异步任务。

JavaScript运行原理

下面是JavaScript运行原理图,同步任务在JS主线程完成,异步任务则新开一个线程

全面掌握,ECMAScript的新特性

疑问:不是说JavaScript是单线程的吗,那为什么又新开了一条线程处理任务呢,这不是多线程方式吗?
有这个疑问不奇怪,我们需要清楚JavaScript单线程其实说的是JavaScript引擎是单线程的,开发者只能通过单线程的方式进行JavaScript开发,而新开了一条线程处理任务是底层执行环境决定的,JavaScript执行环境是多线程。


在实际项目中,异步编程使用场景极其之多,请求个接口数据、创建个定时器、缓存个数据都离不开异步编程的身影,为了更好的处理异步任务,ES6给我们提供两种新的方式,分别是Promise和Generator。

Promise

Promise 是一个代理对象,代表了一个异步任务的最终成功或者失败状态。Promise允许你为异步任务的成功或失败分别设置对应的处理方法,以类似同步的方式便捷的进行异步编程。

一个Promise有三种状态:

  • pending:初始状态,既不是成功,也不是失败状态。
  • fulfilled:成功状态,代表着任务执行完成
  • rejected:失败状态,代表着任务执行失败

基本使用

创建Promise对象

const promise = new Promise(function (resolve, reject) {    let result=&#25191;&#34892;&#24322;&#27493;&#20219;&#21153;;    if(result){        //&#22914;&#26524;&#24322;&#27493;&#20219;&#21153;&#25104;&#21151;&#23436;&#25104;
        resolve()
    }else{        //&#22914;&#26524;&#24322;&#27493;&#20219;&#21153;&#25191;&#34892;&#22833;&#36133;
        reject();
    }
});&#22797;&#21046;&#20195;&#30721;

创建Promise对象需要传递一个executor参数,executor是带有resolve和reject两个参数的函数,这两个参数是JavaScript引擎提供的两个函数,Promise构造函数执行会立即调用executor函数。

  • 当Promise中的异步任务执行成功时,调用resolve(),将Promise对象的状态从pending改为fulfilled(未完成到成功)
  • 当Promise中的异步任务执行失败时,调用reject(),将Promise对象的状态从pending改为rejected(未完成到失败)


image.png

如何使用

实例好promise对象后,我们可以使用下面的语法来对异步任务完成后的状态进行处理。

promise.then(onFulfilled,onRejected)

promise.then(  (result) => {    console.log("&#24322;&#27493;&#20219;&#21153;&#22788;&#29702;&#25104;&#21151;&#65292;&#25191;&#34892;&#30456;&#24212;&#26041;&#27861;");
  },  (error) => {    console.log("&#24322;&#27493;&#20219;&#21153;&#22788;&#29702;&#22833;&#36133;&#65292;&#25191;&#34892;&#30456;&#24212;&#26041;&#27861;");
  }
);&#22797;&#21046;&#20195;&#30721;

但在具体的项目开发中,我们通常都是使用已经存在的Promise对象,下面我们就通过使用常用的promise对象fetch获取接口数据。

案例实现

我们需要调用接口,获取一个用户列表数据

fetch("http://jsonplaceholder.typicode.com/users")
  .then(function (response) {    return response.json();
  })
  .then(function (res) {    console.log(res);   // [{&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}]
  });&#22797;&#21046;&#20195;&#30721;

response是一个包含响应结果的Response对象,它只是一个HTTP响应,而不是真正的JSON。为了获取JSON的内容,需要使用json()方法获取一个Promise对象,然后再使用then获取JSON数据。

其他使用

Promise.prototype.catch()

Promise提供了catch()方法,用来捕获异步操作过程中遇到的错误异常,使用场景如下

const CatchPromise = new Promise(function (resolve, reject) {
  reject(new Error("error msg"));
});

CatchPromise.then().catch((e) => {  console.error(e); //Error: error msg});&#22797;&#21046;&#20195;&#30721;

在Promise对象中,除了可以使用reject(new Error())的方式触发异常,还可以使用throw new Error()的方式触发异常,但不建议使用throw new Error()的方式,因为这种方式不会改变Promise的状态。

Promise.prototype.all()

Promise.all()用于处理多个异步任务,例如处理多张图片上传。Promise.all()接受一个promise对象数组作为参数,执行完毕返回一个Promise对象。

Promise.all()的状态变化:
传入的promise对象数组全部变为fulfill状态则返回成功,调用resolve()
传入的promise对象数组有一个变为reject状态则返回失败,调用reject()

const promise1 = new Promise(function (resolve, reject) {  setTimeout(function () {
    resolve("promise1");
  }, 2000);
});const promise2 = new Promise(function (resolve, reject) {  setTimeout(function () {
    resolve("promise2");
  }, 1000);
});const promise3 = new Promise(function (resolve, reject) {  setTimeout(function () {
    resolve("promise3");
  }, 3000);
});const promiseAll = Promise.all([promise1, promise2, promise3]);
promiseAll.then(function (results) {  console.log(results); // ["promise1", "promise2", "promise3"]});&#22797;&#21046;&#20195;&#30721;

Promise.prototype.race()

Promise.race()也是用于处理多个异步任务,与Promise.all()一样,Promise.race()接受一个promise对象数组作为参数,执行完毕返回一个Promise对象。

Promise.race()的状态变化:
传入的promise对象数组有一个变为resolve状态则返回成功,调用resolve()
传入的promise对象数组有一个变为reject状态则返回失败,调用reject()

const promise1 = new Promise(function (resolve, reject) {  setTimeout(function () {
    reject("promise1");
  }, 2000);
});const promise2 = new Promise(function (resolve, reject) {  setTimeout(function () {
    resolve("promise2");
  }, 1000);
});const promise3 = new Promise(function (resolve, reject) {  setTimeout(function () {
    resolve("promise3");
  }, 3000);
});const promiseAll = Promise.race([promise1, promise2, promise3]);
promiseAll.then(function (results) {  console.log(results); // promise2});&#22797;&#21046;&#20195;&#30721;

Generator函数

Generator函数是用来处理异步任务的函数,函数内部包裹的就是异步任务的处理。Generator不同于普通函数,当执行到异步任务,可以暂停,直到异步任务执行完毕再继续往下执行,类似同步的方法进行异步编程。

如何使用

Generator函数在使用上具体有以下特点

  • :定义generator函数时,function后面需要加上星号,例如function generatorFuncName()
  • yield:需要暂停去执行异步任务时,需要在代码前面加上yield标识,例如yield fetch()
  • next():调用generator函数后获得的是一个指针对象,调用指针的next方法,可以用来分阶段逐步执行generator函数。


那么具体如何使用generator函数实现异步编程呢,在学习Promise的时候,我们实现了一个获取一个用户列表数据的案例,下面我们看看如何使用generator函数实现吧。

function* loadUsers() {  const API = "http://jsonplaceholder.typicode.com/users";  console.log("&#31561;&#24453;&#25968;&#25454;&#35831;&#27714;");  yield fetch(API); //&#26242;&#20572;&#65292;&#24320;&#22987;&#25191;&#34892;&#24322;&#27493;&#20219;&#21153;
  console.log("&#25968;&#25454;&#35831;&#27714;&#23436;&#25104;");  console.log("&#32487;&#32493;&#20854;&#20182;&#36923;&#36753;&#25805;&#20316;");
}const generator = loadUsers();const promise = generator.next().value;console.log(promise);

promise
  .then(function (response) {    return response.json();
  })
  .then(function (result) {    console.log(result); //[{&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}, {&hellip;}]
    generator.next(); //&#25171;&#21360;&#65306;&#25968;&#25454;&#35831;&#27714;&#23436;&#25104;  &#32487;&#32493;&#20854;&#20182;&#36923;&#36753;&#25805;&#20316;&#12290;&#24322;&#27493;&#20219;&#21153;&#25191;&#34892;&#23436;&#27605;&#21518;&#35843;&#29992;next()&#65292;&#32487;&#32493;&#25191;&#34892;generator&#20989;&#25968;&#20013;&#21518;&#32493;&#20195;&#30721;
  });&#22797;&#21046;&#20195;&#30721;

Proxy

Proxy翻译过来叫代理,Proxy可以通过自定义行为来改变对象的基本操作,例如属性赋值、查找、枚举、函数调用等。

基本语法

const p=new Proxy(target,handler); 参数说明: target:需要使用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至是另外一个代理) handler:代理目标对象基本操作的对象 返回值: p:target被代理后不可以直接访问,而只能访问

Proxy使用场景

设置对象属性的读写权限

let people = {  name: "mango",  //&#35774;&#32622;&#23646;&#24615;&#19981;&#21487;&#35835;
  age: 27,  //&#35774;&#32622;&#23646;&#24615;&#19981;&#21487;&#34987;&#20462;&#25913;};let peopleHandler = {  //&#35774;&#32622;&#23646;&#24615;&#20540;&#35835;&#21462;&#30340;&#25429;&#25417;&#22120;
  get: function (target, prop, receiver) {    if (Object.is(prop, "name")) {      return prop + "&#23646;&#24615;&#19981;&#21487;&#35835;";
    }
  },  //&#35774;&#32622;&#23646;&#24615;&#20540;&#25805;&#20316;&#30340;&#25429;&#25417;&#22120;
  set: function (target, prop, value) {    if (Object.is(prop, "age")) {      throw new Error(prop + "&#23646;&#24615;&#19981;&#21487;&#20889;");
    }
  },
};let peopleProxy = new Proxy(people, peopleHandler);
peopleProxy.age = 10; // Uncaught Error: age&#23646;&#24615;&#19981;&#21487;&#20889;console.log(peopleProxy.name); //&#36755;&#20986;&#65306;name&#23646;&#24615;&#19981;&#21487;&#35835;&#22797;&#21046;&#20195;&#30721;

给接口返回的对象中字段为null的属性设置默认值

let people = {  address: null,
};let peopleHandler = {  //&#35774;&#32622;&#23646;&#24615;&#20540;&#35835;&#21462;&#30340;&#25429;&#25417;&#22120;
  get: function (target, prop, receiver) {    return target[prop] ?? "&#40664;&#35748;&#20540;";  //&#31354;&#20540;&#21512;&#24182;&#25805;&#20316;&#31526;
  },
};let peopleProxy = new Proxy(people, peopleHandler);console.log(peopleProxy.address); //&#36755;&#20986;&#65306;&#40664;&#35748;&#20540;&#22797;&#21046;&#20195;&#30721;

拦截函数调用

//handler.apply()&#29992;&#20110;&#25318;&#25130;&#20989;&#25968;&#30340;&#35843;&#29992;function sum(a, b) {  console.log(a + b);  return a + b;
}////&#23545;&#20110;sum&#26041;&#27861;&#65292;&#20851;&#27880;&#30340;&#26159;&#22788;&#29702;&#25968;&#25454;&#30456;&#21152;&#30340;&#36923;&#36753;//&#36890;&#36807;&#20195;&#29702;&#21017;&#21487;&#20197;&#22788;&#29702;&#22312;&#35843;&#29992;&#26041;&#27861;&#26102;&#20505;&#65292;&#23545;&#21442;&#25968;&#30340;&#26657;&#39564;&#65292;&#25968;&#25454;&#25171;&#28857;&#31561;const sumProxy = new Proxy(sum, {  apply: function (target, thisArg, argumentsList) {    console.log("&#35843;&#29992;&#20102;&#26041;&#27861;", "&#25171;&#28857;");
  },
});

sumProxy(1, 2);&#22797;&#21046;&#20195;&#30721;

**

Module


ES6在语言标准上,通过Module实现了模块功能,现阶段几乎取代之前用来实现JavaScript模块化的CommonJS和AMD规范,成为了浏览器环境和node环境通用的模块化解决方案。
Module实现的模块化属于“编译时加载”,即在编译时就完成了模块之间的加载,通过这种“编译时加载”的方式,使得在不运行代码的情况下就可以通过词法分析、语法分析等对程序代码进行扫描,以验证代码的规范性、安全性和可维护性,让静态分析成为了可能。

如何使用


Module实现的模块化功能主要有两个命令构成:

  • export:导出命令,用于提供模块的对外接口
  • import:导入命令,用于引入其他模块提供的接口


一个模块就是一个独立的文件,该文件内的所有变量,外部无法获取,如果想要外部获取模块内的某些变量,就必须使用export关键字导出变量,在需要引入该导出变量的的模块中必须使用import关键字引入变量。

export

下面举例说明export命令导出对外接口的几种方式,在ExportDemo.js文件中,

  • 导出变量
//&#26041;&#27861;&#19968;export let a = 1;//&#26041;&#27861;&#20108;let b = 2;export { b };&#22797;&#21046;&#20195;&#30721;
  • 导出函数
//&#26041;&#27861;&#19968;export function test(){    console.log("name");
}//&#26041;&#27861;&#20108;let test2=function test(){    console.log("name");
}export {test2 as newName}&#22797;&#21046;&#20195;&#30721;

注意在方法二中,使用了as关键字,as关键字可以在导出时重命名对外的接口名。

  • 导出类
//&#26041;&#27861;&#19968;export class People {
  say() {      console.log("Hello Module");
  }
}//&#26041;&#27861;&#20108;export { People };&#22797;&#21046;&#20195;&#30721;

import

使用export导出了模块中的对外接口后,其他JS文件就可以通过import关键字加载这个模块,使用如下。

//&#22823;&#25324;&#21495;&#20013;&#30340;&#21464;&#37327;&#21517;&#24517;&#39035;&#19982;&#34987;&#23548;&#20986;&#23545;&#22806;&#25509;&#21475;&#21517;&#19968;&#33268;import { a, b, test as newTest, People } from "./ExportDemo";//&#23548;&#20837;a&#21644;b&#30340;&#21464;&#37327;console.log(a, b);//&#23548;&#20837;test&#26041;&#27861;,&#21516;&#26679;&#21487;&#20197;&#20351;&#29992;as&#20851;&#38190;&#23383;&#22312;&#23548;&#20837;&#30340;&#26102;&#20505;&#37325;&#21629;&#21517;newTest();//&#23548;&#20837;People&#31867;let people = new People();
people.say();&#22797;&#21046;&#20195;&#30721;


其他使用方式**
在日常开发过程中,Module模块化还有下面几种常见的使用方式。

  • 使用*指定一个对象,加载模块中的所有导出
//import { a, b, test, People } from "./ExportDemo";//&#19978;&#38754;&#30340;&#23548;&#20837;&#26041;&#24335;&#21487;&#20197;&#25913;&#20889;&#25104;&#19979;&#38754;&#26041;&#24335;import * as ExportModule from "./ExportModule";//&#20351;&#29992;&#30340;&#20351;&#29992;&#65292;&#21152;&#19978;&#21069;&#32512;&#21363;&#21487;ExportModule.test()&#22797;&#21046;&#20195;&#30721;
  • 通过export default,为模块指定默认导出名
//&#23548;&#20986;const People = {  say: function () {    console.log("Hello Module");
  },
};export default People;//&#23548;&#20837;import People from "./ExportModule";

People.say(); //Hello Module&#22797;&#21046;&#20195;&#30721;
  • export和import一起使用,处理先输入后输出的情况
//&#20551;&#22914;&#26377;a&#12289;b&#12289;c&#19977;&#20010;&#25991;&#20214;&#27169;&#22359;&#65292;//c&#25991;&#20214;&#27169;&#22359;&#22914;&#19979; c.jslet people={name:"mango",age:27};let address="&#21335;&#20140;";export { people, address };//&#26377;&#19979;&#38754;&#20960;&#31181;&#20351;&#29992;&#22330;&#26223;//&#19968;&#12289;&#22312;b&#20013;&#23548;&#20837;c&#20013;&#30340;people&#21644;address&#65292;&#24182;&#23548;&#20986;&#32473;a&#20351;&#29992;export {people,address} from 'c'//&#20108;&#12289;&#22312;b&#20013;&#25972;&#20307;&#23548;&#20837;c&#65292;&#24182;&#23548;&#20986;&#32473;a&#20351;&#29992;export * from 'c'//&#19977;&#12289;&#22312;b&#20013;&#23548;&#20837;people,&#24182;&#20316;&#20026;b&#30340;&#23548;&#20986;&#21517;&#31216;&#12304;&#20855;&#21517;&#25509;&#21475;&#25913;&#20026;&#40664;&#35748;&#25509;&#21475;&#12305;export {people as default} from 'c'//&#24403;c&#30340;&#23548;&#20986;&#26041;&#24335;&#20026;export default&#30340;&#26102;&#20505;&#65292;&#24182;&#21487;&#20197;&#20351;&#29992;&#12304;&#40664;&#35748;&#25509;&#21475;&#25913;&#20026;&#20855;&#21517;&#25509;&#21475;&#12305;export {default as NewPeople} from 'c'&#22797;&#21046;&#20195;&#30721;

相关免费学习推荐:javascript(视频)

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

436

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

544

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

317

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

81

2025.09.10

es6新特性
es6新特性

es6新特性有:1、块级作用域变量;2、箭头函数;3、模板字符串;4、解构赋值;5、默认参数;6、 扩展运算符;7、 类和继承;8、Promise。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

106

2023.07.17

es6新特性有哪些
es6新特性有哪些

es6的新特性有:1、块级作用域;2、箭头函数;3、解构赋值;4、默认参数;5、扩展运算符;6、模板字符串;7、类和模块;8、迭代器和生成器;9、Promise对象;10、模块化导入和导出等等。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

196

2023.08.04

JavaScript ES6新特性
JavaScript ES6新特性

ES6是JavaScript的根本性升级,引入let/const实现块级作用域、箭头函数解决this绑定问题、解构赋值与模板字符串简化数据处理、对象简写与模块化提升代码可读性与组织性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2025.12.24

数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

311

2023.10.31

2026春节习俗大全
2026春节习俗大全

本专题整合了2026春节习俗大全,阅读专题下面的文章了解更多详细内容。

189

2026.02.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
ECMAScript6 / ES6---十天技能课堂
ECMAScript6 / ES6---十天技能课堂

共25课时 | 2万人学习

走进 ES6 新标准语法
走进 ES6 新标准语法

共15课时 | 1.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号