关于ecmascript:ES13中11个令人惊叹的-JavaScript-新特性

前言 与许多其余编程语言一样,JavaScript 也在一直倒退。每年,该语言都会通过新性能变得更加弱小,使开发人员可能编写更具表现力和简洁的代码。 本葡萄明天就为大家介绍ES13中增加的最新性能,并查看其用法示例以更好地了解它们。 1.类 在ES13之前,类字段只能在构造函数中申明。与许多其余语言不同,无奈在类的最外层作用域中申明或定义它们。 class Car { constructor() { this.color = 'blue'; this.age = 2; } } const car = new Car(); console.log(car.color); // blue console.log(car.age); // 而ES13 打消了这个限度。当初咱们能够编写这样的代码: class Car { color = 'blue'; age = 2;}const car = new Car();console.log(car.color); // blueconsole.log(car.age); // 22.公有办法和字段 ES13以前,不可能在类中申明公有成员。成员传统上带有下划线 ( \_) 前缀,以表明它是公有的,但依然能够从类内部拜访和批改它。 class Person { _firstName = 'Joseph'; _lastName = 'Stevens'; get name() { return `${this._firstName} ${this._lastName}`; }}const person = new Person();console.log(person.name); // Joseph Stevens// 仍能够从类内部拜访 // 本来打算设为公有的成员console.log(person._firstName); // Josephconsole.log(person._lastName); // Stevens// 也能够批改person._firstName = 'Robert';person._lastName = 'Becker';console.log(person.name); // Robert Becker应用 ES13,咱们当初能够通过在类后面增加 ( \#) 来向类增加公有字段和成员。尝试从内部拜访这些类将会引发谬误: ...

September 12, 2023 · 4 min · jiezi

关于ecmascript:let-和-const-命令

let 和 const 命令good luck let 和 const 命令let 命令根本用法ES6 新增了let命令,用来申明变量。它的用法相似于var,然而所申明的变量,只在let命令所在的代码块内无效。 { let a = 10; var b = 1;}a; // ReferenceError: a is not defined.b; // 1下面代码在代码块之中,别离用let和var申明了两个变量。而后在代码块之外调用这两个变量,后果let申明的变量报错,var申明的变量返回了正确的值。这表明,let申明的变量只在它所在的代码块无效。 for循环的计数器,就很适合应用let命令。 for (let i = 0; i < 10; i++) { // ...}console.log(i);// ReferenceError: i is not defined下面代码中,计数器i只在for循环体内无效,在循环体外援用就会报错。 上面的代码如果应用var,最初输入的是10。 var a = [];for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); };}a[6](); // 10下面代码中,变量i是var命令申明的,在全局范畴内都无效,所以全局只有一个变量i。每一次循环,变量i的值都会产生扭转,而循环内被赋给数组a的函数外部的console.log(i),外面的i指向的就是全局的i。也就是说,所有数组a的成员外面的i,指向的都是同一个i,导致运行时输入的是最初一轮的i的值,也就是 10。 ...

October 9, 2021 · 5 min · jiezi

关于ecmascript:ECMAScript-6-简介

ECMAScript 6 简介ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代规范,曾经在 2015 年 6 月正式公布了。它的指标,是使得 JavaScript 语言能够用来编写简单的大型应用程序,成为企业级开发语言。 ECMAScript 和 JavaScript 的关系一个常见的问题是,ECMAScript 和 JavaScript 到底是什么关系? 要讲清楚这个问题,须要回顾历史。1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,心愿这种语言可能成为国际标准。次年,ECMA 公布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的规范,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。 该规范从一开始就是针对 JavaScript 语言制订的,然而之所以不叫 JavaScript,有两个起因。一是商标,Java 是 Sun 公司的商标,依据受权协定,只有 Netscape 公司能够非法地应用 JavaScript 这个名字,且 JavaScript 自身也曾经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,这样有利于保障这门语言的开放性和中立性。 因而,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)。日常场合,这两个词是能够调换的。 ES6 与 ECMAScript 2015 的关系ECMAScript 2015(简称 ES2015)这个词,也是常常能够看到的。它与 ES6 是什么关系呢? ...

October 9, 2021 · 3 min · jiezi

关于ecmascript:ECMAScript版本解读

介绍记录ES每年版本更新的内容解读,帮忙读书疾速了解新版本个性。这里有官网的文档: Stage 1 ProposalsStage 0 ProposalsFinished ProposalsInactive Proposals版本列表ES202010 New JavaScript Features in ES2020 That You Should Know

August 24, 2021 · 1 min · jiezi

关于ecmascript:学习使用Promise

前言最近在开发中遇到一个问题:Table行内有下拉组件四级联动,而且还能够增加新行,每个新行又是四级联动,问:如何解决?想了半天于是应用Promise解决,让我从新对Promise有了意识。 Promise详解通过MDN 官网文档对Promise有段介绍:Promise 对象用于示意一个异步操作的最终实现 (或失败)及其后果值。 一个 Promise 对象代表一个在这个 promise 被创立进去时不肯定已知的值。它让您可能把异步操作最终的胜利返回值或者失败起因和相应的处理程序关联起来。 这样使得异步办法能够像同步办法那样返回值:异步办法并不会立刻返回最终的值,而是会返回一个 promise,以便在将来某个时候把值交给使用者。 一个 Promise 必然处于以下几种状态之一: 待定(pending): 初始状态,既没有被兑现,也没有被回绝。已兑现(fulfilled): 意味着操作胜利实现。已回绝(rejected): 意味着操作失败。待定状态的 Promise 对象要么会通过一个值被兑现(fulfilled),要么会通过一个起因(谬误)被回绝(rejected)。当这些状况之一产生时,咱们用 promise 的 then 办法排列起来的相干处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就曾经被兑现或被回绝了,那么这个处理程序就会被调用,因而在实现异步操作和绑定解决办法之间不会存在竞争状态。 因为 Promise.prototype.then 和 Promise.prototype.catch 办法返回的是 promise, 所以它们能够被链式调用。 1、构造函数 Promise()创立一个新的 Promise 对象。该构造函数次要用于包装还没有增加 promise 反对的函数。 2、静态方法 Promise.all(iterable)这个办法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都胜利的时候才会触发胜利,一旦有任何一个iterable外面的promise对象失败则立刻触发该promise对象的失败。这个新的promise对象在触发胜利状态当前,会把一个蕴含iterable里所有promise返回值的数组作为胜利回调的返回值,程序跟iterable的程序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all办法常被用于解决多个promise对象的状态汇合。(能够参考jQuery.when办法---译者注) Promise.allSettled(iterable)等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已回绝(rejected))。返回一个promise,该promise在所有promise实现后实现。并带有一个对象数组,每个对象对应每个promise的后果。 Promise.any(iterable)接管一个Promise对象的汇合,当其中的一个 promise 胜利,就返回那个胜利的promise的值。 Promise.race(iterable)当iterable参数里的任意一个子promise被胜利或失败后,父promise马上也会用子promise的胜利返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。 Promise.reject(reason)返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的解决办法 Promise.resolve(value)返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then办法的对象),返回的Promise对象的最终状态由then办法执行决定;否则的话(该value为空,根本类型或者不带then办法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then办法。通常而言,如果您不晓得一个值是否是Promise对象,应用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象模式应用。 应用Promise通过下面能够具体理解Promise的静态方法,起初就是应用Promise实例, 创立Promise Promise 对象是由关键字 new 及其构造函数来创立的。该构造函数会把一个叫做“处理器函数”(executor function)的函数作为它的参数。这个“处理器函数”承受两个函数——resolve 和 reject ——作为其参数。当异步工作顺利完成且返回后果值时,会调用 resolve 函数;而当异步工作失败且返回失败起因(通常是一个谬误对象)时,会调用reject 函数。 const myFirstPromise = new Promise((resolve, reject) => { // ?做一些异步操作,最终会调用上面两者之一: // // resolve(someValue); // fulfilled // ?或 // reject("failure reason"); // rejected});想要某个函数领有promise性能,只需让其返回一个promise即可。 ...

August 10, 2021 · 2 min · jiezi

关于ecmascript:E9二开文档

E9二开文档@Author: 福州ebu 杨文杰 1. 前端开发根底1.1 ECMAScript6 的应用ECMAScript 和 JavaScript 的关系是:前者是后者的规格,后者是前者的一种实现。 ES6 既是一个历史名词,也是一个泛指,含意是 5.1 版当前的 JavaScript 的下一代规范,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年公布的正式版本的语言规范。本书中提到 ES6 的中央,个别是指 ES2015 规范,但有时也是泛指 “下一代 JavaScript 语言”。 1.2 ES6常见的语法1.2.1 let 和 const 命令ES6 新增了let命令,用来申明变量。它的用法相似于var,然而所申明的变量,只在let命令所在的代码块内无效。 { let a = 10; var b = 1;}a // ReferenceError: a is not defined.b // 1const申明一个只读的常量。一旦申明,常量的值就不能扭转。 const PI = 3.1415;PI // 3.1415PI = 3;// TypeError: Assignment to constant variable.1.2.2 变量的解构赋值ES6 容许依照肯定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring) 如果解构不胜利,变量的值就等于undefined 数组的解构赋值let [foo, [[bar], baz]] = [1, [[2], 3]];foo // 1bar // 2baz // 3let [ , , third] = ["foo", "bar", "baz"];third // "baz"let [x, , y] = [1, 2, 3];x // 1y // 3let [head, ...tail] = [1, 2, 3, 4];head // 1tail // [2, 3, 4]let [x, y, ...z] = ['a'];x // "a"y // undefinedz // []对象的解构赋值// 常见用法let { bar, foo, baz } = { foo: 'aaa', bar: 'bbb' };foo // "aaa"bar // "bbb"baz // undefined// foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foolet { foo: baz } = { foo: 'aaa', bar: 'bbb' };baz // "aaa"foo // error: foo is not defined// 嵌套应用let obj = { p: [ 'Hello', { y: 'World' } ]};// 第一个p作为变量,则进行赋值,第二个p作为模式,不会进行赋值let { p, p: [x, { y }] } = obj;x // "Hello"y // "World"p // ["Hello", {y: "World"}]1.2.3 ... 运算符函数 rest 参数的应用function f(a, ...b) { console.log(a, b)}f(1,2,3,4,5) // 1 [2,3,4,5]数组拆解const a = [1,2,3]const b = [4,5,6]const c = [...a, ...b]c // [1,2,3,4,5,6]对象拆解const obj = { a: 111, b:222 }const copyObj = { ...obj, c: 333 }copyObj // { a: 111, b:222, c: 333 }1.2.4 函数的扩大参数默认值:ES6 容许为函数的参数设置默认值,即间接写在参数定义的前面。// 根本用法function log(x, y = 'World') { console.log(x, y);}log('Hello') // Hello Worldlog('Hello', 'China') // Hello Chinalog('Hello', '') // Hello// 参数默认值能够与解构赋值的默认值,联合起来应用。function foo({x, y = 5}) { console.log(x, y);}foo({}) // undefined 5foo({x: 1}) // 1 5foo({x: 1, y: 2}) // 1 2foo() // TypeError: Cannot read property 'x' of undefined箭头函数:ES6 容许应用(=>)定义函数。// 根本用法var f = v => v;// 等同于var f = function (v) { return v;};// 箭头函数能够与变量解构联合应用。const full = ({ first, last }) => first + ' ' + last;// 等同于function full(person) { return person.first + ' ' + person.last;}// rest 参数与箭头函数联合const numbers = (...nums) => nums;numbers(1, 2, 3, 4, 5) // [1,2,3,4,5]const headAndTail = (head, ...tail) => [head, tail];headAndTail(1, 2, 3, 4, 5) // [1,[2,3,4,5]]1.3 React根底React 是一个用于构建用户界面的 Javascript 库。 ...

July 30, 2021 · 9 min · jiezi

关于ecmascript:ES6新增语法六Generator函数详解

上篇文章《ES6新增语法(五)——Promise详解》咱们介绍Promise,Promise一旦执行就无奈暂停和勾销,所以ES6引入了Generator函数,能够通过yield关键字,把函数的执行流程挂起,能够扭转执行流程。 什么是Generator函数?Generator次要是异步编程,用来封装异步工作,是一个异步工作的容器,能够让函数依照咱们指定的时候执行或者暂停。 应用语法: function *name(){ ... yield; //须要暂停的时候加yield ... yield; ... } const p = name(); p.next() //调用函数,执行到第一个yield处进行 p.next() //从上一个yeild开始执行,到下一个yield处为止 Generator与一般函数区别1> 定义函数的时候比一般函数多了一个 * 号。 2> 调用的时候,一般函数名后加圆括号间接调用,而Generator并不执行,返回的也不是函数运行后果,而是指向外部的状态的指针对象,必须调用遍历器对象的next()办法,使得指针移向下一个状态。每次调用next,指针就会从上一次停下的中央开始执行到下一个yield。 3> 一般函数是无奈暂停的,但Generator函数是分段执行的,yield是暂停标记,而next()能够复原执行。 generator实例如下: function *show(){ console.log('1') yield; console.log('2')}const p = show();p.next(); //执行第一个yield之前内容,打印1p.next(); //执行yield之后内容,打印2yield特点1> 能够传参数,只能传一个参数 function *chuancan(){ console.log('1') let a = yield; console.log('a',a)//12}const gen = chuancan();gen.next()gen.next(12)2> 返回值 function *fanhui(){ console.log('1'); yield 55; console.log('2');}let fh = fanhui()let res1 = fh.next()console.log(res1) //{value: 55, done: false}let res2 = fh.next()console.log(res2) //{value: undefined, done: true}generator函数中也能够增加 return ...

July 21, 2021 · 1 min · jiezi

关于ecmascript:ES6新增语法五Promise详解

Promise介绍promise是一个对象,从它能够获取异步操作的音讯。有all、race、reject、resolve这几个办法,原型上有then、catch等办法。 Promise的两个特点: 对象的状态不受外界影响。Promise对象获取的是异步操作,有三种状态:pending(进行中)、fulfilled(已胜利)、reject(已失败)。除了异步操作的后果,其余操作都无奈扭转这个状态。一旦状态扭转,就不会再变。从pending变为fulfilled和从pending变为rejected状态,只有处于fulfilled和rejected,状态就不会再变。状态的毛病: 无奈勾销Promise,一旦新建它就会立刻执行,无奈中途勾销。 如果不设置回调函数,Promise外部抛出谬误,不会反馈到内部。 当处于pending状态时,无奈得悉目前停顿到哪一阶段。 应用语法: let p = new Promise( (resolve,reject)=>{ //resolve 和reject是两个函数 }) p.then( ()=>{}, // 传入的resolve函数,resolve翻译成中文是解决 ()=>{} //传入的reject函数,reject翻译成中文是回绝 ).catch((reason,data)=>{ console.log("catch失败执行回调抛出起因",reason) }) then办法then办法接管两个参数作为参数,第一个参数是Promise执行胜利时的回调,第二个参数是Promise执行失败的回调,两个函数只会有一个被调用。 通过.then增加的回调函数,不论什么时候,都会被调用,而且能够增加多个回调函数,会一次依照程序并且独立运行。 const p =new Promise((resolve,reject)=>{ resolve("胜利")})p.then((res)=>{ console.log(res)//返回胜利},(err)=>{ console.log(err)})带有多个回调函数时 const p =new Promise((resolve,reject)=>{ resolve(1)})p.then((res1)=>{ console.log('res1',res1) // 1 return res1 * 2;}).then((res2)=>{ console.log('res2',res2) //2}).then((res3)=>{ console.log('res3',res3) //undefined return Promise.resolve('resolve')}).then(res4=>{ console.log('res4',res4) //resolve})catch用法与Promise对象办法then并行的还有一个catch办法,用来捕捉异样的,与try...catch相似, const p1 = new Promise((resolve,reject)=>{ var num = Math.random()*10 ;//随机生成一个0-10的数字 console.log("num",num) if(num > 5){ resolve('大于5') }else{ reject("小于5") }})p1.then(res=>{ console.log("res",res) // res 大于5}).catch(err=>{ console.log("err",err) // err 小于5})all办法all办法示意所有的异步操作实现后才执行回调,返回后果,返回的数据是个数组,多个申请返回的数据组合。与then办法同级。 ...

July 20, 2021 · 1 min · jiezi

关于ecmascript:ES新特性

es6: https://es6.ruanyifeng.com/es6-es12: https://segmentfault.com/a/11...

July 17, 2021 · 1 min · jiezi

关于ecmascript:Iterator可迭代接口

for..of..for...of... 作为遍历所有数据结构的对立形式 for遍历一般数组 for in 遍历键值对 forEach 数组的遍历办法 const arr = [100,200,300,400]for(const item of arr){ console.log(item); //拿到的是每一个元素,而不是对应的下标 if(item>300){ break; }}//取代forEach办法,for..of..能够应用关键词break随时终止,forEach无奈终止遍历arr.forEach(function(item,index){})其余的遍历 //伪数组的遍历(arguments)// dom操作时一些元素节点的列表 的遍历//Set ,Map对象const s = new Set(['foo',"bar"])for(var i of s){ console.log(i); //foo bar}配合构造应用 const m = new Map()m.set({a:1},"value")m.set(true,100)for(var mm of m){ console.log(mm); //[ { a: 1 }, 'value' ] [ true, 100 ]}//通过解构优化下面的for..offor(var [key,value] of m){ console.log(key,value); //{ a: 1 } value || true 100}留神,遍历对象会报错 //遍历对象会报错const ddd = {naz:"mcgee",baz:100}for(var item of ddd){ console.log(item); //TypeError: ddd is not iterable}Iterable 可迭代接口for..of循环时一种数据对立遍历的形式 ...

May 18, 2021 · 2 min · jiezi

关于ecmascript:Symbol

Symbol类型Symbol新的原始数据类型 (符号)示意举世无双的值 对象的key能够应用Symbol 具备动态属性和静态方法 不反对 new Symbol() 解决不同文件应用公共变量,相互影响, //shared.js ==================================const cache = {}//a.js ======================================//cache['a_foo'] || cache['b_foo'] 以前的做法,约定好不同文件下的key,然而实质上并没有解决问题只是躲避了问题cache['foo'] = "VLAUE" //b.js ========================================cache['foo'] = "VALUE1111"const s = Symbol()console.log(s); //Symbol()console.log(typeof s); //symbolconsole.log(Symbol() === Symbol(),Symbol("aa") === Symbol("aa")); //false falseconsole.log(Symbol("aa"),Symbol("bb")) //形容文本 Symbol(aa) Symbol(bb)能够增加为属性名 const obj1 = { [Symbol()]:123}console.log(obj1);案例 //创立公有变量const name = Symbol()const person = { [name]:"zxa", say(){ console.log(this[name]); }}//b.js// person[Symbol()] //无奈创立完全相同的Symbol,取不到成员person.say() //能够拿到一般成员静态方法 const s1 = Symbol.for() //外部保护了一个全局的注册表,为增加的标识字符串和Symbol值提供一一对应,下次再搜所给定key反现有symbol会返回不会新创建const s2 = Symbol.for()console.log(s1 === s2); //true 如果增加形容字符串,则增加的形容字符串必须统一才true console.log(Symbol.for(true) === Symbol.for("true")); //true 会转化成字符串留神Symbol作为key取不到 ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:SetMap数据结构

Set数据结构ES6 提供了新的数据结构 Set。它相似于数组,然而成员的值都是惟一的,没有反复的值。 Set自身是一个构造函数,用来生成 Set 数据结构。 const s = new Set()s.add(1).add(2).add(1).add(3) //增加,可链式调用,不反复console.log(s); //Set {1,2,3}Set遍历对象 //set对象遍历s.forEach(i=>console.log(i))for(let i of s){ console.log(i);}console.log(s.size); //set对象长度console.log(s.has(100)); //falseconsole.log(s.delete(2)); //trueconsole.log(s); //{1,3}console.log(s.clear()); //革除汇合内的全部内容利用场景 //数组去重const arr = [1,1,1,3,2,1,4,4]const ss = new Set(arr)const narr = Array.from(ss) //转化成实在数组console.log(ss,narr);const result = [...ss] //转化成实在数组console.log(result); Map数据结构相似于对象,实质上都是键值对汇合 原始的对象key无论什么类型都会被转化成字符串 Map是严格意义上的键值对汇合,能够应用任意类型的键 Map与对象的区别 简略的说,Object类型就是增加计算属性,或者通过内部增加属性,他都会转化成string,且Object的key只容许string或symbol,而map很好解决了键的类型问题 传统的增加键值对 const obj = { name:"mcgee"}obj[true] = "value"obj[11] = "value"obj[{a:1}] = "value"console.log(Object.keys(obj)) //[ '11', 'name', 'true', '[object Object]' ]任意类型的Map键值对 const m = new Map()const str = {a:1};m.set(str,"value") //key , valuem.set(11,"asd")console.log(m);操作方法 ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:Class类

Class类以前创立构造函数 function Person(name){this.name = name}Person.prototype.say = function(){console.log( `hi, my name is ${this.name}`);}ES6 的类,齐全能够看作构造函数的另一种写法 class Point {// ...}typeof Point // "function"Point === Point.prototype.constructor // trueclass Point {constructor() { // ...}toString() { // ...}toValue() { // ...}}// 等同于Point.prototype = {constructor() {},toString() {},toValue() {},};constructor 办法一个类必须有constructor()办法,如果没有显式定义,一个空的constructor()办法会被默认增加 constructor()办法默认返回实例对象(即this),齐全能够指定返回另外一个对象 class Foo { constructor() { return Object.create(null); }}new Foo() instanceof Foo// false实例办法,静态方法 static class Person{ //定义一个person类型constructor(name){ //构造函数 this.name = name //以后person类型的实例对象}say(){ console.log( `hi, my name is ${this.name}`);}static create (name){ //静态方法外部this不会指向某个实例对象,而是以后的类型 return new Person(name)}}const p = new Person("mcgee")p.say()const jack = Person.create("jack")jack.say()类的继承 extends子类必须在constructor办法中调用super办法,否则新建实例时会报错。这是因为子类本人的this对象,必须先通过父类的构造函数实现塑造,失去与父类同样的实例属性和办法,而后再对其进行加工,加上子类本人的实例属性和办法。如果不调用super办法,子类就得不到this对象 ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:ProxyReflect

ProxyProxy 能够了解成,在指标对象之前架设一层“拦挡”,外界对该对象的拜访,都必须先通过这层拦挡,因而提供了一种机制,能够对外界的拜访进行过滤和改写。Proxy 这个词的原意是代理,用在这里示意由它来“代理”某些操作,能够译为“代理器” 监督某个对象的属性读写Object.defineProperty (vue3.0之前,3.0之后应用proxy) 简略介绍下 Object.defineProperty Object.defineProperty(obj,"key",{enumerable:false, //key属性是否能够在for..in || Object.keys()中被枚举configurable:false, //key属性是否可被删除,以及除 value 和 writable 个性外的其余个性是否能够被批改writable:false, //不可写入,也就是不可更改obj.keyvalue:undefined,get:undefined,set:undefined})初始化一个 new Proxy实例 const person ={name:"mcgee",age:18}//创立proxy构造函数,参数1代理的对象,参数2执行对象const personProxy = new Proxy(person,{get(target,property){ // console.log(target,property); //{ name: 'mcgee', age: 18 } name // return 100 //内部拜访属性的返回值 返回值能够是任意类型 return property in target ? target[property]:'default'},set(target,property,value){ // console.log(target,property,value); if(property === "age" && !Number.isInteger(value)){ throw new Error(`${value} is not an int`) } return target[property] == value //返回值能够是任意类型}})console.log(personProxy.name) //100 "mcgee"console.log(personProxy.xxx); //defaultpersonProxy.render = trueconsole.log(personProxy); //增加了个render为true的属性// personProxy.age = "aa" //Error: aa is not an int具体13个办法例子详见此处 ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:对象的扩展

对象的扩大对象字面量的加强 Object.is() Object.assign() Object.getOwnPropertyDescriptors() Object.keys(),Object.values(),Object.entries() 对象字面量的加强对象内属性简写,对象内办法简写,留神简写的是function不是箭头函数 const obj = { // bar:bar bar, // method:function(){}, method(){ //留神这种简写,只是针对function console.log(this); //this指向obj }, [Math.random()]:123, //计算属性名 [1+1]:2}Object.is()Object.is('foo', 'foo')// trueObject.is({}, {})// false与===不同之处只有两个:一是+0不等于-0,二是NaN等于本身。 两等在比拟之前能够进行类型转化,三等严格判断类型,对象比拟地址值 +0 === -0 //trueNaN === NaN // falseObject.is(+0, -0) // falseObject.is(NaN, NaN) // trueObject.assign()Object.assign()办法用于对象的合并,将源对象(source)的所有可枚举属性,复制到指标对象(target) 第一个参数是指标对象,前面的参数都是源对象 同名属性,则前面的属性会笼罩后面的属性 返回值就是指标对象,此时bar援用曾经改成合并后的对象 const target = { a: 1, b: 1 };const source1 = { b: 2, c: 2 };const source2 = { c: 3 };const result = Object.assign(target, source1, source2); target // {a:1, b:2, c:3}console.log(result === target) trueObject.getOwnPropertyDescriptors()ES5 的Object.getOwnPropertyDescriptor()办法会返回某个对象属性的形容对象(descriptor)。ES2017 引入了Object.getOwnPropertyDescriptors()办法,返回指定对象所有本身属性(非继承属性)的形容对象 ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:数组的扩展

数组的扩大开展运算符 Array.from() Array.of() find(),findIndex() fill() entries(),keys(),values() includes() flat() 开展运算符 console.log(...[1, 2, 3])// 1 2 3console.log(1, ...[2, 3, 4], 5)// 1 2 3 4 5[...document.querySelectorAll('div')]// [<div>, <div>, <div>]Array.from()Array.from办法用于将两类对象转为真正的数组:相似数组的对象(array-like object)和可遍历(iterable)的对象(包含 ES6 新增的数据结构 Set 和 Map) function foo() { var args = Array.from(arguments); // ...}Array.from('hello')// ['h', 'e', 'l', 'l', 'o']let namesSet = new Set(['a', 'b'])Array.from(namesSet) // ['a', 'b']Array.of()将一组值,转换为数组 Array.of(3, 11, 8) // [3,11,8]Array.of(3) // [3]Array.of(3).length // 1Array()办法没有参数、一个参数、三个参数时,返回的后果都不一样。只有当参数个数不少于 2 个时,Array()才会返回由参数组成的新数组。参数只有一个正整数时,实际上是指定数组的长度 Array.of() // []Array.of(undefined) // [undefined]Array.of(1) // [1]Array.of(1, 2) // [1, 2]数组实例的find()和findIndex()办法数组实例的find办法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员顺次执行该回调函数,直到找出第一个返回值为true的成员,而后返回该成员。如果没有符合条件的成员,则返回undefined ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:函数的扩展

函数的扩大函数参数的默认值 //老办法通过函数外部增加默认值function foo(value){// value = value || true // true为默认值,如果传入false 那么也会应用默认值,很显著谬误value = value === undefined?true:valueconsole.log(value);}foo(false)//给参数增加默认值function bar(value=true){ //多参数时,默认值要放在最初}函数的length属性指定了默认值后,length属性将失真,rest 参数也不会计入length属性 (function (a) {}).length // 1(function (a = 5) {}).length // 0(function (a, b, c = 5) {}).length // 2(function(...args) {}).length // 0函数的作用域函数进行申明初始化时,参数会造成一个独自的作用域(context)。等到初始化完结,这个作用域就会隐没。这种语法行为,在不设置参数默认值时,是不会呈现的 var x = 1;function f(x, y = x) { console.log(y);}f(2) // 2下面代码中,参数y的默认值等于变量x。调用函数f时,参数造成一个独自的作用域。在这个作用域外面,默认值变量x指向第一个参数x,而不是全局变量x,所以输入是2 let x = 1;function f(y = x) { let x = 2; console.log(y);}f() // 1下面代码中,函数f调用时,参数y = x造成一个独自的作用域。这个作用域外面,变量x自身没有定义,所以指向外层的全局变量x。函数调用时,函数体外部的局部变量x影响不到默认值变量x。如果此时,全局变量x不存在,就会报错。 ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:解构

数组解构依据数组下标提取 const arr = [1,2,3]const [foo,bar,baz] = arr //等值const [,,baz] = arr //选值const [foo,...rest] = arr // 残余值,...最初一个成员应用,是个新数组const [foo] = arr //不齐全解构const [foo,bar,baz,more,...bao] = arr //more为undefined,bao=[]const [foo,bar,baz,more="10",] = arr //默认值 more取不到取默认值const [foo] = [] //foo=undefined如果右侧不是可遍历的构造(Iterator)会报错 let [foo] = 1;let [foo] = false;let [foo] = NaN;let [foo] = undefined;let [foo] = null;let [foo] = {};数组解构默认值当一个数组成员严格等于undefined,默认值会失效 let [x = 1] = [undefined]; x // 1let [x = 1] = [null]; x // null对象解构数组解构依据下标程序解构,对象解构依据属性名匹配提取,它没有秩序 ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:let-与块级作用域

块内变量内部无法访问 if(true){let foo = "mcgee0731"}console.log(foo); //foo is not defined...for(let i=0;i< 3;i++>){}console.log(i) //i is not definedvar对循环的影响 for(var i=0;i< 3;i++){for(var i=0;i< 3;i++){ console.log(i);}}//内层循环完后 `i = 3` 到外层循环时,无奈再进入。打印0,1,2三次而不是九次// 循环内处理事件时,事件内拜访计数器var events = [{},{},{}]for(var i=0;i< events.length;i++){events[i].onclick = function(){ console.log(i)}}events[0].onclick() //无论哪一项输入都是3通过IIFE模式处理事件计数器绑定 // 应用闭包解决变量var events = [{},{},{}]for(var i=0;i< events.length;i++){events[i].onclick = (function(i){ return function(){ console.log(i) }})(i)}events[0].onclick() //0应用let 解决 for循环的问题 for(let i=0;i< 3;i++){for(let i=0;i< 3;i++){ console.log(i);}}...var events = [{},{},{}]for(let i=0;i< events.length;i++){events[i].onclick = function(){ console.log(i)}}events[0].onclick() //0for循环内有两层作用域,咱们对上面的办法进行拆解for(let i =0;i < 3;i++){ let i = "foo" console.log(i);}拆解成...let i =0; //这是for循环的作用域 if(i<3){ let i = "foo" //这个n是块内的n,}i++会执行三次不存在变量晋升 ...

May 18, 2021 · 1 min · jiezi

关于ecmascript:ES6-Reflect反射机制

Reflect handlergetsethasapplycalldefineProperty(定义属性,可能细化属性形容)deletePropertyisExtensiblepreventExtensionsgetPrototypeOf(读取原型对象)setPrototypeOf(设置原型对象)ownKeysgetOwnPropertyDescriptorconstructSymbol(Symbol.toStringTag): "Reflect"

May 6, 2021 · 1 min · jiezi

关于ecmascript:ES6数值的扩展

本节咱们学习 ES6 中的罕用数据类型之数值(Number)类型。ES6 中除了 JavaScript 中的六种数据类型之外,还引入了一种新的原始数据类型 Symbol,它是 JavaScript 语言的第七种数据类型: Number (数值)String(字符串)Boolean(布尔值)Object(对象)undefinednullSymbol二进制和八进制表示法ES6 中提供了二进制和八进制数值的新的写法: 二进制的新写法能够应用前缀 0b 或者 0B 示意。let a = 0b1001;console.log(a); // 输入:9八进制的新写法能够应用前缀 0o 或者0O示意。let b = 0o345;console.log(b); // 输入:229从 ES5 开始,在严格模式之中,八进制就不再容许应用前缀 0 示意,ES6 进一步明确,要应用前缀0o示意。 // 非严格模式(function(){console.log(0o11 === 011);})() // true // 严格模式(function(){ 'use strict'; console.log(0o11 === 011);})() 执行代码后,报错信息如下所示: SyntaxError: Octal literals are not allowed in strict mode.如果要将 0b 和 0o 前缀的字符串数值转为十进制,要应用 Number 办法。 示例:console.log(Number('0b110')); // 输入:6console.log(Number('0o43')); // 输入:35Number对象的罕用办法ES6 在 Number 对象上提供了一些办法,咱们一起来看一下。 ...

December 18, 2020 · 2 min · jiezi

关于ecmascript:ES6中的Promise和Generator详解

简介ES6中除了上篇文章讲过的语法新个性和一些新的API之外,还有两个十分重要的新个性就是Promise和Generator,明天咱们将会具体解说一下这两个新个性。 Promise什么是PromisePromise 是异步编程的一种解决方案,比传统的解决方案“回调函数和事件”更正当和更弱小。 所谓Promise,简略说就是一个容器,外面保留着某个将来才会完结的事件(通常是一个异步操作)的后果。 从语法上说,Promise 是一个对象,从它能够获取异步操作的音讯。 Promise的特点Promise有两个特点: 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已实现,又称 Fulfilled)和Rejected(已失败)。 只有异步操作的后果,能够决定以后是哪一种状态,任何其余操作都无奈扭转这个状态。 一旦状态扭转,就不会再变,任何时候都能够失去这个后果。Promise对象的状态扭转,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。 这与事件(Event)齐全不同,事件的特点是,如果你错过了它,再去监听,是得不到后果的。 Promise的长处Promise将异步操作以同步操作的流程表达出来,防止了层层嵌套的回调函数。 Promise对象提供对立的接口,使得管制异步操作更加容易。 Promise的毛病无奈勾销Promise,一旦新建它就会立刻执行,无奈中途勾销。如果不设置回调函数,Promise外部抛出的谬误,不会反馈到内部。当处于Pending状态时,无奈得悉目前停顿到哪一个阶段(刚刚开始还是行将实现)。Promise的用法Promise对象是一个构造函数,用来生成Promise实例: var promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作胜利 */){ resolve(value); } else { reject(error); } });promise能够接then操作,then操作能够接两个function参数,第一个function的参数就是构建Promise的时候resolve的value,第二个function的参数就是构建Promise的reject的error。 promise.then(function(value) { // success }, function(error) { // failure });咱们看一个具体的例子: function timeout(ms){ return new Promise(((resolve, reject) => { setTimeout(resolve,ms,'done'); }))}timeout(100).then(value => console.log(value));Promise中调用了一个setTimeout办法,并会定时触发resolve办法,并传入参数done。 最初程序输入done。 Promise的执行程序Promise一经创立就会立马执行。然而Promise.then中的办法,则会等到一个调用周期过后再次调用,咱们看上面的例子: let promise = new Promise(((resolve, reject) => { console.log('Step1'); resolve();}));promise.then(() => { console.log('Step3');});console.log('Step2');输入:Step1Step2Step3Promise.prototype.then()then办法返回的是一个新的Promise实例(留神,不是原来那个Promise实例)。因而能够采纳链式写法,即then办法前面再调用另一个then办法. ...

December 17, 2020 · 3 min · jiezi

关于ecmascript:eshbase学习

第一步:搞清楚这个框架(技术)是干什么的,解决了什么问题和痛点,同类“竞品”还有哪些 第二步:怎么用 第三步:理解原理 ElasticsearchWHATElasticsearch 是一个基于 Lucene 的 搜寻服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。 Elasticsearch 是用 Java 语言开发的,是一种风行的企业级搜索引擎。 Elasticsearch 的底层是开源库 Lucene。咱们没有方法间接应用 Lucene ,必须本人写代码去调用它的接口。Elasticsearch 是 Lucene 的封装,提供了 RESTful API 的操作接口,开箱即用。 WHY应用数据库 来做搜寻业务,不能很好的满足需要。 尽管某一水平上也能够视为数据库,然而它更次要的身份还是一个优良的全文搜索引擎。它的呈现解决了一部分传统关系型数据库和NoSQL非关系型数据库所没有方法高效实现的一些工作,比方高效的全文检索,结构化检索,甚至是数据分析。 响应工夫eg:数据库在做含糊查问时,如LIKE 语句,它会遍历整张表,同时进行字符串匹配。 而 es 是基于 顺叙索引 的 ,检索速度十分快。 分词Elasticsearch反对中文分词插件 相关性Elasticsearch 反对全文搜寻和相关度评分。这样在返回后果就会依据分数由高到低排列。分数越高,意味着和查问语句越相干。 可视化界面MySQL的Navicat Elasticsearch 的 Kibana HOW入门应用 HbaseWHTAHadoop Database HBase 是Apache的 Hadoop 我的项目的子项目。 HBase 是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统。 HBase 不同于个别的关系数据库,它是一个适宜于非结构化数据存储的数据库, HBase基于列的而不是基于行的模式. HBase的原型是Google的BigTable论文。 WHYMySQL无奈满足海量的数据存储, MySQL -> 面向行存储 HBase -> 面向行存储 HOWHBase概念视图图 表名:webtable 两行:com.cnn.www 和 com.example.www ...

November 13, 2020 · 1 min · jiezi

关于ecmascript:ES6ES7ES8学习指南

作者:CrazyCodeBoy链接:https://www.jianshu.com/p/1ae... 概述ES全称ECMAScript,ECMAScript是ECMA制订的标准化脚本语言。目前JavaScript应用的ECMAScript版本为ECMAScript-262。 ECMAScript 规范建设在一些原有的技术上,最为驰名的是 JavaScript (网景) 和 JScript (微软)。它最后由网景的 Brendan Eich 创造,第一次呈现是在网景的 Navigator 2.0 浏览器上。Netscape 2.0 以及微软 Internet Explorer 3.0 后序的所有浏览器上都有它的身影。 理解这些个性,不仅能使咱们的编码更加的符合规范,而且能进步咱们Coding的效率。ES6的个性ES6的个性比拟多,在 ES5 公布近 6 年(2009-11 至 2015-6)之后才将其标准化。两个公布版本之间时间跨度很大,所以ES6中的个性比拟多。 在这里列举几个罕用的: 类模块化箭头函数函数参数默认值模板字符串解构赋值延展操作符对象属性简写PromiseLet与Const1.类(class)对相熟Java,object-c,c#等纯面向对象语言的开发者来说,都会对class有一种非凡的情怀。ES6 引入了class(类),让JavaScript的面向对象编程变得更加简略和易于了解。 class Animal { // 构造函数,实例化的时候将会被调用,如果不指定,那么会有一个不带参数的默认构造函数. constructor(name,color) { this.name = name; this.color = color; } // toString 是原型对象上的属性 toString() { console.log('name:' + this.name + ',color:' + this.color); } } var animal = new Animal('dog','white');//实例化Animal animal.toString(); console.log(animal.hasOwnProperty('name')); //true console.log(animal.hasOwnProperty('toString')); // false console.log(animal.__proto__.hasOwnProperty('toString')); // true class Cat extends Animal { constructor(action) { // 子类必须要在constructor中指定super 函数,否则在新建实例的时候会报错. // 如果没有置顶consructor,默认带super函数的constructor将会被增加、 super('cat','white'); this.action = action; } toString() { console.log(super.toString()); } } var cat = new Cat('catch') cat.toString(); // 实例cat 是 Cat 和 Animal 的实例,和Es5完全一致。 console.log(cat instanceof Cat); // true console.log(cat instanceof Animal); // true 2.模块化(Module)ES5不反对原生的模块化,在ES6中模块作为重要的组成部分被增加进来。模块的性能次要由 export 和 import 组成。每一个模块都有本人独自的作用域,模块之间的互相调用关系是通过 export 来规定模块对外裸露的接口,通过import来援用其它模块提供的接口。同时还为模块发明了命名空间,避免函数的命名抵触。 ...

November 9, 2020 · 6 min · jiezi

重新认识const-和-let

es6中提供2个声明变量的关键字const 和 let首先,这2个都是块级作用域,在此之前JavaScript是没有块级作用域的概念的。并且在他们的变量声明之前访问都是不允许的。区别就在于,const 声明之后的变量不允许重新赋值。 这里的const 可不像 java中的const那样,不能 理解为不可变,常量。JavaScript中的const,是不能重新声明赋值,但是你改他里面的属性值,删里面的属性都是可以的。如果想要达到上面提到的 java中的const那样的效果,即不能修改。可以使用Object.freeze(obj)达到效果。

July 3, 2020 · 1 min · jiezi

ES6的快速理解

第一节:forEach曾经的遍历for,难理解!最后返回出来的就是这几个 var name = ['Aaron','Ben','Cands','Dade']for(var i=0; i<name.length; i++){ console.log(name[i])}forEach很简单,把你要遍历的东西加一个forEach,把你所有值批量一个名字a, 他就会按顺序给你返回 var name = ['Aaron','Ben','Cands','Dade']name.forEach(function(a){ console.log(a)})小实验,把123455678加一起鸡鸡有这些,用一个sum鸡窝依次放进去!最后返回55只小鸡鸡 var jj = [1,2,3,4,5,6,7,8,9,10]var sum = 0jj.forEach(function(n){ sum+=n})console.log(sum)链接同样的用这个方法更方便!过滤返回来未选中的留下,其他的隐藏。 第二节:map说白了,就是把原本的数组复制一份,然后改改值.再起一个名字曾经养了一堆鸡鸡,然后把原本的鸡鸡乘以2然后返回的价格起一个新的名字叫做KFC。鸡鸡本身便宜,改名就贵了一圈 var jj = [1,2,3,4,5,6,7,8,9,10]var kfc = jj.map(function(n){ return n*2})console.log(kfc)第三节:filter俗称的过滤器,简单的说 新冠状病毒里生病呈阳性的站出来这种就是过滤 var bd = [ {name:"刘忙", type:"Yang"}, {name:"马超", type:"Yin"}, {name:"赵三", type:"Yin"}, {name:"周敏", type:"Yang"}]var txt = bd.filter(function(a){ return a.type === 'Yang'})console.log(txt)第三节:find

June 16, 2020 · 1 min · jiezi

你可能错过的现代-JavaScript-特性

作者:Jimmy Breck-McKye翻译:疯狂的技术宅 原文:http://www.breck-mckye.com/bl... 未经允许严禁转载 尽管我在过去 7 年中几乎每天都在写 JavaScript 代码,但不得不承认,我实际上并不是很注意 ES 语言的发布声明。 async/await 和 Proxies 之类的主要特性是一回事,但是每年都有稳定的小规模、渐进式的改进在不断涌现,因为总有一些东西需要学习。 所以在本文中,我收集了一些现代 JavaScript 特性,这些特性在首次发布时并没有带来太多的关注。其中一些只是编码质量的提高,而另外一些确实很方便,可以减少很多代码量。以下是你可能会错过的一些信息: ES2015二进制和八进制在 JavaScript 中,二进制操作并不常见,但有时也会遇到,否则无法切实解决你的问题。你可能正在为低功耗设备编写高性能代码,将位压缩到本地存储中,在浏览器中进行像素 RGB 操作,或者必须处理紧密打包的二进制数据格式。 这可能意味着有很多工作需要对二进制数字进行处理,我一直觉得用十进制也能做这些事。好吧,ES6 为此添加了一个二进制数字格式:0b const binaryZero = 0b0;const binaryOne = 0b1;const binary255 = 0b11111111;const binaryLong = 0b111101011101101;这使得处理二进制标志非常容易: // Pizza toppingsconst olives = 0b0001;const ham = 0b0010;const pineapple = 0b0100;const artechoke = 0b1000;const pizza_ham_pineapple = pineapple | ham;const pizza_four_seasons = olives | ham | artechoke;对于八进制数也是如此。在 JS 世界中,这些领域有点小众,但在网络和某些文件格式中却很常见。现在你可以用语法 0o 处理八进制。 ...

November 5, 2019 · 2 min · jiezi

Vue源码理解之自定义学习框架abandon

作者:心叶时间:2019-11-02 18:13 这是一篇用于说明abandon v1版本的项目,abandon是一个用于vue.js源码学习而开发的小型前端框架。 abandon地址:https://github.com/yelloxing/abandon 目录结构最外层大体说明一下: demo:使用用例dist:打包后的框架代码scripts:源码编译脚本src:源码别的文件就不说了,我们主要是来看看src源码里面的几个主要文件。 大家看的时候,应该先看src/core/instance/index.js,下面,我们来说明一下其中必要重要的几个文件。 入口文件目录:src/core/instance/index.js 我们把abandon对象的各个部分划分到不同的文件中去了,这是为了方便维护,而index.js文件的作用就是分别引入这些文件,然后挂载好接口,最终,启动对象初始化,创建好实例。 render函数目录:src/core/vnode/create-element.js 未来我们会添加虚拟结点,其次目前其实不存在vnode。 这个文件的作用是把template变成render函数。举例子: <div> <label> 值: </label> <input v-model='value'/></div>转变以后就是: createElement('div',{},[ createElement('label',{},'值:'), createElement('input',{ "v-model":"value" })]);这个render和虚拟结点有关,添加虚拟结点以后应该会对应调整。 后记这篇文章会随着abandon的更新同步更新,目前刚刚起步,略做笔记。

November 2, 2019 · 1 min · jiezi

ZooTeam-前端周刊|第-54-期

政采云前端小报第54期浏览更多往期小报,请访问: https://weekly.zoo.team ES6、ES7、ES8、ES9、ES10新特性一览 掌握不断更新的ES新特性从程序媛角度去看项目管理 | Aotu.io「凹凸实验室」 项目管理一般是从技术负责人、项目产品负责人的角度去看的,程序员虽然码代码很重要,但对项目的领悟能力也同样重要。我们经常会遇到各种困惑:手上的项目需求越来越多,BUG列表只增不减,该采取怎样的措施,保证自己的生产力?希望以下的讲述带给你莫名的认同感,或多或少让你磨刀霍霍一试。 需求管理下图描述的是程序员从接到需求到开发环节的过程: 一般我们首先会收到产品的PRD或交互稿,被询问今天什么时间点是...我不想成为不懂 GUI 的 UI 开发者 - 掘金 作为一个程序员,我是从切图开始职业生涯的。行业内一般把我这种编写用户界面 (UI) 的岗位,叫做前端开发。工作几年后我发现了个奇怪的现象,那就是整个前端圈子里,虽然大家常常谈 UI,但很少有人谈 GUI。 这话要从何说起呢?前端圈子里从上游到下游,强调的都是...技术栈:为什么 Node 是前端团队的核心技术栈 小菜前端的基建在一步步走过来的过程中,NodeJS 是如何使用的及扮演了哪些角色,它对于工程师个人,团队能力,公司研发效率,业务支撑,技术的探索与突破等等到底有什么实际的意义...从“愚昧之巅”到“绝望之谷”,讲讲我价值几千万的认知 不要缝合自己的脑洞,打开,打开,重新打开自己的逻辑闭环。当前端遇到机器学习?听 TensorFlow.js 负责人怎么说 第十四届 D2 前端技术论坛将于12月14日拉开帷幕,其中, Google TensorFlow.js 团队的负责人 Ping Yu 将作为「智能化」专场的嘉宾,为我们讲解 TensorFlow.js 生态系统,以及如何将现有的机器学习模型植入到前端。网站性能优化实战——从12.67s到1.06s的故事 - 腾讯Web前端 IMWeb 团队社区 | blog | 团队博客 Web前端 腾讯IMWeb 团队社区再谈javascriptjs原型与原型链及继承相关问题 - 腾讯Web前端 IMWeb 团队社区 | blog | 团队博客 Web前端 腾讯IMWeb 团队社区React Concurrent 模式抢先预览上篇: Suspense the world - 掘金 ...

November 2, 2019 · 1 min · jiezi

JS-口袋书第-3-章JavaScript-函数

阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/... 函数是什么函数是完成某个特定功能的一组语句。如没有函数,完成任务可能需要五行、十行、甚至更多的代码。这时我们就可以把完成特定功能的代码块放到一个函数里,直接调用这个函数,就省重复输入大量代码的麻烦。 函数可以概括为:一次封装,四处使用。 函数的定义函数的定义方式通常有三种:函数声明方式、函数表达式、 使用Function构造函数 。 函数声明方式 语法: function 函数名(参数1,参数2,...){ //要执行的语句 } 例: // 声明function sum(num1, num2) { return num1 + num2;}// 调用sum(1, 2) // 3函数表达式 语法: var fn = function(参数1,参数2,...){ //要执行的语句 };例: // 声明var sum = function(num1,num2){ return num1+num2; };// 调用sum(1, 2) // 3使用Function构造函数 Function构造函数可以接收任意数量的参数,最后一个参数为函数体,其他的参数则枚举出新函数的参数。其语法为: new Function("参数1","参数2",...,"参数n","函数体"); 例: // 声明var sum = new Function("num1","num2","return num1+num2"); // 调用sum(1, 2) // 3三种定义方式的区别 三种方式的区别,可以从作用域、效率以及加载顺序来区分。 从作用域上来说,函数声明式和函数表达式使用的是局部变量,而 Function()构造函数却是全局变量,如下所示: var name = '我是全局变量 name';// 声明式function a () { var name = '我是函数a中的name'; return name;}console.log(a()); // 打印: "我是函数a中的name"// 表达式var b = function() { var name = '我是函数b中的name'; return name; // 打印: "我是函数b中的name"}console.log(b())// Function构造函数function c() { var name = '我是函数c中的name'; return new Function('return name')}console.log(c()()) // 打印:"我是全局变量 name",因为Function()返回的是全局变量 name,而不是函数体内的局部变量。从执行效率上来说,Function()构造函数的效率要低于其它两种方式,尤其是在循环体中,因为构造函数每执行一次都要重新编译,并且生成新的函数对象。 ...

October 9, 2019 · 4 min · jiezi

工作中常用es6特性

结合工作中使用情况,简单对es6进行一些复习总结,包括常用的语法,api等,以及短时间内要上手需要重点学习的知识点(不同工作环境可能有一些差别),主要参考链接是阮一峰的博客以及外文博客(阮老师大部分文章是直接翻译的这个博客) http://2ality.com/p/about.html 1.简介先说一下ECMAScript,ECMA是一个标准化组织,他们制定了JavaScript的语言标准,所以之后一直称为ECMAScript,广泛的讲,Javascript是其一种标准实现,包括ECMAScript,dom,bom等 ECMA组织每年都会有新标准发布,标准名为ES+年份,所以我们会听到ES2015,ES2016,ES2017等,ES6其实就是ES2015,表示在15年发布的最新版本,相应的ES2016,ES2017分别称为ES7和ES8,依次往后对应。 现在大部分博客,文章,分享中提到的ES6其实也可以理解为ES6+,只不过因为2015年之前,ECMAScript有很多年没有发版(也有历史原因:ES4的夭折),积累了大量的新语法,api,所以在2015年一次性加在了ES6版本中发布,之后每年都只有很少的一些新增,比如: ES7: http://2ality.com/2016/01/ecm... (只有很少的两个属性)ES8:http://2ality.com/2016/02/ecm...…语法提案关于语法提案的流程,简单了解一下:一个新的语法从提案到成为标准需要经过五个阶段,每个阶段都需要标准委员会TC39定时开会进行批准 流程见链接:http://exploringjs.com/es2016... 需要注意的一点,所有的标准都是基于实现的,几大厂商浏览器对提案的实现必须先于标准才会进入定稿阶段,包括Babel 我们常用的async和await,就是因为16年开会的时候没有达到可定案的标准,而没有进入ES2016标准,最后添加在2017标准中 可参考该链接,有每年发布标准中新增的特性:http://2ality.com/2017/02/ecm... 2.简单知识点介绍下面主要就是结合平时工作,简单介绍最常用的语法,类方法以及实例方法等,下面主要是一些列举,大部分知识点想深入学习的话,还是得到阮老师博客或者外文博客上学习 不过我标注了实际工程中的使用频率,可以参考,针对性的学习,快速上手 提示:实际开发中结合eslint可以帮助自己写出更规范的代码使用频率极高(为方便一起介绍,会将一些不常用的语法也列出来,标题括号中也为大量使用): 2.1 let与const这是最基础的两个命令,都是声明变量,要强制所有的声明都使用他们两个 与var的区别: 作用域 var作用域在全局let与const作用域为代码块变量提升 (https://www.jianshu.com/p/68a...)暂时性死区,表示在一个块级作用域内,只要使用let声明一个变量,声明前将不能使用该变量不允许重复声明与顶层对象window或者global的关系,var声明的全局变量与顶层变量挂钩,而let const声明的全局变量不挂钩const与let区别: const定义一个只读的常量,一旦声明不可改变,但需要注意的是,不可改变的是变量指向的那个内存地址,如果使用const声明一个对象,对象内部是可以改变的,如果要强制一个对象不可改变,那么可以使用Object.freeze来冻结(该方法只冻结该对象,不会冻结其属性,所以可考虑递归)2.2 默认值设置我们可以直接在通过 param = 1 的形式设置默认值包括为函数参数设置,为解构设置(见下面介绍)避免了以前的这种写法: function test(data) { data = data || {}; ...}// 可以直接写为function test(data = {}) { ...}需要注意的是:默认值生效的条件是,严格等于 undefined,如果值为null,不会使用默认值2.3 解构赋值与rest操作符解构解构赋值其实就是为了更方便的从数组或者对象中通过属性名取数据,熟练使用之后,配合默认值,rest操作符可以很大程度提高效率,简化代码 下面是一些简单的使用对比 var a = 1, b = 2, c = 3;// 或者var param = { a: 1, b: 2, c: 3 };var a = param.a || 1; // 默认值var b = param.b;var c = param.c;// 或者function add(param) { param = param || {}; var v1 = param.v1 || 0; var v2 = param.v2 || 0; return v1 + v2;}可以看出来,如果参数比较多的话,代码很臃肿如果用解构赋值,我们可以写成这样,很简洁 ...

July 13, 2019 · 2 min · jiezi

『ES6知识点总结』遍历器iterator

『ES6知识点总结』遍历器iterator本文内容如下: 1 具有iterator接口的数据结构2 遍历器过程3 遍历器作用:4 模拟next()方法5 使用while循环6 TypeScript的写法7 Iterator接口与Generator函数8 对象的遍历器接口8.1 对于类似数组的对象9 调用Iterator接口的场合9.1 解构赋值9.2 扩展运算符9.3 yield*9.4 其他场合10 字符串的Iterator接口具有iterator接口的数据结构【01】原生就具有Iterator接口,它们的遍历器接口部署在Symbol.iterator属性上: Array,Object(类数组对象),Map,WeakMap,Set,WeakSet,字符串。 let arr = new Array(); let iterator =arr[Symbol.iterator](); 【02】其他数据结构(主要是对象)的Iterator接口,都需要自己部署在Symbol.iterator属性上面。(原型链上的对象具有该方法也可)。 【03】一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。就称为部署了遍历器接口。就可以遍历所有成员。可通过for of 遍历。 【04】遍历器对象本身也有Symbol.iterator方法,执行后返回自身。 gen是一个Generator函数,调用它会生成一个遍历器对象g。它的Symbol.iterator属性,也是一个遍历器对象生成函数,执行后返回它自己。 function* gen(){ // some code}var g = gen();g[Symbol.iterator]() === g // true遍历器过程【01】zyx456:说白了,等于这些数据结构有一个方法(PS,这个方法称为遍历器函数)。 方法名是[Symbol.iterator],方法中返回一个对象(PS,这个对象称为遍历器对象),该对象有一个next()方法。这个next()会遍历数据结构的成员。返回{value:XX||undefined , done:true||false} let obj = { [Symbo.iterator] (){ return {next(){}} } } 调用遍历器函数,就会返回一个遍历器对象。 每次调用iterator.next(),就使用该数据结构的一个成员,成员的值就是返回对象中value的值。done为false,最后会返回一个有value和done两个属性的对象。 从头到尾依次使用数据结构的成员。直到使用的成员都访问完了。 当数据结构的成员已全部访问了,此时,再调用iterator.next()。返回的对象中,value的值为undefined,done为true。 done属性是一个布尔值,表示遍历是否结束。 let arr = [1,2,3]; ...

July 11, 2019 · 3 min · jiezi

Elasticsearch-学习

Elasticsearch

May 28, 2019 · 1 min · jiezi

怎样阅读-ECMAScript-规范

翻译自:How to Read the ECMAScript SpecificationEcmascript 语言规范 The ECMAScript Language specification(又名:Javascript 规范 the JavaScript specification 或 ECMA-262)是学习 JavaScript 底层工作原理的非常好的资源。 然而,这是一个庞大的专业文本资料,咋一眼看过去,大家可能会感到迷茫、恐惧,满怀激情却无从下手。 前言不管你是打算每天阅读一点 ECMAScript 规范,还是把它当成一个年度或者季度的目标,这篇文章旨在让你更轻松的开始阅读最权威的 JavaScript 语言参考资料。 为什么要阅读 ECMAScript 规范Ecmascript 规范是所有 JavaScript 运行行为的权威来源,无论是在你的浏览器环境,还是在服务器环境( Node.js ),还是在宇航服上[ NodeJS-NASA ] ,或在你的物联网设备上[ JOHNNY-FIVE ]。 所有 JavaScript 引擎的开发者都依赖于这个规范来确保他们各种天花乱坠的新特性能够其他 JavaScript 引擎一样,按预期工作。 Ecmascript 规范 绝不仅仅对 JavaScript 引擎开发者有用,它对普通的 JavaScript 编码人员也非常有用,而你只是没有意识到或者没有用到。 假设有一天你在工作中发现了下面这个奇怪的问题: > Array.prototype.push(42)1> Array.prototype[ 42 ]> Array.isArray(Array.prototype)true> Set.prototype.add(42)TypeError: Method Set.prototype.add called on incompatible receiver #<Set> at Set.add (<anonymous>)> Set.prototypeSet {}并且非常困惑为什么一个方法在它的原型上工作,但是另一个方法在它的原型上却不工作。 不幸的是,这种问题你 Google 不到, Stack Overflow 可能也解决不了你的疑惑。 ...

May 21, 2019 · 9 min · jiezi

JS 数组常用API方法和遍历方法总结

数组 (array)ES5 *map语法:[].map(function(item, index, array) {return xxx})功能:遍历数组,返回回调返回值组成的新数组,不改变原数组,不会对空数组进行检测forEach语法:[].forEach(function(item, index, array) {})功能:无法break,可以用try/catch中throw new Error来停止,不改变原数组filter语法:[].filter(function(item, index, array) {})功能:过滤,返回过滤后的数组,不改变原数组,不会对空数组进行检测eg:const data = [-8, 9, 5, 3];const res = data.filter(function(item) { if (item > 3) { return item }});console.log(res); // [9, 5]some语法:[].some(function(item, index, array) {})功能:有一项返回true,则整体为true,不改变原数组every语法:[].every(function(item, index, array) {})功能:需要全部符合条件才返回true,有一项返回false,则整体为false,不改变原数组join语法:[].join(str)功能:返回通过指定连接符str把数组连接成字符串,不改变原数组push / pop语法:[].push(item) / [].pop(item)功能:数组末尾推入push和弹出pop,返回改变后数组的长度/弹出项,改变原数组unshift / shift语法:[].unshift(item) / [].shift(item)功能:数组头部推入unshift和弹出shift,返回改变后数组的长度/弹出项,改变原数组sort(fn) / reverse语法:[].sort(fn) [].reverse()功能:按规则排序与反转,改变原数组splice语法:[].splice(start, number, value1, value2…)功能:返回删除元素组成的数组,从start处开始删除number个值后插入valueN参数列表到数组中,改变原数组concat语法:[].concat([])功能:连接n(n >= 2)个数组,返回数组连接后的数组副本,浅拷贝,不改变原数组slice语法:[].slice(start, end)功能:返回截断后的新数组,不改变原数组indexOf / lastIndexOf(value, fromIndex)语法:[].indexOf(value[, fromIndex])功能:查找数组项indexOf 从fromIndex(默认为0)开始向后查找valuelastIndexOf 从fromIndex(默认为-1)开始向前查找value返回value对应的下标reduce / reduceRight语法:reduce / reduceRight(callback[, initialValue])功能:两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)callback 函数的参数:之前值(previousValue)、当前值(currentValue)、索引值(currentIndex)以及数组本身(array)initialValue 可选的初始值,作为第一次调用回调函数时传给previousValue的值。也就是,为累加等操作传入起始值(额外的加值)reduceRight是从数组的末尾开始isArray *语法:Array.isArray(value) 功能:用于确定参数value是否是一个ArrayES6find *ind(fn)`功能:返回符合条件的第一个数组元素itemfindIndex *语法:[].findIndex(fn) 功能:返回符合条件的第一个数组元素的索引from *语法:[].fill(value[, start, end]) 功能:将类似数组的对象和可遍历(iterable)的对象转为真正的数组常用:const set = new Set(3, 8, 9, 0)Array.from(set)entries *语法:[].entries()功能:返回迭代器:返回键值对【注】Object.entries(obj)方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)【MDN】而[].entries()是Array.prototype上的方法keys/values 类似//数组const arr = [‘a’, ‘b’, ‘c’];for(let v of arr.entries()) { console.log(v)}// [0, ‘a’] [1, ‘b’] [2, ‘c’]//Setconst arr1 = new Set([‘a’, ‘b’, ‘c’]);for(let v of arr1.entries()) { console.log(v)}// [‘a’, ‘a’] [‘b’, ‘b’] [‘c’, ‘c’]//Mapconst arr2 = new Map();arr2.set(‘a’, ‘a’);arr2.set(‘b’, ‘b’);for(let v of arr2.entries()) { console.log(v)}// [‘a’, ‘a’] [‘b’, ‘b’]keys *语法:[].keys()功能:返回迭代器:返回键key(即上面的每个数组中的第一个值)values语法:[].values()功能:返回迭代器:返回值value(即上面的每个数组中的第二个值)includes *语法:[].includes(val[, fromIndex]) 功能:用于从fromIndex判断数组中是否包含val,可替代ES5中的 indexOfcopyWithin语法:[].copyWithin(target[, start[, end]])功能:浅复制数组的一部分(start~end)到同一数组中的另目标位置target,返回改变后的数组,而不修改其大小;start默认为0, end默认为length-1; 改变原数组of语法:Array.of() 功能:创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型Array构造函数 & Array.of() 区别实例说明Array.of(7); // [7] Array.of(1, 2, 3); // [1, 2, 3]Array(7); // [ , , , , , , ]Array(1, 2, 3); // [1, 2, 3]fill语法:[].fill(value[, start, end]) 功能:用指定的元素填充数组,可用于初始化数组,返回改变后的数组,改变原数组填充值(value),填充起始位置(start,默认为0),填充结束位置(end,默认为数组length)。遍历数组map/forEach/some/every/filter 见上forfor…in遍历所有可枚举属性,常用于遍历对象Objectfor…of遍历所有可迭代iterable的对象对象【属性】for…in循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)【可枚举 - Symbol】Object.keys(obj)返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)【自身可枚举 - Symbol】Object.getOwnPropertyNames(obj)返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)【自身 - Symbol】Object.getOwnPropertySymbols(obj)返回一个数组,包含对象自身的所有Symbol属性【自身的Symbol】Reflect.ownKeys(obj)返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否可枚举 【自身所有】参考 「干货」细说 Array 的常用操作(ES5 和 ES6) ...

April 10, 2019 · 1 min · jiezi

ES2019(ES10)

一、JSON superset将ECMA-262语法扩展为JSON超集动机ECMAScript声称JSON是一个子集JSON.parse,但是(因为已经有详细记录)这是不正确的,因为JSON字符串可以包含未转义的U + 2028 LINE SEPARATOR和U + 2029 PARAGRAPH SEPARATOR字符,而ECMAScript字符串则不能二、Optional catch binding对ECMAScript进行了语法更改,允许catch中不写error捕获动机此提议引入的语法更改允许catch省略绑定其周围的括号原写法try { // 尝试使用可能无法实现的Web功能} catch (unused) { // 支持可能无法实现的web功能情况}以后可以这样写try { // do something} catch { //}三、Symbol.prototype.description新增一个Symbol.prototype.description方法,是一个只读属性,它会返回 Symbol 对象的可选描述的字符串democonsole.log(Symbol(‘desc’).description); // expected output: “desc"console.log(Symbol.iterator.description); // expected output: “Symbol.iterator"console.log(Symbol.for(‘foo’).description); // expected output: “foo"console.log(Symbol(‘foo’).description + ‘bar’); // expected output: “foobar"四、Function.prototype.toString revision新增一个Function.prototype.toString方法,返回一个表示当前函数源代码的字符串1.语法function.toString()2.democonst fun = (name) => { console.log(name) }fun.toString() // “(name) => { console.log(name) }“五、Object.fromEntries ———— 用于将键值对列表转换为对象(兼容性有点差,chrome最新的beta版才支持)。新增Object.fromEntries属性,用于将键值对列表转换为对象1.语法const newObject = Object.fromEntries(iterable);iterable: 类似实现了可迭代协议 Array 或者 Map 或者其它对象的可迭代对象2.democonst newObject = Object.fromEntries([[‘a’, 1], [‘b’, 2]]); // { a: 1, b: 2 }const map = new Map().set(‘a’, 1).set(‘b’, 2);const newObject1 = Object.fromEntries(map); // { a: 1, b: 2 }六、Well-formed JSON.stringify防止JSON.stringify返回格式错误的Unicode字符串的提议七、String.prototype.{trimStart,trimEnd}新增String.prototype.trimStart和String.prototype.trimEnd属性,移除空白字符,并返回一个新字符串String.prototype.trimStart从一个字符串的开端删除空白字段,并返回一个新字符串1.语法str.trimStart();2.democonst str = ’ 我愿是猪 ‘;const newStr = str.trimStart(); // ‘我愿是猪 ‘String.prototype.trimEnd从一个字符串的末端删除空白字段,并返回一个新字符串1.语法str.trimEnd();2.democonst str = ’ 我愿是猪 ‘;const newStr = str.trimEnd(); // ’ 我愿是猪’八、Array.prototype.{flat,flatMap}新增Array.prototype.flat和Array.prototype.flatMap属性,对数组的内含数组进行展开操作并返回一个新数组Array.prototype.flat!参考资料方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回1.语法const newArray = arr.flat(depth)depth: 需要展开内层数组的层数,默认为12.demo展开内层数组/** 默认参数: /const array = [1, [2, [3]]];const array1 = array.flat(); // [1, 2, [3]]/* 递归展平,直到数组不再包含嵌套数组: /const arrayInfinity = array.flat(Infinity); // [1, 2, 3]/* 此处等同于 */const array2 = array.flat(2);移除空项const array = [1, 2, , 3];const arrayRemove = array.flat(); // [1, 2, 3]Array.prototype.flatMap方法类似与Array.prototype.map,但是会展开数组(只会展开一层)1.语法const new_array = arr.flatMap((currentValue, index, array) => { // 返回新数组的元素})currentValue: 数组中正在处理的当前元素index: 正在处理元素的索引array: 正在被处理素组2.democonst array = [1, 2, 3];const new_array = array.flatMap(ele => [ele * 2]) // [2, 4, 6]const new_array2 = array.flatMap(ele => [[ele * 2]]) // [[2], [4], [6]]gitub上修改 ...

April 6, 2019 · 1 min · jiezi

前端培训-初级阶段(13) - ECMAScript (语法、变量、值、类型、运算符、语句)

前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。该文为前端培训-初级阶段(13、18) (介绍了 ECMAScript 历史,ES6 常用点)的补充内容。本文介绍ECMAScript基础知识。我们要讲什么语法变量类型、值运算符语句语法如果是熟悉任意一门高级编程语言的开发者会发现 ECMAScript 的语法很容易掌握,因为差距不是很大,其中也有借鉴的地方。尤其是与 Java 有一些关键的语法特性相同,名字都是蹭热度。区分大小写 var 与 Var 是不同的变量变量是弱类型的 这点和其他语言有很大区别,(前端也有TS)。结尾分号不是必须的 但是比如(()=>console.log(’ln’))(),有时候容易出现异常错误window.a;(v=>console.log(v))(1)window.a(v=>console.log(v))(1)注释单行注释以双斜杠开头(//)多行注释以单斜杠和星号开头(/),以星号和单斜杠结尾(/)括号表示代码块 不会生成块级作用域(老版本)变量命名规则第一个字符必须是字母、下划线(_)或美元符号($),余下的字符可以是下划线、美元符号或任何字母或数字字符声明方式var 声明变量,变量提升let 会生成块级作用域const 生成一个不可以改变的常量类型、值原始类型存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。原型类型有 Undefined、Null、Boolean、Number 和 String 。由于这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域中(栈)。这样存储便于迅速查寻变量的值。可以使用 typeof 来判断是什么类型注释:您也许会问,为什么 typeof 运算符对于 null 值会返回 “Object”。这实际上是 JavaScript 最初实现中的一个错误,然后被 ECMAScript 沿用了。现在,null 被认为是对象的占位符,从而解释了这一矛盾,但从技术上来说,它仍然是原始值。Undefined 当声明的变量未初始化时,或者对象中不存在的值。认为是一个暂未赋值的值。Null 对象占位符,认为是一个空的值。Boolean 布尔类型 true 和 false。Number 可以表示 32 位的整数,还可以表示 64 位的浮点数。对于浮点字面量的有趣之处在于,用它进行计算前,真正存储的是字符串。用 64 位 IEEE 754 形式存储浮点值,这意味着十进制值最多可以有 17 个十进制位。17 位之后的值将被裁去,从而造成一些小的数学误差。String 字符串类型引用类型存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。该类型指 Object ,当然还有 Array,Array 也是对象的一种。运算符运算符优先级例子描述 . [] () 1Math.random();arr[0];(a+1)*b字段访问、数组下标、函数调用以及表达式分组 ++ – + - ~ ! delete new typeof void 2++a;a++;+a;-a;~a;!a;一元运算符 * / % 3++a;a++;+a;-a;~a;!a;二元运算符,算数运算符,乘、除、余 + - 4a+b;a+’’;a-b二元运算符,算数运算符,加减、字符串连接 << >> >>> 52>>1二元运算符,位运算符,位移,无符号位移 < <= > >= instanceof 62>1二元运算符,比较运算符 == != === !== 72==1二元运算符,比较运算符 & 82&1二元运算符,位运算符,按位与 ^ 92^1二元运算符,位运算符,按位异或 1 10211二元运算符,位运算符,按位或 && 112&&1二元运算符,逻辑运算符,短路 11 122111二元运算符,逻辑运算符,短路 ?: 13三元运算符,条件运算符 = oP= 14二元运算符,赋值运算符 , 15``逗号,多重语句语句功能示例描述if逻辑判断if(a % 2 == 0){console.log(‘偶数’)}用来判断条件成立执行代码if(){}else{} if(){}else if(){}else{} switch(){case:break;default:break;}类似于if但是是单值匹配 找到对应状态执行代码for(初值;判断;步长){}循环遍历for(var = 1;i < 10; i++) console.log(i)完成多个相同功能的任务while(判断){}循环遍历 完成多个相同功能的任务do{}while();循环遍历 完成多个相同功能的任务 ...

April 1, 2019 · 1 min · jiezi

前端培训-初级阶段(13、18)

前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。先来说一下为什么这节课跳课了,不是说中间的我们不讲了,而且上节课主讲人讲了 18,没办法我这节课补一下。收集上几周的反馈,普遍觉得内容多的超乎想象,所以之后的培训计划会根据内容适当调整。我们要讲什么上下左右居中的几种实现。ECMAScript核心语法结构上下左右居中的几种实现这个问题比较常见,咱们也简单说说吧。其实分为两种,一种行内结构,一种块结构。行内结构居中行内结构可以理解为文本,文本居中可以通过设置父元素的属性来实现。text-align: center 水平居中line-height: height; 垂直居中。行高和高设置为一样的值。vertical-align: middle; 垂直居中。这个属性是用来设置对齐方式的,通过伪元素构建一个 height:100% 然后设置居中就ok了。块级结构居中块结构的特点,占满整行,所以设置要点是设置自己的属性来实现。margin: auto; 水平居中,自动分配剩余空间,但是正常情况下,只有水平方向有剩余空间。position:fixed;top:0;right:0;bottom:0;left:0; 垂直水平居中,这个方法有个要点,就是定宽定高,不然就占满了。当然还有要 margin:auto 来分配剩余空间才可以。position:absolute;left:50%;margin-left:一半宽度 垂直水平居中,left 是基于父级来设置的,所以需要用 margin 再拉回来,也需要定宽高。position:absolute;left:50%;top:50%;transform: translate(-50%,-50%); 垂直水平居中,这个方案是上一个方案的优化版本,translate是基于自己的宽高来现实,所以可以用 -50% 来拉回。特殊的盒子实现居中这个东西就是说一个特殊模型,所以他自身就支持完成水平垂直居中table-cell vertical-align: middle;text-align:centerflex 就不用多说了吧,不懂的去看看上节课。还不懂就要挨锤了。grid margin: auto;ECMAScript 核心语法结构ECMAScript 是一种由 Ecma国际(前身为欧洲计算机制造商协会,英文名称是 European Computer Manufacturers Association)通过 ECMA-262 标准化的脚本程序设计语言。可以理解为是JavaScript的一个标准,但实际上 JS 是 ECMA-262 标准的实现和扩展。版本时间简述ECMAScript 11997年06月首版ECMAScript 21998年06月格式修正,以使得其形式与ISO/IEC16262国际标准一致ECMAScript 31999年12月强大的正则表达式,更好的文字链处理,新的控制指令,异常处理,错误定义更加明确,数输出的格式化及其它改变ECMAScript 4未完成更明确的类的定义,命名空间等等。2004年6月欧洲计算机制造商协会发表了ECMA-357标准,它是ECMAScript的一个扩延,它也被称为E4X(ECMAScript for XML)ECMAScript 52009年12月首版ECMAScript 2015 (ES6/ES2015)2015年6月17日截止发布日期,JavaScript的官方名称是ECMAScript 2015,Ecma国际意在更频繁地发布包含小规模增量更新的新版本,下一版本将于2016年发布,命名为ECMAScript 2016。从现在开始,新版本将按照ECMAScript+年份的形式发布。ECMAScript 2016 (ES7/ES2016)2016年 ECMAScript 2017 (ES8/ES2017)2017年 ECMAScript 2018 (ES9/ES2018)2018年 ECMAScript 20192019年 这一课我真的觉得 ruanyifeng大佬的就很棒 ,这里我先大体介绍一下,之后有时间会开单张来介绍一些常规用法。如:Array数组对象的forEach、map、filter、reduce –之前写的一篇,这样的章节。下面的介绍不全,只是其中的一部分let/var/const 的区别关键字绑定到顶层对象(特殊情况)变量提升块级作用域(if、for)描述varyesyesno会变量提升,可多次赋值,无块级概念(function、try 的块有)letnonoyes只可声明一次,可多次赋值constnonoyes只可以赋值一次字符串扩展repeat(n),重复字符串多少次,padStart(n,s),padEnd(n,s),字符串补全长度的功能,比如前面补 0模板字符串 反引号标识标签模板,其实也是一个偶然机会碰到这个东西的。有个prompt(1) to win,做这个题的时候发现了这种办法。 alert123 // 等同于 alert(123)正则的扩展数值的扩展isNaN() ,NaN是唯一一个自己不等于自己的。函数的扩展默认值 ,fucntion(a = 1){}默认值解构,// 写法一function m1({x = 0, y = 0} = {}) { return [x, y];}// 写法二function m2({x, y} = { x: 0, y: 0 }) { return [x, y];}rest 参数 ,代替 arguments 对象=> 函数()=>console.log(1) 等同于 function(){return console.log(1)}()=>{console.log(1)} 等同于 function(){console.log(1)}this对象绑定为定义时候的对象不可以当作构造函数不可以使用arguments对象数组的扩展扩展运算符,…[1,2,3]分开插入,可以用来替代 apply()Array.from(),将类数组转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。Array.of() 用来修复new Array(3)的异常find() 和 findIndex(),查找元素或者下标fill() 填充一个数组entries(),keys() 和 values() 遍历includes() 判断是否存在,用来替代~indexOfflat(),flatMap() 将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。还可以传入深度对象的扩展ProxyPromise 对象async 函数课后作业(能写几种写几种,越多越好)一行居中,多行居左,怎么实现?(水平居中)一行居中,多行居中,怎么实现?(垂直居中)实现一个重复字符串的函数。往期内容前端培训-初级阶段(1 - 4)前端培训-初级阶段(5 - 8)前端培训-初级阶段(9 - 12)参考资料ECMAScript –百度百科 介绍了一些历史JavaScript 实现 –w3school.com.cn介绍了JS由什么构成,值得一看JavaScript 高级教程 –w3school.com.cn一些语法基础ECMAScript 6 入门 –ruanyifeng如果你想学 ES6,这本书一定不要错过 ...

March 25, 2019 · 1 min · jiezi

尝鲜 ES2019 的新功能

翻译:疯狂的技术宅原文:https://medium.freecodecamp.o…本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章ECMAScript 每年都会发布一个新版本,其中的提案是已经正式通过的,并分发给开发者和用户。本文将讨论该语言的最新版本,以及它又具有了什么新功能。ES10/ES2019 在本次更新中有很大的改进。它引入了一些新的函数和方法,使开发者能够编写更少的代码,并提高工作效率。让我们直接进入正题。flat()flat() 是一种用于展平数组的方法。在某些时候,数组的元素还是数组,这些类型的数组称为嵌套数组。要取消数组的嵌套(展平它们),我们不得不使用递归。现在引入 flat(),可以用一行代码完成。 一个被展平的数组是一个深度为 0 的数组,flat() 接受一个参数,一个代表深度的数字。深度指的是数组内嵌套的数量。下面这个例子可以帮你理解嵌套和深度。一个深度为 3 的嵌套数组上面是一个深度为 3 的数组。它是一个数组在另一个数组的内部,又在另一个数组内部,又在另一个数组内部 ????????????。通常在 JavaScript 中,数组的深度可以为无穷大,或者直到内存不足为止。假设一个数组的嵌套深度为3,并且我们仅将其展平到深度 2,那么主数组中仍然会存在一个嵌套数组。句法返回值它返回一个扁平数组。示例用 flat() 展平一个深度为3的嵌套数组,参数深度为3。如果将参数深度设为2,我们得到:可以看到输出中仍然有一个未展平的数组。flatMap()flatMap() 用于展平嵌套数组并根据给出的像 map() 这样的函数更改值。此函数作用于数组并用一个回调函数作为参数。回调函数用于指示数组应该怎样被展平。它就像 map 一样工作,此外也使它变得扁平。如果你想了解有关 map 的更多信息,请查看关于this的文章。flatMap() 可用于展平深度为1的数组,它在内部调用 map 函数,后跟着参数深度为1的 flat 函数,。句法返回值带有操纵值的扁平数组,由提供给它的回调函数提供。就像一个map一样。map() + flat() => flatmap()示例在此例中,我们逐个显示 map 和 flatMap 以显示两个函数之间的差异。 map() 返回嵌套数组,而flatMap() 的输出除了数组的展平外,还与 map 的结构相同。Object.fromEntries()另一个非常有用的函数 Object.fromEntries 用于根据提供的键值对生成对象。它接受一个键值对列表,并返回一个对象,对象的属性由参数 entries 给出。它的作用与 Object.entries()相反。参数接受任何可迭代的对象,即数组。返回值返回有给定键值对的对象。示例我们可以看到,当向 fromEntries() 函数提供了一个map(将值成对存储)时,会得到一个对象,其对应的键值对和 map 中一样。trimStart()trimStart() 方法删除字符串开头的空格。 trimLeft() 是此方法的别名。句法返回值返回一个字符串,前面的空格被删除。示例可以清楚地看到输出中删除的空格。trimEnd()trimEnd() 方法删除字符串末尾的空格。 trimRight() 是此方法的别名。句法返回值它返回一个字符串,末尾所有的空格被删除。示例我们可以清楚地看到末尾的空格被删除。修改 catch 绑定在 ES10 之前,我们必须通过语法为 catch 子句绑定异常变量,无论是否有必要。很多时候 catch 块是多余的。 ES10 提案使我们能够简单的把变量省略掉。示例在上面的例子中,可以看到没有为 catch 提供变量。符号描述当我们在 JS 中创建一个 Symbol 时,可以指定一个在以后用于调试的描述。得到这个描述的过程有点无聊,必须再次重新构造 Symbol,并在 toString() 方法的帮助下才能访问描述。ES10添加了一个新的名为 description 的只读属性,它返回 Symbol 的描述。示例可以看到使用 Symbol 的.description 属性能够直接获取描述。总结以上是当前 ES2019 标准中将要引入的一些功能。希望你喜欢这篇文章!感谢阅读。本文首发微信公众号:jingchengyideng欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章欢迎继续阅读本专栏其它高赞文章:12个令人惊叹的CSS实验项目世界顶级公司的前端面试都问些什么CSS Flexbox 可视化手册过节很无聊?还是用 JavaScript 写一个脑力小游戏吧!从设计者的角度看 ReactCSS粘性定位是怎样工作的一步步教你用HTML5 SVG实现动画效果程序员30岁前月薪达不到30K,该何去何从7个开放式的前端面试题React 教程:快速上手指南 ...

March 13, 2019 · 1 min · jiezi

Webpack5.0 新特性尝鲜实战

作者:志佳老师本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章在老袁写这篇文章的时候,v5版本仍然处于早期阶段,可能仍然有问题。而且作为一个major版本,其中有一些breaking changes,可能会导致一些配置和插件不工作。但这并无妨碍我们去开始对changelog上的新特性进行尝鲜实战。大家如果遇到什么问题可以移步到这进行反馈。另外有关于Webpack4的配置和Compiler->Compilation->Chunk->Module->Template整体运行原理国内外有很多优秀的文章我这里就不一一展开了。接下来天也不早了人也不少了,让我们一起干点正事。(本图截自twitter列出了接下来v5版本的改进,嗯…感觉屏幕还是小了一点)(本图截自github,截图时间为3月12日。我们看到目前开发进度到了57%)一顿操作猛如虎指南升级你的Node到8(V5将Node.js版本从6升级到了8)npm install webpack@next —save-devnpm install webpack-cli —save-devpackage.json添加 “dev”: “webpack –mode development"package.json 添加 “prod”: “webpack –mode production"开始Webpack V5尝鲜之旅新建src文件夹,然后新建index.js。简单的写了一句 console.log(“Hello Webpack5”)1. dist打包文件测评#激动的心 颤抖的手npm run dev我的内心毫无波澜……卒????…好了,到这里结束了。散了吧~3个小时以后…我依旧心不死 发现了这个issues解决。让我们一起看看运行成功之后V5和V4的对比图<u>V5打包到dist的main.js</u><u>V4打包到dist的main.js</u><u>V5打包过程</u><u>V4打包过程</u>没有文化的我只能说一句,哎呀我去!!体积小了一半之多,而且那个startup函数简直骚气的一批????2. 让人揪心的按需加载以前当我们想在index.js内部 import(./async.js”).then(…)的时候,如果我们什么也不加。V4会默认对这些文件生成一堆0.js,1.js,2.js…是多么的整齐.所以我们需要使用import(/* webpackChunkName: “name” */ “module”) 才能化解这份尴尬。今天V5可以在开发模式中启用了一个新命名的块 id 算法,该算法提供块(以及文件名)可读的引用。 模块 ID 由其相对于上下文的路径确定。 块 ID 是由块的内容决定的,所以你不再需要使用Magic Comments。//src文件夹index.jsimport(”./async.js").then(()=>{ console.log(.data);})console.log(“Hello Webpack5”)//src文件夹async.jsconst data = “异步数据????";export default data; 再次编译之后src_async_js.js 就躺在了dist里????。如果这个时候去执行 npm run prod 会在dist里出现一个已数字开头的js文件。比如我的是61.js,你可能非常好奇,这是什么鬼❓3. moduleIds & chunkIds得已确定首先我们改造一下上面的文件。//src文件夹index.jsimport(”./async.js").then(() => { console.log(.data);})import("./async2.js").then(() => { console.log(.data2);})console.log(“Hello Webpack5”)//src文件夹async2.jsimport common from “./common.js"console.log(common)const data2 = “异步数据????";export default data2;在V4的版本中async.js、async2.js会被一次分配给一个chunkId。然后生成的main.js根据chunkId加载对应的文件,但是悲剧的事如果此时我删掉 import(”./async.js”).then(() => {console.log(.data);}) 这一行的话会导致async2进行上位也就是原来的1变成了0。如下图:利用BeyondCompare我们也清晰的看到了main的变化。有同学说这还不好办,我又可以用Magic Comments、也可以用一些插件就可以固定住他的 moduleIds & chunkIds。是的你说的没错,但是V5将不需要引入任何的外力,如上我们遇到prod陌生的带数字的JS,就是为了增强long-term caching,增加了新的算法,并在生产模式下使用以下配置开启。这些算法以确定性的方式为模块和数据块分配非常短(3或4个字符)的数字 id。//Webpack4生产环境的默认配置module.exports = { optimization:{ chunkIds: “deterministic”, moduleIds: “deterministic” }}//Webpack4生产环境的默认配置module.exports = { optimization:{ chunkIds: “natural”, moduleIds: “size” }}如果你觉得这些新特性让你不爽,你依旧可以设置 optimization: { chunkIds: ’named’ } 它是兼容的,这一点还是值得点赞的。4. 饱受诟病的编译速度Webpack的编译速度相信是很多同学比较头痛的问题,当然我们也有很多优化的办法。比如HappyPack、Cache-loader、排除node_modules、多线程压缩甚至可以采用分布式编译等等。其实Webpack编译慢还跟他的laoder机制不无关系,比如string->ast->string这一点跟Parcel确实有些差距 ????。那在V5的版本中都带来些哪些改变呢?其实你只要在配置文件中加上这样一句:module.exports = { cache: { type: “filesystem” }}其实cache在V4版本中就有cache,不过如上这个配置官网上也在说是一个实验性的,也说如果当使用持久缓存时,不再需要cache-loader。 对于 babel cacheDirectory 等也是如此。老袁太忙也没有时间详细的翻所有的pr和源码,不过大致运行了下貌似有的效果????如果哪位大神这里有空翻过了源码也欢迎在评论区讨论????(开启缓存之后的编译速度)5. minSize&maxSize 更好的方式表达在V4版本中默认情况下,仅能处理javascript的大小????module.exports = { optimization: { splitChunks: { cacheGroups: { commons: { chunks: “all”, name: “commons”, minChunks: 1, minSize: “数值”, maxSize: “数值” } } } }}V5版本的变更,这个变更简直是太皮了???? 老袁已经试过了,效果还是蛮不错的。module.exports = { optimization: { splitChunks: { cacheGroups: { commons: { chunks: “all”, name: “commons”, } }, //最小的文件大小 超过之后将不予打包 minSize: { javascript: 0, style: 0, }, //最大的文件 超过之后继续拆分 maxSize: { javascript: 1, //故意写小的效果更明显 style: 3000, } } }}7.编译器的优化如果大家读过Webpack的源码一定知道Compiler的重要性,在Webpack中充斥着大量的钩子和触发事件。在新的版本中,编译器在使用完毕后应该被关闭,因为它们在进入或退出空闲状态时,拥有这些状态的 hook。 插件可以用这些 hook 来执行不太重要的工作(比如:持久性缓存把缓存慢慢地存储到磁盘上)。同时插件的作者应该预见到某些用户可能会忘记关闭编译器,所以 当编译器关闭所有剩下的工作时应尽快完成。 然后回调将会通知已彻底完成。 当你升级到 v5 时,请确保在完成工作后使用 Node.js API 调用 Compiler.close。8. Node.js polyfills 自动被移除过去,Webpack 4版本附带了大多数 Node.js 核心模块的 polyfills,一旦前端使用了任何核心模块,这些模块就会自动应用,但是其实有些是不必要的。 V5中的尝试是自动停止 polyfilling 这些核心模块,并侧重于前端兼容的模块。当迁移到 v5时,最好尽可能使用前端兼容的模块,并尽可能手动添加核心模块的polyfills。 Webpack鼓励大家多提交自己的意见,因为这个更改可能会也可能不会进入最终的 v5版本。现在微前端已经在很多国内的团队大量应用,老袁个人觉得这个改动对于前端更专注开发模块更有益处。在本文开头的时候,我们列出了一张作者演讲的图有关于Webpack的改动。大家可以点击这里看到全部。新的版本变动必将引起很多插件会出问题,但是V5的性能改进是我们更加期待的。最后我想说天下武功出少林,天下技术出基础。大家夯实基础多悟原理才能跟的上变化如此快的前端娱乐圈。作者 志佳老师 2019 年 03月 12日欢迎继续阅读本专栏其它高赞文章:12个令人惊叹的CSS实验项目世界顶级公司的前端面试都问些什么CSS Flexbox 可视化手册过节很无聊?还是用 JavaScript 写一个脑力小游戏吧!从设计者的角度看 ReactCSS粘性定位是怎样工作的一步步教你用HTML5 SVG实现动画效果程序员30岁前月薪达不到30K,该何去何从7个开放式的前端面试题React 教程:快速上手指南本文首发微信公众号:jingchengyideng欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章 ...

March 13, 2019 · 2 min · jiezi

promise

前言今天来分享下promise的用法,es6伟大发明之一,当初我学习的时候也是蛮头大的,不知道为啥,整个脑子就是,我在哪,我要干啥的懵圈,后面认真学习之后,觉得真是十分好用,下面就来一起学习下吧。为什么会有promise首先为什么会有promise的存在,其实很多人都知道的,其中最大的问题就是在处理多个有依赖关系的异步操作时,会出现回调地狱( callback hell ),如下:$.ajax({ url: ’….’, success: function (data) { $.ajax({ url: ’….’, success: function (data) { } }); } });promise提供了一个优雅的方式,来解决这个问题,同时提供了很多的错误捕获机制。如何使用promise我们先不讲promise的理论语法,这样会一开始就降低学习的欲望,直接来看使用案例,然后去理解。首先看基本使用new Promise(function (resolve, reject) { // 假设此处是异步请求某个数据 $.ajax({ url: ’……’, success: function (res) { if (res.code === 200) { resolve(res.data); } else { reject(‘获取data失败’); } } })}).then(function A(data) { // 成功,下一步 console.log( data); }, function B(error) { // 失败,做相应处理 console.log(error) });console:sucesserror解析:梳理流程:首先我们在promise函数里,执行我们的异步操作得到data如果成功的话,通过resolve函数数据传递出来,如果失败。通过reject把错误信息传递出来然后在.then里可以接受传递出来的数据,.then()里面接受两个函数,第一个函数接收resolve传递出来的值,也就是正确情况下的处理,第二个函数接收reject传递的信息,也就是错误的情况下的处理。Promise是一个对象,它的内部其实有三种状态。初始状态( pending )。已完成( fulfilled ): Promise 的异步操作已结束成功。已拒绝( rejected ): Promise 的异步操作未成功结束。resolve 方法可以使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操作。reject 方法则是将 Promise 对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操作。then(onFulfilled, onRejected)—(onFulfilled, onRejected)链式then当然,我们既然解决回调地狱,一个异步,看不出来啥优势,现在看多个异步请求, 为了代码简约,我们用setTimeout来代替ajax请求 作为异步操作,如下:new Promise((resolve, reject) => { setTimeout( () => { if (…){ resolve([1, 2, 3]) } else { reject(’error’); } }, 2000);}) .then( data => { console.log(value); // 打印出[1, 2, 3] return new Promise( (resolve, reject)=> { // 新的异步请求,需要promise对象 let data2 = 1 + data; setTimeout( () => { if (…) { resolve(data2); } else { reject(’error2’) } }, 2000); }); }, error => { cosnole.log(error) }).then( data2 => { console.log(data2 ); }, error => { cosnole.log(error) });解析:-这个例子中,第一个异步操作得到数据[1, 2, 3],传递到第一个then中,我们在第一个then中运用拿到的数据,进行第二次异步操作,并把结果传递出去。在第二个then中拿到数据,并且捕获error。可以看到本来嵌套的两个异步操作,现在清晰多了,而且链式接无数个then在这里有两个地方需要注意then里面的可捕获错误的函数,可以捕获到上面的所有then的错误,所以只在最后一个then里,写错误捕获函数就可以。每次异步操作时候需要返回一个新的promise,因为只有用promise对象才会等异步操作执行完,才去执行下面的then,才能拿到异步执行后的数据,所以第二个then里的异步请求,也需要声明Promise对象。如果then里面返回常量,可以直接返回。如下:new Promise((resolve, reject) => { setTimeout( () => { if (…){ resolve([1, 2, 3]) } else { reject(’error’); } }, 2000);}) .then( value => { return ‘222’; // 如果是直接返回常量,可直接return }) .then( value2 => { console.log(value2 ); // 打印出222 })下面忽略error情况,看两个例子,大家可以自己思考下打印结果new Promise(resolve => { setTimeout( () => { resolve(‘value1’); }, 2000);}) .then( value1 => { console.log(value1); (function () { return new Promise(resolve => { setTimeout(() => { console.log(‘Mr.Laurence’); resolve(‘Merry Xmas’); }, 2000); }); }()); return false; }) .then( value => { console.log(value + ’ world’); });value1false worldMr.Laurencenew Promise( resolve => { console.log(‘Step 1’); setTimeout(() => { resolve(100); }, 1000);}).then( value => { return new Promise(resolve => { console.log(‘Step 1-1’); setTimeout(() => { resolve(110); }, 1000); }) .then( value => { console.log(‘Step 1-2’); return value; }) .then( value => { console.log(‘Step 1-3’); return value; });}).then(value => { console.log(value); console.log(‘Step 2’);});console:Step 1Step 1-1Step 1-2Step 1-3110Step 2catchcatch 方法是 then(onFulfilled, onRejected) 方法当中 onRejected 函数的一个简单的写法,也就是说可以写成 then(fn).catch(fn),相当于 then(fn).then(null, fn)。使用 catch 的写法比一般的写法更加清晰明确。我们在捕获错误的时候,直接在最后写catch函数即可。 let promise = new Promise(function(resolve, reject) { throw new Error(“Explosion!”);});promise.catch(function(error) { console.log(error.message); // “Explosion!”});上面代码等于与下面的代码 let promise = new Promise(function(resolve, reject) { throw new Error(“Explosion!”);});promise.catch(function(error) { console.log(error.message); // “Explosion!”});异步代码错误抛出要用rejectnew Promise( resolve => { setTimeout( () => { throw new Error(‘bye’); }, 2000);}).then( value => { }).catch( error => { console.log( ‘catch’, error); });控制台会直接报错 Uncaught Error: bye解析:因为异步情况下,catch已经执行完了,错误才抛出,所以无法捕获,所以要用reject,如下:new Promise( (resolve, reject) => { setTimeout( () => { reject(‘bye’); }, 2000);}).then( value => { console.log( value + ’ world’); }).catch( error => { console.log( ‘catch’, error); });catch bye利用reject可以抓捕到promise里throw的错catch 可以捕获then里丢出来的错,且按顺序只抓捕第一个没有被捕获的错误new Promise( resolve => { setTimeout( () => { resolve(); }, 2000);}).then( value => { throw new Error(‘bye’); }).then( value => { throw new Error(‘bye2’); }).catch( error => { console.log( ‘catch’, error); });console: Error: byenew Promise( resolve => { setTimeout( () => { resolve(); }, 2000);}).then( value => { throw new Error(‘bye’); }).catch( error => { console.log( ‘catch’, error); }).then( value => { throw new Error(‘bye2’); }).catch( error => { console.log( ‘catch’, error); });console: Error: byeconsole: Error: bye2catch 抓捕到的是第一个没有被捕获的错误错误被捕获后,下面代码可以继续执行new Promise(resolve => { setTimeout(() => { resolve(); }, 1000);}) .then( () => { throw new Error(’test1 error’); }) .catch( err => { console.log(‘I catch:’, err); // 此处捕获了 ’test1 error’,当错误被捕获后,下面代码可以继续执行 }) .then( () => { console.log(’ here’); }) .then( () => { console.log(‘and here’); throw new Error(’test2 error’); }) .catch( err => { console.log(‘No, I catch:’, err); // 此处捕获了 ’test2 error’ });I catch: Error: test2 errorhereand here I catch: Error: test2 error错误在捕获之前的代码不会执行new Promise(resolve => { setTimeout(() => { resolve(); }, 1000);}) .then( () => { throw new Error(’test1 error’); }) .catch( err => { console.log(‘I catch:’, err); // 此处捕获了 ’test1 error’,不影响下面的代码执行 throw new Error(‘another error’); // 在catch里面丢出错误,会直接跳到下一个能被捕获的地方。 }) .then( () => { console.log(‘and here’); throw new Error(’test2 error’); }) .catch( err => { console.log(‘No, I catch:’, err); // 此处捕获了 ’test2 error’ });I catch: Error: test2 errorI catch: Error: another errornew Promise(resolve => { setTimeout(() => { resolve(); }, 1000);}) .then( () => { console.log(‘start’); throw new Error(’test1 error’); }) .then( () => { console.log(‘arrive here’); }) .then( () => { console.log(’… and here’); throw new Error(’test2 error’); }) .catch( err => { console.log(‘No, I catch:’, err); // 捕获到了第一个 });No, I catch: Error: test1 error at Promise.then (<anonymous>:8:1Promise.allPromise.all([1, 2, 3]) .then( all => { console.log(‘1:’, all); })[1, 2, 3]Promise.all([function () {console.log(‘ooxx’);}, ‘xxoo’, false]) .then( all => { console.log( all); }); [ƒ, “xxoo”, false]let p1 = new Promise( resolve => { setTimeout(() => { resolve(‘I'm P1’); }, 1500);});let p2 = new Promise( (resolve, reject) => { setTimeout(() => { resolve(‘I'm P2’); }, 1000); });let p3 = new Promise( (resolve, reject) => { setTimeout(() => { resolve(‘I'm P3’); }, 3000); }); Promise.all([p1, p2, p3]).then( all => { console.log(‘all’, all);}).catch( err => { console.log(‘Catch:’, err);});all (3) [“I’m P1”, “I’m P2”, “I’m P3”]案例:删除所有数据后,做一些事情、、、、db.allDocs({include_docs: true}).then(function (result) { return Promise.all(result.rows.map(function (row) { return db.remove(row.doc); }));}).then(function (arrayOfResults) { // All docs have really been removed() now!});Promise.resolvePromise.resolve() .then( () => { console.log(‘Step 1’); })其他Promise.resolve(‘foo’).then(Promise.resolve(‘bar’)).then(function (result) { console.log(result);});VM95:2 foo如果你向 then() 传递的并非是一个函数(比如 promise)它实际上会将其解释为 then(null),这就会导致前一个 promise 的结果会穿透下面How do I gain access to resultA here?function getExample() { return promiseA(…).then(function(resultA) { // Some processing return promiseB(…); }).then(function(resultB) { // More processing return // How do I gain access to resultA here? });}解决 Break the chainfunction getExample() { var a = promiseA(…); var b = a.then(function(resultA) { // some processing return promiseB(…); }); return Promise.all([a, b]).then(function([resultA, resultB]) { // more processing return // something using both resultA and resultB });}

February 27, 2019 · 5 min · jiezi

ES10 特性的完整指南

ES10 还只是一个草案。但是除了 Object.fromEntries 之外,Chrome 的大多数功能都已经实现了,为什么不早点开始探索呢?当所有浏览器都开始支持它时,你将走在前面,这只是时间问题。在新的语言特性方面,ES10 不如 ES6 重要,但它确实添加了一些有趣的特性(其中一些功能目前还无法在浏览器中工作: 2019/02/21)在 ES6 中,箭头函数无疑是最受欢迎的新特性,在 ES10 中会是什么呢?BigInt -任意精度整数BigInt 是第七种 原始类型。BigInt 是一个任意精度的整数。这意味着变量现在可以 表示²³ 数字,而不仅仅是9007199254740992。const b = 1n; // 追加 n 以创建 BigInt在过去,不支持大于 9007199254740992 的整数值。如果超过,该值将锁定为 MAX_SAFE_INTEGER + 1:const limit = Number.MAX_SAFE_INTEGER;⇨ 9007199254740991limit + 1;⇨ 9007199254740992limit + 2;⇨ 9007199254740992 <— MAX_SAFE_INTEGER + 1 exceededconst larger = 9007199254740991n;⇨ 9007199254740991nconst integer = BigInt(9007199254740991); // initialize with number⇨ 9007199254740991nconst same = BigInt(“9007199254740991”); // initialize with “string”⇨ 9007199254740991ntypeoftypeof 10;⇨ ’number’typeof 10n;⇨ ‘bigint’等于运算符可用于两种类型之间比较:10n === BigInt(10);⇨ true10n == 10;⇨ true数学运算符只能在自己的类型中工作:200n / 10n⇨ 20n200n / 20⇨ Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions <-运算符可以操作, + 不可用-100n⇨ -100n+100n⇨ Uncaught TypeError: Cannot convert a BigInt value to a number当你读到这篇文章的时候,matchAll 可能已经在 Chrome C73 中正式实现了——如果不是,它仍然值得一看。特别是如果你是一个正则表达式(regex)爱好者。string.prototype.matchAll()如果您运行谷歌搜索JavaScript string match all,第一个结果将是这样的:如何编写正则表达式“match all”?最佳结果将建议 String.match 与正则表达式和 /g 一起使用或者带有 /g 的 RegExp.exec 或者带有 /g 的 RegExp.test 。首先,让我们看看旧规范是如何工作的。带字符串参数的 String.match 仅返回第一个匹配:let string = ‘Hello’;let matches = string.match(’l’);console.log(matches[0]); // “l"结果是单个 “l”(注意:匹配存储在 matches[0] 中而不是 matches)在“hello”中搜索 “l” 只返回 “l”。将 string.match 与 regex 参数一起使用也是如此:让我们使用正则表达式 /l/ 找到字符 串“hello” 中的 “l” 字符:let string = “Hello”;let matches = string.match(/l/);console.log(matches[0]); // “l"添加 /g 混合let string = “Hello”;let ret = string.match(/l/g); // (2) [“l”, “l”];很好,我们使用 < ES10 方式得到了多个匹配,它一直起作用。那么为什么要使用全新的 matchAll 方法呢? 在我们更详细地回答这个问题之前,让我们先来看看 捕获组。如果不出意外,你可能会学到一些关于正则表达式的新知识。正则表达式捕获组在 regex 中捕获组只是从 () 括号中提取一个模式,可以使用 /regex/.exec(string) 和string.match 捕捉组。常规捕获组是通过将模式包装在 (pattern) 中创建的,但是要在结果对象上创建 groups 属性,它是: (?<name>pattern)。要创建一个新的组名,只需在括号内附加 ?<name>,结果中,分组 (pattern) 匹配将成为 group.name,并附加到 match 对象,以下是一个实例:字符串标本匹配:这里创建了 match.groups.color 和 match.groups.bird :const string = ‘blackraven limeparrot whiteseagull’;const regex = /(?<color>.?)*(?<bird>[a-z0-9]+)/g;while (match = regex.exec(string)){ let value = match[0]; let index = match.index; let input = match.input; console.log(${value} at ${index} with '${input}');console.log(match.groups.color); console.log(match.groups.bird);}需要多次调用 regex.exec 方法来遍历整个搜索结果集。 在每次迭代期间调用.exec 时,将显示下一个结果(它不会立即返回所有匹配项。),因此使用 while 循环。输出如下:blackraven at 0 with ‘blackraven limeparrot whiteseagull’blackravenlimeparrot at 11 with ‘blackraven limeparrot whiteseagull’limeparrotwhiteseagull at 23 with ‘blackraven limeparrot whiteseagull’whiteseagull但奇怪的是:如果你从这个正则表达式中删除 /g,你将永远在第一个结果上创建一个无限循环。这在过去是一个巨大的痛苦。想象一下,从某个数据库接收正则表达式时,你不确定它的末尾是否有 /g,你得先检查一下。使用 .matchAll() 的好理由在与捕获组一起使用时,它可以更加优雅,捕获组只是使用 () 提取模式的正则表达式的一部分。它返回一个迭代器而不是一个数组,迭代器本身是有用的。迭代器可以使用扩展运算符 (…) 转换为数组。它避免了带有 /g 标志的正则表达式,当从数据库或外部源检索未知正则表达式并与陈旧的RegEx 对象一起使用时,它非常有用。使用 RegEx 对象创建的正则表达式不能使用点 (.) 操作符链接。高级: RegEx 对象更改跟踪最后匹配位置的内部 .lastindex 属性,这在复杂的情况下会造成严重破坏。.matchAll() 是如何工作的?让我们尝试匹配单词 hello 中字母 e 和 l 的所有实例, 因为返回了迭代器,所以可以使用 for…of 循环遍历它:// Match all occurrences of the letters: “e” or “l” let iterator = “hello”.matchAll(/[el]/);for (const match of iterator) console.log(match);这一次你可以跳过 /g, .matchall 方法不需要它,结果如下:[ ’e’, index: 1, input: ‘hello’ ] // Iteration 1[ ’l’, index: 2, input: ‘hello’ ] // Iteration 2[ ’l’, index: 3, input: ‘hello’ ] // Iteration 3使用 .matchAll() 捕获组示例:.matchAll 具有上面列出的所有好处。它是一个迭代器,可以用 for…of 循环遍历它,这就是整个语法的不同。const string = ‘blackraven limeparrot whiteseagull’;const regex = /(?<color>.?)*(?<bird>[a-z0-9]+)/;for (const match of string.matchAll(regex)) { let value = match[0]; let index = match.index; let input = match.input; console.log(${value} at ${index} with '${input}');console.log(match.groups.color); console.log(match.groups.bird);}请注意已经没有 /g 标志,因为 .matchAll() 已经包含了它,打印如下:blackraven at 0 with ‘blackraven limeparrot whiteseagull’blackravenlimeparrot at 11 with ‘blackraven limeparrot whiteseagull’limeparrotwhiteseagull at 23 with ‘blackraven limeparrot whiteseagull’whiteseagull也许在美学上它与原始正则表达式非常相似,执行while循环实现。但是如前所述,由于上面提到的许多原因,这是更好的方法,移除 /g 不会导致无限循环。动态导入现在可以将导入分配给变量:element.addEventListener(‘click’, async() => { const module = await import(./api-scripts/button-click.js); module.clickEvent();})Array.flat()扁平化多维数组:let multi = [1,2,3,[4,5,6,[7,8,9,[10,11,12]]]];multi.flat(); // [1,2,3,4,5,6,Array(4)]multi.flat().flat(); // [1,2,3,4,5,6,7,8,9,Array(3)]multi.flat().flat().flat(); // [1,2,3,4,5,6,7,8,9,10,11,12]multi.flat(Infinity); // [1,2,3,4,5,6,7,8,9,10,11,12]Array.flatMap()let array = [1, 2, 3, 4, 5];array.map(x => [x, x * 2]);let array = [1, 2, 3, 4, 5];array.map(x => [x, x * 2]);结果:[Array(2), Array(2), Array(2), Array(2), Array(2)]0: (2) [1, 2]1: (2) [2, 4]2: (2) [3, 6]3: (2) [4, 8]4: (2) [5, 10]使用 flatMap 方法:array.flatMap(v => [v, v * 2]);[1, 2, 2, 4, 3, 6, 4, 8, 5, 10]Object.fromEntries()将键值对列表转换为对象:let obj = { apple : 10, orange : 20, banana : 30 };let entries = Object.entries(obj);entries;(3) [Array(2), Array(2), Array(2)] 0: (2) [“apple”, 10] 1: (2) [“orange”, 20] 2: (2) [“banana”, 30]let fromEntries = Object.fromEntries(entries);{ apple: 10, orange: 20, banana: 30 }String.trimStart() 与 String.trimEnd()let greeting = " Space around “;greeting.trimEnd(); // " Space around”;greeting.trimStart(); // “Space around “;格式良好的 JSON.stringify()此更新修复了字符 U+D800 到 U+DFFF 的处理,有时可以进入 JSON 字符串。 这可能是一个问题,因为 JSON.stringify 可能会将这些数字格式化为没有等效 UTF-8 字符的值, 但 JSON 格式需要 UTF-8 编码。解析方法使用格式良好的JSON字符串,如:’{ “prop1” : 1, “prop2” : 2 }’; // A well-formed JSON format string注意,要创建正确 JSON 格式的字符串,绝对需要在属性名周围加上双引号。缺少或任何其他类型的引号都不会生成格式良好的JSON。’{ “prop1” : 1, “meth” : () => {}}’; // Not JSON format stringJSON 字符串格式与 Object Literal 不同,后者看起来几乎一样,但可以使用任何类型的引号括住属性名,也可以包含方法(JSON格式不允许使用方法):let object_literal = { property: 1, meth: () => {} };不管怎样,一切似乎都很好。第一个示例看起来是兼容的。但它们也是简单的例子,大多数情况下都能顺利地工作!U+2028 和 U+2029 字符问题是, ES10 之前的 EcmaScript 实际上并不完全支持 JSON 格式。前 ES10 时代不接受未转义行分隔符 U+2028 和段落分隔符 U+2029 字符:对于 U+D800 - U+DFFF 之间的所有字符也是如此如果这些字符潜入 JSON 格式的字符串(假设来自数据库记录),你可能会花费数小时试图弄清楚为什么程序的其余部分会产生解析错误。因此,如果你传递 eval 这样的字符串 “console.log(’ hello ‘)”,它将执行 JavaScript语句 (通过尝试将字符串转换为实际代码),也类似于 JSON.parse 将处理你的 JSON 字符串的方式。稳定的 Array.prototype.sort()V8 之前的实现对包含10个以上项的数组使用了一种不稳定的快速排序算法。一个稳定的排序算法是当两个键值相等的对象在排序后的输出中出现的顺序与在未排序的输入中出现的顺序相同时。但情况不再是这样了,ES10 提供了一个稳定的数组排序:var fruit = [ { name: “Apple”, count: 13, }, { name: “Pear”, count: 12, }, { name: “Banana”, count: 12, }, { name: “Strawberry”, count: 11, }, { name: “Cherry”, count: 11, }, { name: “Blackberry”, count: 10, }, { name: “Pineapple”, count: 10, }];// 创建排序函数:let my_sort = (a, b) => a.count - b.count;// 执行稳定的ES10排序:let sorted = fruit.sort(my_sort);console.log(sorted);控制台输出(项目以相反的顺序出现):新的F unction.toString()函数是对象,并且每个对象都有一个 .toString() 方法,因为它最初存在于Object.prototype.toString() 上。 所有对象(包括函数)都是通过基于原型的类继承从它继承的。这意味着我们以前已经有 funcion.toString() 方法了。但是 ES10 进一步尝试标准化所有对象和内置函数的字符串表示。 以下是各种新案例:典型的例子:function () { console.log(‘Hello there.’); }.toString();控制台输出(函数体的字符串格式:)⇨ function () { console.log(‘Hello there.’); }下面是剩下的例子:直接在方法名 .toString()Number.parseInt.toString();⇨ function parseInt() { [native code] }绑定上下文:function () { }.bind(0).toString();⇨ function () { [native code] }内置可调用函数对象:Symbol.toString();⇨ function Symbol() { [native code] }动态生成的函数:function* () { }.toString();⇨ function* () { }prototype.toStringFunction.prototype.toString.call({});⇨ Function.prototype.toString requires that ’this’ be a Function"可选的 Catch Binding在过去,try/catch 语句中的 catch 语句需要一个变量。 try/catch 语句帮助捕获终端级别的错误:try { // Call a non-existing function undefined_Function undefined_Function(“I’m trying”);}catch(error) { // Display the error if statements inside try above fail console.log( error ); // undefined_Function is undefined}在某些情况下,所需的错误变量是未使用的:try { JSON.parse(text); // <— this will fail with “text not defined” return true; <— exit without error even if there is one}catch (redundant_sometmes) <— this makes error variable redundant{ return false;}编写此代码的人通过尝试强制 true 退出 try 子句。但是,这并不是实际发生的情况(() => { try { JSON.parse(text) return true } catch(err) { return false }})()=> false在 ES10 中,捕获错误的变量是可选的现在可以跳过错误变量:try { JSON.parse(text); return true;}catch{ return false;}目前还无法测试上一个示例中的 try 语句的结果,但一旦它出来,我将更新这部分。标准化 globalThis 对象这在ES10之前, globalThis 还没有标准化。在产品代码中,你可以自己编写这个怪物,在多个平台上“标准化”它:var getGlobal = function () { if (typeof self !== ‘undefined’) { return self; } if (typeof window !== ‘undefined’) { return window; } if (typeof global !== ‘undefined’) { return global; } throw new Error(‘unable to locate global object’);};但即使这样也不总是奏效。因此,ES10 添加了 globalThis 对象,从现在开始,该对象用于在任何平台上访问全局作用域:// 访问全局数组构造函数globalThis.Array(0, 1, 2);⇨ [0, 1, 2]// 类似于 ES5 之前的 window.v = { flag: true }globalThis.v = { flag: true };console.log(globalThis.v);⇨ { flag: true }Symbol.descriptiondescription 是一个只读属性,它返回 Symbol 对象的可选描述。let mySymbol = ‘My Symbol’;let symObj = Symbol(mySymbol);symObj; // Symbol(My Symbol)symObj.description; // “My Symbol"Hashbang 语法也就是 unix 用户熟悉的 shebang。它指定一个解释器(什么将执行JavaScript文件?)。ES10标准化,我不会对此进行详细介绍,因为从技术上讲,这并不是一个真正的语言特性,但它基本上统一了 JavaScript 在服务器端的执行方式。$ ./index.js代替$ node index.jsES10类:private、static 和 公共成员新的语法字符 #octothorpe(hash tag)现在用于直接在类主体的范围内定义变量,函数,getter 和 setter ……以及构造函数和类方法。下面是一个毫无意义的例子,它只关注新语法:class Raven extends Bird {#state = { eggs: 10};// getter get #eggs() { return state.eggs; }// setter set #eggs(value) { this.#state.eggs = value; }#lay() { this.#eggs++; }constructor() { super(); this.#lay.bind(this); }#render() { /* paint UI */ }}老实说,我认为这会让语言更难读。原文:https://medium.freecodecamp.o…你的点赞是我持续分享好东西的动力,欢迎点赞!一个笨笨的码农,我的世界只能终身学习!更多内容请关注公众号《大迁世界》! ...

February 26, 2019 · 5 min · jiezi

正则表达式在 ES2018 中的新写法

翻译:疯狂的技术宅原文:https://www.smashingmagazine….本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章摘要:如果你曾用 JavaScript 做过复杂的文本处理和操作,那么你将会对 ES2018 中引入的新功能爱不释手。 在本文中,我们将详细介绍第 9 版标准如何提高 JavaScript 的文本处理能力。有一个很好的理由能够解释为什么大多数编程语言都支持正则表达式:它们是用于处理文本的极其强大的工具。 通常一行正则表达式代码就能完成需要几十行代码才能搞定的文本处理任务。 虽然大多数语言中的内置函数足以对字符串进行一般的搜索和替换操作,但更加复杂的操作(例如验证文本输入)通常需要使用正则表达式。自从 1999 年推出 ECMAScript 标准第 3 版以来,正则表达式已成为 JavaScript 语言的一部分。ECMAScript 2018(简称ES2018)是该标准的第 9 版,通过引入四个新功能进一步提高了JavaScript的文本处理能力:后行断言命名捕获组s (dotAll) flagUnicode属性转义下面详细介绍这些新功能。后行断言能够根据之后或之前的内容匹配一系列字符,使你可以丢弃可能不需要的匹配。 当你需要处理大字符串并且意外匹配的可能性很高时,这个功能非常有用。 幸运的是,大多数正则表达式都为此提供了 lookbehind 和 lookahead 断言。在 ES2018 之前,JavaScript 中只提供了先行断言。 lookahead 允许你在一个断言模式后紧跟另一个模式。先行断言有两种版本:正向和负向。 正向先行断言的语法是 (?=…)。 例如,正则表达式 /Item(?= 10)/ 仅在后面跟随有一个空格和数字 10 的时候才与 Item 匹配:const re = /Item(?= 10)/;console.log(re.exec(‘Item’));// → nullconsole.log(re.exec(‘Item5’));// → nullconsole.log(re.exec(‘Item 5’));// → nullconsole.log(re.exec(‘Item 10’));// → [“Item”, index: 0, input: “Item 10”, groups: undefined]此代码使用 exec() 方法在字符串中搜索匹配项。 如果找到匹配项, exec() 将返回一个数组,其中第一个元素是匹配的字符串。 数组的 index 属性保存匹配字符串的索引, input 属性保存搜索执行的整个字符串。 最后,如果在正则表达式中使用了命名捕获组,则将它们放在 groups 属性中。 在代码中, groups 的值为 undefined ,因为没有被命名的捕获组。负向先行的构造是 (?!…) 。 负向先行断言的模式后面没有特定的模式。 例如, /Red(?!head)/ 仅在其后不跟随 head 时匹配 Red :const re = /Red(?!head)/;console.log(re.exec(‘Redhead’));// → nullconsole.log(re.exec(‘Redberry’));// → [“Red”, index: 0, input: “Redberry”, groups: undefined]console.log(re.exec(‘Redjay’));// → [“Red”, index: 0, input: “Redjay”, groups: undefined]console.log(re.exec(‘Red’));// → [“Red”, index: 0, input: “Red”, groups: undefined]ES2018 为 JavaScript 补充了后行断言。 用 (?<=…) 表示,后行断言允许你在一个模式前面存在另一个模式时进行匹配。假设你需要以欧元检索产品的价格但是不捕获欧元符号。 通过后行断言,会使这项任务变得更加简单:const re = /(?<=)\d+(.\d*)?/;console.log(re.exec(‘199’));// → nullconsole.log(re.exec(’$199’));// → nullconsole.log(re.exec(‘199’));// → [“199”, undefined, index: 1, input: “199”, groups: undefined]注意:先行(Lookahead)和后行(lookbehind)断言通常被称为“环视”(lookarounds)。后行断言的反向版本由 (?<!…) 表示,使你能够匹配不在lookbehind中指定的模式之前的模式。 例如,正则表达式 /(?<!\d{3}) meters/ 会在 三个数字不在它之前 匹配单词“meters”如果:const re = /(?<!\d{3}) meters/;console.log(re.exec(‘10 meters’));// → [" meters", index: 2, input: “10 meters”, groups: undefined]console.log(re.exec(‘100 meters’)); // → null与前行断言一样,你可以连续使用多个后行断言(负向或正向)来创建更复杂的模式。下面是一个例子:const re = /(?<=\d{2})(?<!35) meters/;console.log(re.exec(‘35 meters’));// → nullconsole.log(re.exec(‘meters’));// → nullconsole.log(re.exec(‘4 meters’));// → nullconsole.log(re.exec(‘14 meters’));// → [“meters”, index: 2, input: “14 meters”, groups: undefined]此正则表达式仅匹配包含“meters”的字符串,如果它前面紧跟 35 之外的任何两个数字。正向后行确保模式前面有两个数字,同时负向后行能够确保该数字不是 35。命名捕获组你可以通过将字符封装在括号中的方式对正则表达式的一部分进行分组。 这可以允许你将规则限制为模式的一部分或在整个组中应用量词。 此外你可以通过括号来提取匹配值并进行进一步处理。下列代码给出了如何在字符串中查找带有 .jpg 并提取文件名的示例:const re = /(\w+).jpg/;const str = ‘File name: cat.jpg’;const match = re.exec(str);const fileName = match[1];// The second element in the resulting array holds the portion of the string that parentheses matchedconsole.log(match);// → [“cat.jpg”, “cat”, index: 11, input: “File name: cat.jpg”, groups: undefined]console.log(fileName);// → cat在更复杂的模式中,使用数字引用组只会使本身就已经很神秘的正则表达式的语法更加混乱。 例如,假设你要匹配日期。 由于在某些国家和地区会交换日期和月份的位置,因此会弄不清楚究竟哪个组指的是月份,哪个组指的是日期:const re = /(\d{4})-(\d{2})-(\d{2})/;const match = re.exec(‘2020-03-04’);console.log(match[0]); // → 2020-03-04console.log(match[1]); // → 2020console.log(match[2]); // → 03console.log(match[3]); // → 04ES2018针对此问题的解决方案名为捕获组,它使用更具表现力的 (?<name>…) 形式的语法:const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;const match = re.exec(‘2020-03-04’);console.log(match.groups); // → {year: “2020”, month: “03”, day: “04”}console.log(match.groups.year); // → 2020console.log(match.groups.month); // → 03console.log(match.groups.day); // → 04因为生成的对象可能会包含与命名组同名的属性,所以所有命名组都在名为 groups 的单独对象下定义。许多新的和传统的编程语言中都存在类似的结构。 例如Python对命名组使用 (?P<name>) 语法。 Perl支持与 JavaScript 相同语法的命名组( JavaScript 已经模仿了 Perl 的正则表达式语法)。 Java也使用与Perl相同的语法。除了能够通过 groups 对象访问命名组之外,你还可以用编号引用访问组—— 类似于常规捕获组:const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;const match = re.exec(‘2020-03-04’);console.log(match[0]); // → 2020-03-04console.log(match[1]); // → 2020console.log(match[2]); // → 03console.log(match[3]); // → 04新语法也适用于解构赋值:const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;const [match, year, month, day] = re.exec(‘2020-03-04’);console.log(match); // → 2020-03-04console.log(year); // → 2020console.log(month); // → 03console.log(day); // → 04即使正则表达式中不存在命名组,也始终创建 groups 对象:const re = /\d+/;const match = re.exec(‘123’);console.log(‘groups’ in match); // → true如果可选的命名组不参与匹配,则 groups 对象仍将具有命名组的属性,但该属性的值为 undefined:const re = /\d+(?<ordinal>st|nd|rd|th)?/;let match = re.exec(‘2nd’);console.log(‘ordinal’ in match.groups); // → trueconsole.log(match.groups.ordinal); // → ndmatch = re.exec(‘2’);console.log(‘ordinal’ in match.groups); // → trueconsole.log(match.groups.ordinal); // → undefined你可以稍后在模式中引用常规捕获的组,并使用 \1 的形式进行反向引用。 例如以下代码使用在行中匹配两个字母的捕获组,然后在模式中调用它:console.log(/(\w\w)\1/.test(‘abab’)); // → true// if the last two letters are not the same // as the first two, the match will failconsole.log(/(\w\w)\1/.test(‘abcd’)); // → false要在模式中稍后调用命名捕获组,可以使用 /\k<name>/ 语法。 下面是一个例子:const re = /\b(?<dup>\w+)\s+\k<dup>\b/;const match = re.exec(“I’m not lazy, I’m on on energy saving mode”); console.log(match.index); // → 18console.log(match[0]); // → on on此正则表达式在句子中查找连续的重复单词。 如果你愿意,还可以用带编号的后引用来调用命名的捕获组:const re = /\b(?<dup>\w+)\s+\1\b/;const match = re.exec(“I’m not lazy, I’m on on energy saving mode”); console.log(match.index); // → 18console.log(match[0]); // → on on 也可以同时使用带编号的后引用和命名后向引用:const re = /(?<digit>\d):\1:\k<digit>/;const match = re.exec(‘5:5:5’); console.log(match[0]); // → 5:5:5与编号的捕获组类似,可以将命名的捕获组插入到 replace() 方法的替换值中。 为此,你需要用到 $<name> 构造。 例如:const str = ‘War & Peace’;console.log(str.replace(/(War) & (Peace)/, ‘$2 & $1’)); // → Peace & Warconsole.log(str.replace(/(?<War>War) & (?<Peace>Peace)/, ‘$<Peace> & $<War>’)); // → Peace & War如果要使用函数执行替换,则可以引用命名组,方法与引用编号组的方式相同。 第一个捕获组的值将作为函数的第二个参数提供,第二个捕获组的值将作为第三个参数提供:const str = ‘War & Peace’;const result = str.replace(/(?<War>War) & (?<Peace>Peace)/, function(match, group1, group2, offset, string) { return group2 + ’ & ’ + group1;});console.log(result); // → Peace & Wars (dotAll) Flag默认情况下,正则表达式模式中的点 (.) 元字符匹配除换行符 (\n) 和回车符 (\r)之外的所有字符:console.log(/./.test(’\n’)); // → falseconsole.log(/./.test(’\r’)); // → false尽管有这个缺点,JavaScript 开发者仍然可以通过使用两个相反的速记字符类来匹配所有字符,例如[ w W],它告诉正则表达式引擎匹配一个字符(\w)或非单词字符(\W):console.log(/[\w\W]/.test(’\n’)); // → trueconsole.log(/[\w\W]/.test(’\r’)); // → trueES2018旨在通过引入 s (dotAll) 标志来解决这个问题。 设置此标志后,它会更改点 (.)元字符的行为以匹配换行符:console.log(/./s.test(’\n’)); // → trueconsole.log(/./s.test(’\r’)); // → trues 标志可以在每个正则表达式的基础上使用,因此不会破坏依赖于点元字符的旧行为的现有模式。 除了 JavaScript 之外, s 标志还可用于许多其他语言,如 Perl 和 PHP。Unicode 属性转义ES2015中引入的新功能包括Unicode感知。 但是即使设置了 u 标志,速记字符类仍然无法匹配Unicode字符。请考虑以下案例:const str = ‘????’;console.log(/\d/.test(str)); // → falseconsole.log(/\d/u.test(str)); // → false????被认为是一个数字,但 \d 只能匹配ASCII [0-9],因此 test() 方法返回 false。 因为改变速记字符类的行为会破坏现有的正则表达式模式,所以决定引入一种新类型的转义序列。在ES2018中,当设置 u 标志时,Unicode属性转义(由 \p{…} 表示)在正则表达式中可用。 现在要匹配任何Unicode 数字,你只需使用 \p{Number},如下所示:const str = ‘????’;console.log(/\p{Number}/u.test(str)); // → true要匹配 Unicode 字符,你可以使用\p{Alphabetic}:const str = ‘漢’;console.log(/\p{Alphabetic}/u.test(str)); // → true// the \w shorthand cannot match 漢console.log(/\w/u.test(str)); // → false\P{…} 是 \p{…} 的否定版本,并匹配 \p{…} 没有的所有字符:console.log(/\P{Number}/u.test(’????’)); // → falseconsole.log(/\P{Number}/u.test(‘漢’)); // → trueconsole.log(/\P{Alphabetic}/u.test(’????’)); // → trueconsole.log(/\P{Alphabetic}/u.test(‘漢’)); // → false当前规范提案中提供了受支持属性的完整列表。请注意,使用不受支持的属性会导致 SyntaxError:console.log(/\p{undefined}/u.test(‘漢’)); // → SyntaxError兼容性列表桌面浏览器 ChromeFirefoxSafariEdge后行断言62XXX命名捕获组64X11.1Xs (dotAll) Flag62X11.1XUnicode 属性转义64X11.1X移动浏览器 Chrome For AndroidFirefox For AndroidiOS SafariEdge MobileSamsung InternetAndroid Webview后行断言62XXX8.262命名捕获组64X11.3XX64s (dotAll) Flag62X11.3X8.262Unicode 属性转义64X11.3XX64NODE.JS8.3.0 (需要 –harmony 运行时标志)8.10.0 (支持 s (dotAll) flag 和后行断言)10.0.0 (完全支持)总结通过使正则表达式得到增强,ES2018 继续了以前版本ECMAScript的工作。新功能包括后行断言,命名捕获组, s (dotAll) flag 和 Unicode属性转义。 后行断言允许你在一个模式前面存在另一个模式进行匹配。与常规捕获组相比,命名捕获组使用了更具表现力的语法。 s (dotAll) flag 通过更改点(.)元字符的行为来匹配换行符。最后,Unicode 属性转义在正则表达式中提供了一种新类型的转义序列。在构建复杂的模式时,使用正则表达式测试程序通常很有帮助。一个好的测试器会提供一个接口来对字符串的正则表达式进行测试,并显示引擎所做的每一步,这在你理解其他人编写的表达式时非常有帮助。它还可以检测正则表达式中可能出现的语法错误。 Regex101 和 RegexBuddy 是两个值得一试的正则表达式测试程序。除此之外你能推荐其他的工具吗?欢迎在评论中分享!本文首发微信公众号:jingchengyideng欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章 ...

February 19, 2019 · 4 min · jiezi

ECMASCript 2019可能会有哪些特性?

译者按: 又过了1年…原文:What’s New in JavaScript for 2019译者: Fundebug为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。最近这些年,ECMASCript标准发展节奏非常稳定,每年都会发布新的特性。那么,ECMASCript 2019可能会有哪些特性呢?ECMASCript语法提案的批准流程JavaScript的标准即为ECMAScript,其标准委员会是TC39。所有语法提案都需要经历标准的批准流程,该流程包括5个阶段:Stage 0 - Strawman(展示阶段)Stage 1 - Proposal(征求意见阶段)Stage 2 - Draft(草案阶段)Stage 3 - Candidate(候选阶段)Stage 4 - Finished(定案阶段)只有语法特性到达Stage 4,该特性才能成为正式的ECMAScript标准。但是,JS引擎例如V8(Chrome和Node.js)以及SpiderMonkey(Firefox)会试验性地支持Stage 4之前的语法特性,这样开发者可以进行测试和反馈。当我写这篇博客的时候,还没有新的Stage 4的语法提案,处于Stage 3的语法提案有好几个。ES2019可能不会包括所有Stage 3的语法提案。事实上,有些提案已经被搁置很多年了。Class相关变化有好几个提案是针对Class的,包括:属性定义私有方法及属性静态方法及属性代码示例如下:class Truck extends Automobile { model = “Heavy Duty”; // 公有属性 #numberOfSeats = 5; // 私有属性 #isCrewCab = true; static #name = “Truck”; // 静态私有属性 // 静态方法 static formattedName() { return This vehicle is a ${ Truck.#name }.; } constructor( model, seats = 2 ) { super(); this.seats = seats; } // 私有方法 #getBodyType() { return this.#isCrewCab ? “Crew Cab” : “Standard Cab”; } bodyType() { return ${ this.#numberOfSeats }-passenger ${ this.model } ${ this.#getBodyType() }; } get seats() { return this.#numberOfSeats; } set seats( value ) { if ( value >= 1 && value < 7 ) { this.#numberOfSeats = value; this.#isCrewCab = value > 3; } }}个人认为,使用#来定义私有成员不是很好,学习其他语言,使用private来定义显然更好。String的trimStart()与trimEnd()方法String有一个trim()方法可以移除字符串开头和结尾的空格,而trimStart()与trimEnd()方法则可以分别移除开头和结尾的空格:const one = " hello and let “;const two = “us begin. “;console.log( one.trimStart() + two.trimEnd() ) // 打印"hello and let us begin.“有趣的是,不少浏览器已经支持了这2个方法。可见,浏览器们一直在推动ECMASCript标准的进步。使用BigInt定义大整数Number所能定义的最大整数为2^53 ,对于更大数,则可以使用BigInt来定义:// 最大的Numberconst theBiggestIntegerToday = Number.MAX_SAFE_INTEGER; // 9007199254740991// 在整数后面添加n来定义BigIntconst ABiggerInteger = 9100000000000001n;// 使用BigInt()const EvenBigger = BigInt( 9100000000000002 ); // 9100000000000002n// 使用BigInt()const SuchBigWow = BigInt( “9100000000000003” ); // 9100000000000003n关于BigInt的更多使用示例,可以查看BigInt: arbitrary-precision integers in JavaScriptArray的flat()与flatMap()方法如果你学习过函数式编程,那么你应该知道flat()和flatMap()。flat()可以将一个包含嵌套数组的数组变换为一维数组。const nestedArraysOhMy = [ “a”, [“b”, “c”], [“d”, [“e”, “f”]]];// flat()的参数为数组的嵌套深度const ahhThatsBetter = nestedArraysOhMy.flat( 2 );console.log( ahhThatsBetter ); // [ “a”, “b”, “c”, “d”, “e”, “f” ]flatMap()与map()类似,当回调函数返回数组时,flatMap()返回的是一维数组,而map()返回的是嵌套数组:const scattered = [ “my favorite”, “hamburger”, “is a”, “chicken sandwich” ];const huh = scattered.map( chunk => chunk.split( " " ) );console.log( huh ); // [ [ “my”, “favorite” ], [ “hamburger” ], [ “is”, “a” ], [ “chicken”, “sandwich” ] ]const better = scattered.flatMap( chunk => chunk.split( " " ) );console.log( better ); // [ “my”, “favorite”, “hamburger”, “is”, “a”, “chicken”, “sandwich” ]其他ES2019候选特性这些是当前的Stage 3候选特性:globalThis动态import()遗留的RegExp特性 featuresimport.metaString的matchAll()方法Object.fromEntries()规范JSON.stringify标准化命令行程序的HashbangES2019什么时候发布?过去几年,TC39通常在6月份发布ECMAScript标准。因此,ES2019很可能也会在今年6月份发布。如何试用ES2019特性?其实有些特性其实JS引擎已经支持了,我们只需要配置一下就好了。使用Node.js 11Node.js使用V8引擎,而V8引擎已经支持了一些最新的特性,例如Array.prototype.flat和String.prototype.trimEnd,因此使用最新版的Node.js,即Node.js 11即可试用这些特性。我使用的Node.js版本为11.8.0:node -vv11.8.0如果要启用某个特性,可以使用node命令的–harmony-{feature-flag}选项。使用–v8-options,则可以查看node命令的所有选项,一些实验性的特性被标记为"in progress”。macOS / Linuxnode –v8-options | grep “in progress” –harmony-do-expressions (enable “harmony do-expressions” (in progress)) –harmony-class-fields (enable “harmony fields in class literals” (in progress)) –harmony-static-fields (enable “harmony static fields in class literals” (in progress)) –harmony-await-optimization (enable “harmony await taking 1 tick” (in progress)) –harmony-locale (enable “Intl.Locale” (in progress)) –harmony-intl-list-format (enable “Intl.ListFormat” (in progress)) –harmony-intl-relative-time-format (enable “Intl.RelativeTimeFormat” (in progress))Windowsnode –v8-options | find “in progress"例如,当我们的Node.js代码index.js中的Class有静态方法,则在执行的时候添加–harmony-static-fields选项即可:node –harmony-class-fields –harmony-static-fields index.js使用Babel 7.0 +使用Babel,我们就可以使用最新的JavaScript语法了,因为它会对代码进行转换以兼容旧的浏览器。Babel支持通过一些插件来支持实验性的JS特性。Babel所支持的ECMAScript特性提案可以查看babel/proposals仓库。参考Learn JavaScript in 2019!The History (and Future) of Asynchronous JavaScriptBuild a Secure Node.js Application with JavaScript Async Await Using HapiUse TypeScript to Build a Node API with ExpressStandard ECMA-262关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了9亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!版权声明转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2019/01/30/what-is-new-in-javascript-for-2019/ ...

January 30, 2019 · 2 min · jiezi

每天一本电子书 - Eloquent Javascript, 3rd Edition

Eloquent Javascript, 3rd Edition作者: Marijn Haverbeke出版社: No Starch Press副标题: A Modern Introduction to Programming出版年: 2018-10-30页数: 472定价: GBP 30.04装帧: PaperbackISBN: 9781593279509内容简介 · · · · · ·经过全面修订和更新,这本畅销的JavaScript编程入门专注于编写实际应用程序。Eloquent JavaScript深入研究JavaScript语言,向程序员展示如何编写优雅,有效的JavaScript代码。 像任何好的编程书一样,Eloquent JavaScript从基础 - 变量,控制结构,函数和数据结构 - 开始,然后转向复杂的主题,如面向对象的编程和正则表达式。 第三版介绍了2017版JavaScript的新功能,例如类符号,箭头函数,迭代器,异步函数,模板字符串和黑色范围。 作者Marijn Haverbeke保留了友好的语气和易于理解的解释,使原作成为热门,他为读者添加了新的练习来测试他们的技能。 雄辩的JavaScript将让读者能够立刻熟练掌握网络语言。作者简介 · · · · · ·Marijn Haverbeke是一名编程语言爱好者和多语言。 他从事过广泛的软件系统工作,从数据库到编译器再到编辑器。 他围绕他的开源项目经营一家小企业。更多信息文档资源搜索Maning参考12 Books Every JavaScript Developer Should Read

January 26, 2019 · 1 min · jiezi

小程序全局变量的实现方式

小程序的一个很少人知道的全局对象引用global对象:前端开发人员对这个global对象应该不会很陌生,Node环境的时候全局对象就是这个,浏览器的全局对象是window。这个对象有什么用呢?小程序开发的时候可能经常会引用一些接口的调用、工具类的模块使用,每次调用都需要require或者import下真的好麻烦,而且很难维护,我们肯定会想能不能在一个统一的地方维护呢,global对象就可以实现。如下小程序的app.js代码:const api = require(’./utils/api.js’);const ajax= require(’./utils/tooAjax.js’);const storage= require(’./utils/storage.js’);const util = require(’./utils/util.js’);//第一种global.navH = 64;//自定义导航栏高度global.api = api;//apiglobal.ajax = ajax;//接口global.storage = storage;//本地存储global.util =util;//工具//第二种wx.api = api;//apiwx.ajax = ajax;//接口wx.storage = storage;//本地存储wx.util = util;//工具在其他页面就可以调用了哦,比如: //接口调用1 global.ajax.wearShowList().then((res) => { }); //接口调用2 wx.ajax.wearShowList().then((res) => { });

January 10, 2019 · 1 min · jiezi

[译] 浏览器中的 ECMAScript 模块

原文链接:ECMAScript modules in browsers作者:Jake Archibald浏览器现在可以使用 ES 模块(module)了!它们是:Safari 10.1Chrome 61Firefox 60Microsoft Edge 16<script type=“module”> import {addTextToBody} from ‘./utils.mjs’; addTextToBody(‘Modules are pretty cool.’);</script>// utils.mjsexport function addTextToBody(text) { const div = document.createElement(‘div’); div.textContent = text; document.body.appendChild(div);}在线演示您只需要在 script 元素上添加 type=module,浏览器就会将内联脚本或外部脚本作为 ECMAScript module 处理。关于模块(module)已经有一些很棒的文章,但是我想分享一些在我测试和阅读规范的时候学到的浏览器特有的内容。目前还不支持的某些 import 用法// 已支持:import {foo} from ‘https://jakearchibald.com/utils/bar.mjs';import {foo} from ‘/utils/bar.mjs’;import {foo} from ‘./bar.mjs’;import {foo} from ‘../bar.mjs’;// 不支持:import {foo} from ‘bar.mjs’;import {foo} from ‘utils/bar.mjs’;有效的模块路径说明符必须符合下列条件之一:一个完整的非相对URL,同样地,通过 new URL(moduleSpecifier) 得到的URL也不会报错。以 / 开头的。以 ./ 开头的。以 ../ 开头的。其他形式的说明符保留供将来使用,例如导入内置模块。使用 nomodule 来向后兼容<script type=“module” src=“module.mjs”></script><script nomodule src=“fallback.js”></script>在线演示理解 type=module 的浏览器会忽略属性为 nomodule 的脚本。这意味着您可以给支持模块的浏览器提供模块树,同时给其他浏览器提供一个回退版本。浏览器问题Firefox 浏览器不支持 nomodule (issue)。已在 Firefox nightly 中修复!Edge 浏览器不支持 nomodule (issue)。已在 Edge 16 中修复!Safari 浏览器不支持 nomodule。已在 Safari 11 中修复!对于 10.1,这里有一个非常聪明的替代办法。默认情况下推迟<!– 这个脚本的执行会晚于… –><script type=“module” src=“1.mjs”></script><!– …这个脚本… –><script src=“2.js”></script><!– …但是会在这个脚本之前执行。 –><script defer src=“3.js”></script>在线演示执行的顺序是:2.js,1.mjs,3.js。script 在获取期间会阻塞 HTML 解析器的方式是非常糟糕的。对于常规脚本,您可以使用 defer 来避免阻塞,当然这也会推迟脚本的执行,直到文档完成解析,并与其他延迟脚本一起维护执行顺序。模块脚本的默认表现行为就像 defer ——当它正在获取时,没有办法让一个模块脚本阻塞 HTML 解析器。模块脚本使用和添加了 defer 的常规脚本相同的执行队列。内联脚本也是延时的<!– 这个脚本的执行会晚于… –><script type=“module”> addTextToBody(“Inline module executed”);</script><!– …这个脚本… –><script src=“1.js”></script><!– …和这个脚本… –><script defer> addTextToBody(“Inline script executed”);</script><!– …但是会在这个脚本之前执行。 –><script defer src=“2.js”></script>在线演示执行顺序是1.js ,内联脚本,内联脚本,2.js 。常规的内联脚本会忽略 defer ,然而内联模块脚本却总是被延迟,无论它们有没有导入任何东西。异步适用于外部和内联模块<!– 一旦获取了导入,就会执行此操作 –><script async type=“module”> import {addTextToBody} from ‘./utils.mjs’; addTextToBody(‘Inline module executed.’);</script><!– 一旦获取了脚本和它的导入,就会执行此操作 –><script async type=“module” src=“1.mjs”></script>在线演示快速下载的脚本会在慢速下载的脚本之前执行。与常规脚本一样,async 会让脚本在下载过程中不会阻塞 HTML 解析器,并且尽快地执行。与常规脚本不同,async 也适用于内联模块。与往常的 async 一样,脚本不会按照它们出现在 DOM 中的顺序执行。浏览器问题Firefox 浏览器不支持内联模块脚本上的 async (issue)。已在 Firefox 59 中修复!模块仅执行一次<!– 1.mjs 仅执行一次 –><script type=“module” src=“1.mjs”></script><script type=“module” src=“1.mjs”></script><script type=“module”> import “./1.mjs”;</script><!– 然而,普通的脚本却执行多次 –><script src=“2.js”></script><script src=“2.js”></script>在线演示如果您理解 ES 模块,您就会知道您虽然可以引入它们很多次,但是它们却仅仅会执行一次。当然,这同样适用于HTML中的脚本模块 - 特定URL的模块脚本每页只执行一次。浏览器问题Edge 执行多次模块 (issue)。已修复,但是还没发布(希望 Edge 17 会带上这个修复内容)。总是 CORS<!– 该脚本不会执行, 因为它不能通过 CORS 检查 –><script type=“module” src=“https://….now.sh/no-cors”></script><!– 该脚本不会执行, 因为它引入的脚本之一不能通过 CORS 检查 –><script type=“module”> import ‘https://….now.sh/no-cors’; addTextToBody(“This will not execute.”);</script><!– 该脚本会执行,因为它通过了 CORS 检查 –><script type=“module” src=“https://….now.sh/cors”></script>在线演示与常规脚本不同,模块脚本(和它引入的内容)是通过 CORS 获取的。这就意味着跨域的模块脚本必须返回有效的 CORS header ,比如 Access-Control-Allow-Origin: *。浏览器问题Firefox 加载 Demo 页面失败 (issue)Edge 加载没有 CORS header 的模块脚本 (issue)。 已在 Edge 16 中修复!没有凭据<!– 使用凭据获取(cookie 等) –><script src=“1.js”></script><!– 不使用凭据获取 –><script type=“module” src=“1.mjs”></script><!– 使用凭据获取 –><script type=“module” crossorigin src=“1.mjs?"></script><!– 不适用凭据获取 –><script type=“module” crossorigin src=“https://other-origin/1.mjs”></script><!– 使用凭据获取 –><script type=“module” crossorigin=“use-credentials” src=“https://other-origin/1.mjs?"></script>在线演示如果请求来自相同的源,大多数基于 CORS 的 API 会发送凭据(cookie 等),但是 fetch() 和模块脚本却是例外的——非您要求它们,否则它们不会发送凭据除。您可以通过添加 crossorigin 属性来向同源模块添加凭据(这对我来说似乎有点奇怪,我在规范中对此提出质疑)。如果您打算向其他的源也发送凭据,使用 crossorigin=“use-credentials”。注意其他源必须使用 Access-Control-Allow-Credentials:true 的 header 来响应。此外,还有一个与“模块只执行一次”规则相关的问题。模块由其URL标记,因此如果您请求没有凭据的模块,然后使用凭据请求它,您将获得相同的无凭证模块。 这就是为啥我在上面的URL中使用 问号 ? 的原因,使它们成为唯一的。更新: 上面的情况可能很快就会发生改变。fetch() 和模块脚本默认都会向同源的 URL 发送凭据。Issue浏览器问题Chrome 使用凭据请求同源模块(issue)。已在 Chrome 61 中修复!Safari 即使添加了 crossorigin 属性,也不使用凭据请求同源模块(issue)。Edge 即使添加了 crossorigin 属性,也不使用凭据请求同源模块(issue)。已在 Edge 16 中修复!Edge 使用凭据请求同源模块(issue)。MIME 类型不同于常规脚本,模块脚本必须是有效的 JavaScript MIME 类型中的一种类型,否则模块就不会执行。HTML 标准建议使用 text/javascript。浏览器问题Edge 使用无效的 MIME 类型执行脚本(issue)这就是我目前学到的内容啦。毋庸置疑,我对 ES 模块登陆浏览器感到非常兴奋!性能建议,动态导入等等!请查阅有关 Web Fundamentals 的文章,深入了解模块使用情况。 ...

January 7, 2019 · 2 min · jiezi

es6的set和map学习

SetES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。因为 Set 中的值总是唯一的,所以需要判断两个值是否相等。在ECMAScript规范的早期版本中,这不是基于和===操作符中使用的算法相同的算法。具体来说,对于 Set s, +0 (+0 严格相等于-0)和-0是不同的值。然而,在 ECMAScript 2015规范中这点已被更改。有关详细信息,请参阅浏览器兼容性 表中的“value equality for -0 and 0”。另外,NaN和undefined都可以被存储在Set 中, NaN之间被视为相同的值(尽管 NaN !== NaN)。Set本身是一个构造函数,用来生成 Set 数据结构。Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。let b = new Set([‘a’,‘b’,‘c’,‘a’,‘b’]);// Set(3) {“a”, “b”, “c”}set传入参数也可以一试string;let a = new Set(‘aabbcc’);// Set(3) {a,b,c}Set 结构的实例有以下属性。Set.prototype.constructor:构造函数,默认就是Set函数。Set.prototype.size:返回Set实例的成员总数。Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。add(value):添加某个值,返回 Set 结构本身。delete(value):删除某个值,返回一个布尔值,表示删除是否成功。has(value):返回一个布尔值,表示该值是否为Set的成员。clear():清除所有成员,没有返回值。Array.from方法可以将 Set 结构转为数组。或者是扩展运算符…const items = new Set([1, 2, 3, 4, 5]);const array = Array.from(items);const test = […items];遍历操作Set 结构的实例有四个遍历方法,可以用于遍历成员。keys():返回键名的遍历器values():返回键值的遍历器entries():返回键值对的遍历器forEach():使用回调函数遍历每个成员由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。let set = new Set([‘red’, ‘green’, ‘blue’]);for (let item of set.keys()) { console.log(item);}// red// green// bluefor (let item of set.values()) { console.log(item);}// red// green// bluefor (let item of set.entries()) { console.log(item);}// [“red”, “red”]// [“green”, “green”]// [“blue”, “blue”]Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法。Set.prototype[Symbol.iterator] === Set.prototype.values// true这意味着,可以省略values方法,直接用for…of循环遍历 Set。let set = new Set([‘red’, ‘green’, ‘blue’]);for (let x of set) { console.log(x);}// red// green// blueWeakSetWeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。首先,WeakSet 的成员只能是对象,而不能是其他类型的值。const ws = new WeakSet();ws.add(1)// TypeError: Invalid value used in weak setws.add(Symbol())// TypeError: invalid value used in weak setWeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在MapJavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。const map = new Map([ [’name’, ‘张三’], [’title’, ‘Author’]]);map.size // 2map.has(’name’) // truemap.get(’name’) // “张三"不仅仅是数组,任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构(详见《Iterator》一章)都可以当作Map构造函数的参数。这就是说,Set和Map都可以用来生成新的 Map。Map.prototype.clear()移除Map对象的所有键/值对 。Map.prototype.delete(key)如果 Map 对象中存在该元素,则移除它并返回 true;否则如果该元素不存在则返回 falseMap.prototype.get(key)返回键对应的值,如果不存在,则返回undefined。Map.prototype.has(key)返回一个布尔值,表示Map实例是否包含键对应的值。Map.prototype.keys()返回一个新的 Iterator对象, 它按插入顺序包含了Map对象中每个元素的键 。Map.prototype.set(key, value)设置Map对象中键的值。返回该Map对象。遍历方法Map 结构原生提供三个遍历器生成函数和一个遍历方法。keys():返回键名的遍历器。values():返回键值的遍历器。entries():返回所有成员的遍历器。forEach():遍历 Map 的所有成员。WeakMapWeakMap与Map的区别有两点。首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。 ...

January 6, 2019 · 1 min · jiezi

ES6 系列之 defineProperty 与 proxy

前言我们或多或少都听过“数据绑定”这个词,“数据绑定”的关键在于监听数据的变化,可是对于这样一个对象:var obj = {value: 1},我们该怎么知道 obj 发生了改变呢?definePropetyES5 提供了 Object.defineProperty 方法,该方法可以在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。语法Object.defineProperty(obj, prop, descriptor)参数obj: 要在其上定义属性的对象。prop: 要定义或修改的属性的名称。descriptor: 将被定义或修改的属性的描述符。举个例子:var obj = {};Object.defineProperty(obj, “num”, { value : 1, writable : true, enumerable : true, configurable : true});// 对象 obj 拥有属性 num,值为 1虽然我们可以直接添加属性和值,但是使用这种方式,我们能进行更多的配置。函数的第三个参数 descriptor 所表示的属性描述符有两种形式:数据描述符和存取描述符。两者均具有以下两种键值:configurable当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,也能够被删除。默认为 false。enumerable当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。数据描述符同时具有以下可选键值:value该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。writable当且仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变。默认为 false。存取描述符同时具有以下可选键值:get一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined。set一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。值得注意的是:属性描述符必须是数据描述符或者存取描述符两种形式之一,不能同时是两者。这就意味着你可以:Object.defineProperty({}, “num”, { value: 1, writable: true, enumerable: true, configurable: true});也可以:var value = 1;Object.defineProperty({}, “num”, { get : function(){ return value; }, set : function(newValue){ value = newValue; }, enumerable : true, configurable : true});但是不可以:// 报错Object.defineProperty({}, “num”, { value: 1, get: function() { return 1; }});此外,所有的属性描述符都是非必须的,但是 descriptor 这个字段是必须的,如果不进行任何配置,你可以这样:var obj = Object.defineProperty({}, “num”, {});console.log(obj.num); // undefinedSetters 和 Getters之所以讲到 defineProperty,是因为我们要使用存取描述符中的 get 和 set,这两个方法又被称为 getter 和 setter。由 getter 和 setter 定义的属性称做”存取器属性“。当程序查询存取器属性的值时,JavaScript 调用 getter方法。这个方法的返回值就是属性存取表达式的值。当程序设置一个存取器属性的值时,JavaScript 调用 setter 方法,将赋值表达式右侧的值当做参数传入 setter。从某种意义上讲,这个方法负责“设置”属性值。可以忽略 setter 方法的返回值。举个例子:var obj = {}, value = null;Object.defineProperty(obj, “num”, { get: function(){ console.log(‘执行了 get 操作’) return value; }, set: function(newValue) { console.log(‘执行了 set 操作’) value = newValue; }})obj.value = 1 // 执行了 set 操作console.log(obj.value); // 执行了 get 操作 // 1这不就是我们要的监控数据改变的方法吗?我们再来封装一下:function Archiver() { var value = null; // archive n. 档案 var archive = []; Object.defineProperty(this, ’num’, { get: function() { console.log(‘执行了 get 操作’) return value; }, set: function(value) { console.log(‘执行了 set 操作’) value = value; archive.push({ val: value }); } }); this.getArchive = function() { return archive; };}var arc = new Archiver();arc.num; // 执行了 get 操作arc.num = 11; // 执行了 set 操作arc.num = 13; // 执行了 set 操作console.log(arc.getArchive()); // [{ val: 11 }, { val: 13 }]watch API既然可以监控数据的改变,那我可以这样设想,即当数据改变的时候,自动进行渲染工作。举个例子:HTML 中有个 span 标签和 button 标签<span id=“container”>1</span><button id=“button”>点击加 1</button>当点击按钮的时候,span 标签里的值加 1。传统的做法是:document.getElementById(‘button’).addEventListener(“click”, function(){ var container = document.getElementById(“container”); container.innerHTML = Number(container.innerHTML) + 1;});如果使用了 defineProperty:var obj = { value: 1}// 储存 obj.value 的值var value = 1;Object.defineProperty(obj, “value”, { get: function() { return value; }, set: function(newValue) { value = newValue; document.getElementById(‘container’).innerHTML = newValue; }});document.getElementById(‘button’).addEventListener(“click”, function() { obj.value += 1;});代码看似增多了,但是当我们需要改变 span 标签里的值的时候,直接修改 obj.value 的值就可以了。然而,现在的写法,我们还需要单独声明一个变量存储 obj.value 的值,因为如果你在 set 中直接 obj.value = newValue 就会陷入无限的循环中。此外,我们可能需要监控很多属性值的改变,要是一个一个写,也很累呐,所以我们简单写个 watch 函数。使用效果如下:var obj = { value: 1}watch(obj, “num”, function(newvalue){ document.getElementById(‘container’).innerHTML = newvalue;})document.getElementById(‘button’).addEventListener(“click”, function(){ obj.value += 1});我们来写下这个 watch 函数:(function(){ var root = this; function watch(obj, name, func){ var value = obj[name]; Object.defineProperty(obj, name, { get: function() { return value; }, set: function(newValue) { value = newValue; func(value) } }); if (value) obj[name] = value } this.watch = watch;})()现在我们已经可以监控对象属性值的改变,并且可以根据属性值的改变,添加回调函数,棒棒哒~proxy使用 defineProperty 只能重定义属性的读取(get)和设置(set)行为,到了 ES6,提供了 Proxy,可以重定义更多的行为,比如 in、delete、函数调用等更多行为。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。我们来看看它的语法:var proxy = new Proxy(target, handler);proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。var proxy = new Proxy({}, { get: function(obj, prop) { console.log(‘设置 get 操作’) return obj[prop]; }, set: function(obj, prop, value) { console.log(‘设置 set 操作’) obj[prop] = value; }});proxy.time = 35; // 设置 set 操作console.log(proxy.time); // 设置 get 操作 // 35除了 get 和 set 之外,proxy 可以拦截多达 13 种操作,比如 has(target, propKey),可以拦截 propKey in proxy 的操作,返回一个布尔值。// 使用 has 方法隐藏某些属性,不被 in 运算符发现var handler = { has (target, key) { if (key[0] === ‘_’) { return false; } return key in target; }};var target = { _prop: ‘foo’, prop: ‘foo’ };var proxy = new Proxy(target, handler);console.log(’_prop’ in proxy); // false又比如说 apply 方法拦截函数的调用、call 和 apply 操作。apply 方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组,不过这里我们简单演示一下:var target = function () { return ‘I am the target’; };var handler = { apply: function () { return ‘I am the proxy’; }};var p = new Proxy(target, handler);p();// “I am the proxy"又比如说 ownKeys 方法可以拦截对象自身属性的读取操作。具体来说,拦截以下操作:Object.getOwnPropertyNames()Object.getOwnPropertySymbols()Object.keys()下面的例子是拦截第一个字符为下划线的属性名,不让它被 for of 遍历到。let target = { _bar: ‘foo’, prop: ‘bar’, prop: ‘baz’};let handler = { ownKeys (target) { return Reflect.ownKeys(target).filter(key => key[0] !== ‘’); }};let proxy = new Proxy(target, handler);for (let key of Object.keys(proxy)) { console.log(target[key]);}// “baz"更多的拦截行为可以查看阮一峰老师的 《ECMAScript 6 入门》值得注意的是,proxy 的最大问题在于浏览器支持度不够,而且很多效果无法使用 poilyfill 来弥补。watch API 优化我们使用 proxy 再来写一下 watch 函数。使用效果如下:(function() { var root = this; function watch(target, func) { var proxy = new Proxy(target, { get: function(target, prop) { return target[prop]; }, set: function(target, prop, value) { target[prop] = value; func(prop, value); } }); if(target[name]) proxy[name] = value; return proxy; } this.watch = watch;})()var obj = { value: 1}var newObj = watch(obj, function(key, newvalue) { if (key == ‘value’) document.getElementById(‘container’).innerHTML = newvalue;})document.getElementById(‘button’).addEventListener(“click”, function() { newObj.value += 1});我们也可以发现,使用 defineProperty 和 proxy 的区别,当使用 defineProperty,我们修改原来的 obj 对象就可以触发拦截,而使用 proxy,就必须修改代理对象,即 Proxy 的实例才可以触发拦截。ES6 系列ES6 系列目录地址:https://github.com/mqyqingfeng/BlogES6 系列预计写二十篇左右,旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容。如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。 ...

November 9, 2018 · 4 min · jiezi