关于es6:ES6使用let命令声明变量

ES6 中新增了 let 命令,能够用于申明变量。上面咱们就一起来看一下 let 命令的应用。 应用let申明变量let 命令是 ES6 中新增的用于申明变量的一个命令,申明变量时的用法和 JavaScript 中的 var 相似。 示例:例如上面咱们应用 let 命令来申明变量: let a = 10;let b = 20;let c = 30;let 申明的变量只在代码块内无效let 命令的应用尽管和 var 相似,然而两者还是有区别的,例如应用 let 申明的变量,只在 let 所在的代码块内无效。这是什么意思呢,上面咱们通过一个例子来解说一下。 示例:例如咱们在一段代码块中同时应用 let 和 var 来申明一个变量,而后在代码块外应用这个变量: { var a = 10; let b = 20;}console.log(a); console.log(b);当咱们咱们执行这段代码时,输入后果会报错,上面为谬误提醒: ReferenceError: b is not defined这个谬误通知咱们,变量 b 没有被申明,然而咱们明明在 {} 中申明了变量 b ,这示意 let 申明的变量只在它所在的代码块无效,在代码块外应用变量 b 会报错。 let不容许反复申明变量let 命令和 var 命令还有一个不同就是,let 命令只能申明同一个变量一次,而 var 能够申明一个变量屡次。 ...

December 3, 2020 · 1 min · jiezi

关于es6:ES6的简介

ES6 是 ECMAScript6 的简称,是2015年6月正式公布的 JavaScript 语言的规范,正式命名为 ECMAScript 2015,它的指标是使得 JavaScript 语言能够用来编写简单的大型应用程序,成为企业级开发语言。 ES6 次要是为了解决 ES5 的先天不足,比方 JavaScript 里没有类的概念,然而目前浏览器的 JavaScript 是 ES5 版本,大多数高版本的浏览器也反对 ES6,不过只是实现了 ES6 的局部个性和性能。 ECMAScript和JavaScript的关系对于 ECMAScript 和 JavaScript 两者之间的关联,简略的来说就是,前者是后者语言的国际标准,后者是前者的一种实现,在日常场合,这两个词是能够调换的。 JavaScript 的创造者 Netscape 公司,将 JavaScript 提交给国际标准化组织 ECMA,心愿这种语言可能成为国际标准,起初 ECMA 公布标准文件的第一版(ECMA-262),规定了浏览器脚本语言的规范,并将这种语言称为 ECMAScript。该规范从一开始就是针对 JavaScript 语言制订的,之所以不叫 JavaScript,有两个起因: 一是商标,Java 是 Sun 公司的商标,依据受权协定,只有 Netscape 公司能够非法地应用 JavaScript 这个名字,且 JavaScript 自身也曾经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,有利于保障这门语言的开放性和中立性。一个残缺的 JavaScript 实现应该由以下三个局部组成: ECMAScript :外围。DOM:文档对象模型。BOM:浏览器对象模型。ES6与ECMAScript 2015的关系2011 年,ECMAScript 5.1 版公布后,就开始制订 6.0 版了。因而 ES6 这个词的原意,就是指 JavaScript 语言的下一个版本。 ...

November 27, 2020 · 1 min · jiezi

关于es6:ES6-箭头函数

应用箭头函数来定义函数:var f=v=>v;//等同于var f=function(v){ return v;};如果箭头函数不须要参数:var f=()=>5;//等同于var f=function(){return 5};如果箭头函数有多个参数:var sum = (num1,num2)=>num1+num2;//等同于var sum = function(num1,num2){ return num1+num2;};如果箭头函数的代码块局部多余一条语句,就要应用大括号将它们括起来,并且应用return语句返回。var sum = (num1,num2) => {return num1 + num2;}因为大括号被解释为代码块,所以如果箭头函数间接返回一个对象,必须在对象里面加上括号。 let getTempItem=id=>{id:id,name:"Temp"};//报错let getTempItem=id=>({id:id,name:"Temp"});//不报错上面代码可运行,但会失去谬误的后果。 let foo=()=>{a:1};foo() //undefined下面代码中,本用意返回一个对象{a:1},但因为大括号被解释成代码块,所以执行了一行语句a:1。此时,a被解释为语句的标签,因而理论执行的语句是1,而后函数就完结了,没有返回值。 如果箭头函数只有一行语句,且不须要返回值,能够采纳上面的写法,就不须要写大括号了。let fn=()=>void doesNotReturn();箭头函数能够与变量构造联合应用:const full=({first,last})=>first+' '+last;//等同于function full(person){ return person.first+' '+person.last;}箭头函数使得表白更加简洁:const isEven=n=>n%2===0;const square=n=>n*n;两行醒目的代码定义了两个简略的工具函数,如果不应用箭头函数,可能就要占用多行。 箭头函数的一个用途是简化回调函数://一般函数[1,2,3].map(function(x){ return x*x;});//箭头函数[1,2,3].map(x=>x*x);//一般函数var result = values.sort(function(a,b){ return a-b;});//箭头函数var result = values.sort((a,b)=>a-b);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]]*箭头函数留神点函数体内的this对象,就是定义时所在的对象,而不是应用时所在的对象。不能够当作构造函数,即不能够应用new命令,否则会抛出谬误。不能够应用arguments对象,该对象在函数体内不存在,能够应用rest参数代替。不能够应用yield命令,因而箭头函数不能用作Generator函数。第一点扩大=>this对象的指向是可变的,然而在箭头函数中,它是固定的。function foo(){ setTimeout(()=>{ console.log('id:',this.id); },100);}var id=21;foo.call({id:42});//id:42该代码中,setTimeout()的参数是一个箭头函数,这个箭头函数的定义失效是在foo函数生成时,而它的真正执行要等到100毫秒后。如果是一般函数,执行时this应该指向全局对象window,这时应该输入21。但箭头函数导致this总是指向函数定义失效时所在的对象({id:42}),所以打印进去的时42。 箭头函数能够让setTimeout外面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。 function Timer() { this.s1 = 0; this.s2 = 0; // 箭头函数 setInterval(() => this.s1++, 1000); // 一般函数 setInterval(function () { this.s2++; }, 1000);}var timer = new Timer();setTimeout(() => console.log('s1: ', timer.s1), 3100);setTimeout(() => console.log('s2: ', timer.s2), 3100);// s1: 3// s2: 0该代码中,Timer函数外部设置了两个定时器,别离应用了箭头函数和一般函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(全局对象)。所以,3100ms之后,timer.s1被更新了三次,而timer.s2一次都没更新。 ...

November 14, 2020 · 2 min · jiezi

关于es6:ECMAScript新特性

首先要辨别语言和平台之间的关系,语言自身是指ECMAScript,平台是指浏览器或者node,在平时咱们浏览器开发里js就是ECMAScript。浏览器的组成部分node.js的组成部分

November 7, 2020 · 1 min · jiezi

关于es6:使用ES5实现ES6的Class

ES5的寄生组合式继承function parent (age) { this.age = age}parent.prototype.say = function () { console.log(this.age)}function sub (age, value) { parent.call(this, age) this.value = value}sub.prototype = Object.create(parent.prototype, { constructor: { value: sub, enumerable: false, writable: true, configurable: true }})ES6的Class对于Class的语法举荐看这里:es6.ruanyifeng.com/#docs/class ES6 的class能够看作只是一个语法糖,它的绝大部分性能,ES5 都能够做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。然而它们还是有区别的。 区别: 类必须应用new调用,否则会报错。ES的构造函数是能够当成一般函数应用的类的外部所有定义的办法,都是不可枚举的。(包含外部定义的静态方法)类的静态方法也能够被子类继承能够继承原生构造函数 ES5 是先新建子类的实例对象this,再将父类的属性增加到子类上,因为父类的外部属性无奈获取,导致无奈继承原生的构造函数。ES6 容许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this,而后再用子类的构造函数润饰this,使得父类的所有行为都能够继承应用ES5模仿实现ES6的class依据下面的区别,咱们一步步的看。 1. new操作符查看函数解决问题: 类必须应用new调用,否则会报错。ES的构造函数是能够当成一般函数应用的function _checkType (obj, constructor) { if (!(obj instanceof constructor)) { throw new TypeError('Cannot call a class as a function') }}2. 外部办法不可枚举解决问题: ...

November 5, 2020 · 2 min · jiezi

关于es6:promise-all异步用法

同步与异步的区别: 同步: 同步的思维是:所有的操作都做完,才返回给用户。这样用户在线期待的工夫太长,给用户一种卡死了的感觉(就是零碎迁徙中,点击了迁徙,界面就不动了,然而程序还在执行,卡死了的感觉)。这种状况下,用户不能敞开界面,如果敞开了,即迁徙程序就中断了。 异步: 将用户申请放入音讯队列,并反馈给用户,零碎迁徙程序曾经启动,你能够敞开浏览器了。而后程序再缓缓地去写入数据库去。这就是异步。然而用户没有卡死的感觉,会通知你,你的申请零碎曾经响应了。你能够敞开界面了。 promise all异步用法: getType=(data)=>{ return new Promise(function(resolve, reject){ resolve(data); //输入数据 });}getHeader=(data)=>{ return new Promise(function(resolve, reject){ resolve(data); //输入数据 });}getList=(data1,data2)=>{ this.setState({ data1, data2, })} Promise.all([ this.getType(1), this.getHeader(2) ]).then((results)=>{ var data1=results[0]; var data2=results[1]; this.getList(data1,data2); })

November 2, 2020 · 1 min · jiezi

关于es6:9数组的扩展

扩大运算符含意扩大运算符(spread)是三个点(...),能够当作rest参数的逆运算,将数组转为用逗号分隔的参数序列rest是把传入的参数组合成一个数组扩大运算符是把数组分解成参数 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>]该运算符次要用于函数的调用,将一个数组,变为参数序列function push(array,...items){ array.push(...items)}function add(x,y){ return x+y}const numbers = [4,38]add(...numbers) //42...能够与失常的参数联合应用function f(v,w,x,y,z){ console.log(v,w,x,y,z) //-1 0 1 2 3}const args = [0,1]f(-1,...args,2,...[3]);...前面还能够搁置表达式var x = 1const arr = [ ...(x>0?['a']:[]), 'b',]console.log(arr) //['a','b']如果扩大运算符前面是一个空数组,则不产生任何成果。[...[], 1]// [1]只有函数调用时,扩大运算符才能够放在圆括号中(...[1, 2])// Uncaught SyntaxError: Unexpected numberconsole.log((...[1, 2]))// Uncaught SyntaxError: Unexpected numberconsole.log(...[1, 2])// 1 2下面三种状况,扩大运算符都放在圆括号外面,然而前两种状况会报错,因为扩大运算符所在的括号不是函数调用。代替apply办法es5:function f(x,y,z){ console.log(x,y,z) // 0 1 2}var args = [0,1,2];f.apply(null,args)因为f接管的参数不能为数组,为了不便,能够用apply办法来实现用数组的参数来传递,这是很多时候使用的一个小技巧罢了。而apply办法第一个参数,是要代替的对象。没有要代替的,用null,也是很天然的es6:function f(x,y,z){ console.log(x,y,z) // 0 1 2}var args = [0,1,2]f(...args)利用:Math.max// ES5 的写法Math.max.apply(null, [14, 3, 77])// ES6 的写法Math.max(...[14, 3, 77])// 等同于Math.max(14, 3, 77);将一个数组增加到另一个数组的尾部es5:var arr1 = [0, 1, 2];var arr2 = [3, 4, 5];Array.prototype.push.apply(arr1,arr2)console.log(arr1)//[0,1,2,3,4,5]push办法的参数不能是数组,所以只好通过apply办法变通应用push办法es6:let arr1 = [0, 1, 2];let arr2 = [3, 4, 5];arr1.push(...arr2);console.log(arr1)//[0,1,2,3,4,5]另一个例子// ES5new (Date.bind.apply(Date, [null, 2015, 1, 1]))// ES6new Date(...[2015, 1, 1]);bind.apply: ...

October 16, 2020 · 5 min · jiezi

关于es6:8函数的扩展

函数参数的默认值根本用法es5中,传入函数的参数如果为'',那么在进行判断时会转化为false,对后果造成影响 function log(x, y) { y = y || 'World'; console.log(x, y);}log('Hello') // Hello Worldlog('Hello', 'China') // Hello Chinalog('Hello', '') // Hello World //这里!es6容许为函数的参数设置默认值,间接写在参数定义的前面,只有在参数是undefined时才采纳默认值 function log(x, y = 'World') { console.log(x, y);}log('Hello') // Hello Worldlog('Hello', 'China') // Hello Chinalog('Hello', '') // Hellofunction Point(x=0,y=0){ this.x = x this.y = y}const p = new Point()p //{x:0,y:0}参数的变量是默认申明的,不能再次申明 function foo(x=5){ let x =1 // error const x =2 // error}应用参数默认值时,函数不能有同名函数 ...

October 16, 2020 · 5 min · jiezi

关于es6:7数值的扩展

1.二进制八进制二进制:前缀0b:0b111110111 === 503 八进制:前缀0o:0o767 === 503 2.Number.isFinite(),Number.isNaN()Number.isFinite():查看数值是否为无限的,Infinity和非数值类型都返回false Number.isFinite(15); // trueNumber.isFinite(0.8); // trueNumber.isFinite(NaN); // falseNumber.isFinite(Infinity); // falseNumber.isFinite(-Infinity); // falseNumber.isFinite('foo'); // falseNumber.isFinite('15'); // falseNumber.isFinite(true); // falseNumber.isNaN():查看数值是否为NaN,参数类型不是NaN返回false Number.isNaN(NaN) // trueNumber.isNaN(15) // falseNumber.isNaN('15') // falseNumber.isNaN(true) // falseNumber.isNaN(9/NaN) // trueNumber.isNaN('true' / 0) // trueNumber.isNaN('true' / 'true') // true区别于传统的isFinite()和isNaN()isFinite()和isNaN()会先调用Number(),转为数字,再判断Number.isFinite(),Number.isNaN()只对数字无效,不转化 3.Number.parseInt(),Number.parseFloat()ES6 将全局办法parseInt()和parseFloat(),移植到Number对象下面,行为齐全放弃不变。这样做的目标,是逐渐缩小全局性办法,使得语言逐渐模块化。 Number.parseInt === parseInt // trueNumber.parseFloat === parseFloat // true4.Number.isInteger()Number.isInteger():判断一个数是否为整数,非数值和浮点数返回false(js外部,整数和浮点数采纳同样的贮存办法,所以25.0等同于25)留神:1.因为 JavaScript 采纳 IEEE 754 规范,数值存储为64位双精度格局,数值精度最多能够达到 53 个二进制位(1 个暗藏位与 52 个无效位)。如果数值的精度超过这个限度,第54位及前面的位就会被抛弃,这种状况下,Number.isInteger可能会误判。2.如果一个数值的绝对值小于Number.MIN_VALUE(5E-324),即小于 JavaScript 可能分辨的最小值,会被主动转为 0。这时,Number.isInteger也会误判。 ...

October 16, 2020 · 3 min · jiezi

关于es6:5字符串新增方法

String.fromCodePoint()因为String.fromCharCode 用于从unicode码点返回对应字符,但码点大于0xFFFF的不行所以String.fromCodePoint能够识别码点大于0xFFFF的字符 Stirng.raw()String.raw()实质上是一个函数,能够作为解决模板字符串的根本办法,它会将所有变量替换专用于模板字符串的标签函数写成失常函数的模式:它的第一个参数,应该是一个具备raw属性的对象,且raw属性的值应该是一个数组,对应模板字符串解析后的值。 // `foo${1 + 2}bar`// 等同于String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"返回一个斜杠都被本义的字符串 String.raw`Hi\n${2+3}!`// 理论返回 "Hi\\n5!",显示的是本义后的后果 "Hi\n5!"String.raw`Hi\u000A!`;// 理论返回 "Hi\\u000A!",显示的是本义后的后果 "Hi\u000A!"如果原字符串的斜杠曾经本义,那么String.raw()会进行再次本义 String.raw`Hi\\n`// 返回 "Hi\\\\n"String.raw`Hi\\n` === "Hi\\\\n" // truecodePointAt()JavaScript 外部,字符以 UTF-16 的格局贮存,每个字符固定为2个字节。对于那些须要4个字节贮存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符.codePointAt()够正确处理 4 个字节贮存的字符,返回一个字符的码点 normalize()includes(),stratsWith(),endsWith()确定字符串是否蕴含在另一个字符串中,三个均返回布尔值includes(string,n):是否找到了参数字符串startsWith(string,n):参数字符串是否在原字符串头部endsWith(string,n):参数字符串是否在原字符串尾部n:endsWith:前n个字符includes,startsWith:第n个地位到字符串完结 let s = 'Hello world!';s.startsWith('world', 6) // trues.endsWith('Hello', 5) // trues.includes('Hello', 6) // falserepeat()返回一个新字符串,将原字符串反复n次 'x'.repeat(3) // "xxx"'hello'.repeat(2) // "hellohello"'na'.repeat(0) // ""小数会被取整'na'.repeat(2.9) // "nana"正数或者infinity会报错'na'.repeat(Infinity)// RangeError'na'.repeat(-1)// RangeError0到-1,取整,视为0'na'.repeat(-0.9) // ""NaN,等同于0'na'.repeat(NaN) // ""repeat的参数是字符串,则会先转换成数字。'na'.repeat('na') // ""'na'.repeat('3') // "nanana"padStart(),padEnd()如果字符串不够指定长度,会在头部或尾部补全padStart(n,string):补全头部padEnd(n,string):补全尾部n:最大长度string:用来补全的字符串 ...

October 16, 2020 · 1 min · jiezi

关于es6:变量的解构赋值

变量的解构赋值:数组的解构赋值:依照肯定模式,从数组和对象中提取对象,对变量进行赋值,称为解构. let [a,b,c] = [1,2,3]写法属于“模式匹配”:依照对应地位,对变量赋值 let [head,...tail] = [1,2,3,4]head = 1tail = [2,3,4]解构不胜利:变量的值就等于undefined. let [bar,foo] = [1]foo = undefined不齐全解构: let [a,[b],d] = [1,[2,3],4]a = 1b= 2d = 4如果左边不是数组,回报错 let [foo] = 1;let [foo] = false;let [foo] = NaN;let [foo] = undefined;let [foo] = null;let [foo] = {};set构造,也能够解构赋值 let [x,y,z] = new Set(['a','b','c'])只有数据结构具备迭代,都能够解构赋值 默认值let [foo = true] = []foo = truelet [x, y='b'] =['a',undefined]x= ay = b当一个数组成员严格等于(===)undefined的时候,才采纳默认值([y= 'b']) ...

October 16, 2020 · 3 min · jiezi

关于es6:forEach和for循环方法

forEach()办法用于调用数组的每一个元素,并将元素传递给回调函数语法:array.forEach(function(currentValue, index, arr), thisValue)currentValue:必填,以后元素。index:可选,以后元素的索引。arr:可选,以后元素所属的数组对象。thisValue:可选,传递给函数的值个别用this值,如果这个参数为空,"undefined"会传递给"this"值。(这个参数个别很少填)留神:currentValue 必须放在index的后面 const list = ['a', 'b', 'c', 'd']list.forEach((item, index, arr) => { console.log(item, index, arr)})//for循环与以上成果等同for (let i = 0; i < list1.length; i++) { const element = list[i]; console.log(element, i, list)}迭代1、 forEach() 对于空数组是不会执行回调函数的。2、 for能够用continue跳过循环中的一个迭代,forEach用continue会报错。3、 forEach() 须要用 return 跳过循环中的一个迭代,跳过之后会执行下一个迭代。 const list = ['a', 'b', 'c', 'd'] list3.forEach((item, index) => { if (index == 2) { return;//跳出迭代 } console.log(item, index)});for (let i = 0; i < list.length; i++) { if (i == 2) { continue;//跳出迭代 } console.log(list[i], i)}

October 16, 2020 · 1 min · jiezi

关于es6:javascript-ES6-var-let-const的区别于用法

在es6中更新了两个变量命名办法别离为let const简洁来说:let:比照var不能反复定义,有作用域{自带闭包问题}经常体现在if判断和for循环当中const:不能反复定义,会被间接定义为常量例 function fun(){var a=1var a=2}fun()alert(a)//这里会弹出2为什么咱们在函数内定义的变量在函数里面仍然能够拜访呢?就是因为下面说的,没有作用域问题,并且能够反复定义同样的问题let没有任何谬误在日常99%的状况let是能够代替var的 function fun(){let a=1let a=2}fun()alert(a)//这里会间接报错,就算删掉第二次定义也会弹出‘未定义’,这是因为let自带的作用域问题,在函数内定义的问题就只能在函数内应用至于const常量怎么用他就怎么用,个别是用不到的

October 12, 2020 · 1 min · jiezi

关于es6:es6

ES6一、变量1.1 let变量用于申明变量,用法与var相似,但存在新的个性 个性: let所申明的变量,只在以后代码块内无效,防止全局净化没有变量申明晋升暂时性死区,在let命令申明变量前,该变量都是不可用的不容许反复申明二、常量2.1 const命令用于申明常量 个性: 不能够从新赋值 const obj = { name:'alice', age:22}obj.name = 'zhang' //{ name: 'zhang', age: 22 },不报错,因为只扭转了对象的值,没有扭转援用地址申明的同时必须初始化 const a = 7;暂时性死区不容许反复申明只在以后的代码块内无效三、解构3.1 数组解构从数组和对象中提取值,对变量进行赋值。即只有等号两边的模式雷同,等号左边的值就会一一进行赋值。 let [a,b,c] = [1,2,3]let [a,b,c] = [1,2,3,4] //1 2 3let [a,b,...c] = [1,2,3,4] //1 2 [3,4]let[a,b,c,d,e] = [1,2,3] //1 2 3 undefined undefined//等号右边变量多余,多余的变量会被赋值为undefined//等号左边变量多余,多余的变量会被忽视或者应用...将其整合为一个数组let[a,[b],c] = [1,[2,3],4] //1 2 4let[a,b,c] = [1,[2,3],4] //1 [ 2, 3 ] 4let[a,[b,c],d] = [1,[2,3],4] //1 2 3 4let[a,b,c,d] = [1,[2,3],4] //1 [ 2, 3 ] 4 undefinedlet[a,b=22] = [10] //10 22let[a,b=22] = [10,20] //10 20//如果扭转了默认值,则以扭转后的值为准,若没有扭转,则持续应用默认值数组嵌套对象 ...

October 3, 2020 · 5 min · jiezi

关于es6:Promise的理解及asyncawait的基本用法

Promise 是ES6中新进去的API。其实就是对于回调函数的另一种写法,能够帮忙咱们防止回调天堂。 Promise是一个构造函数,new Promise 返回一个 promise 对象,接管一个带有 resolve 和 reject 两个参数的函数,这个函数在 Promise 构造函数返回所创立 promise 实例对象前被调用。 var p = new Promise(function(resolve, reject) { resolve() // 胜利时调用 reject() // 失败时调用});p.then(function(res) { // 从resolve失去失常后果}, function(res) { // 从reject失去错误信息})resolve,reject 是一个函数,解决完结后调用 resolve 或 reject。当调用resolve,会把以后promise对象状态由 pending 标记胜利(fulfilled),当调用 reject,会把状态由 pending 标记失败(rejected)。 Promise的三种状态: pending :挂起,以后promise执行的工作,正在执行中fulfilled: 实现,以后promise对象执行的工作,曾经实现,并且是胜利状态rejected: 实现,以后promise对象执行的工作,曾经实现,并且处于失败的状态封装一个反对Promise API的延时函数: function timeOut(time){ // 这个函数中就须要返回一个Promise对象 return new Promise((resolve, reject) => { setTimeout(function(){ // resolve和reject在调用的时候,是能够传递数据的,这个数据会最终被传递到胜利或者失败的回调函数中 resolve(123) // resolve() // reject() }, time) })}基于Promise解决Ajax申请: ...

September 30, 2020 · 2 min · jiezi

关于es6:javascript高级6

为什么要学习ES6每一次规范的诞生意味着语言的欠缺,性能的增强,javascript自身也有一些令人不称心的中央 变量晋升个性减少了程序运行时的不可预测性语法过于涣散,实现雷同的性能,不同的人可能会写出不同的代码 let关键字let申明的关键字具备块级作用域,所谓的块级作用域便是一个{}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>let申明的变量具备块级作用域</title></head><body></body><script> if (true) { let a = 20; console.log(a); //20 if (true) { let b = 50; console.log(b)//50 } } console.log(a) //a is not define</script></html> let能够避免循环变量变成全局变量<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>let能够避免循环变量变成全局变量</title></head><body></body><script> for(let i =0;i<2;i++){ } console.log(i) //i is not define</script></html> let申明的变量不会进行变量晋升<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>let申明的变量不会进行变量晋升</title></head><body></body><script> console.log(a) // a is not define let a = 20;</script></html> let申明的变量具备暂存性死区的个性<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>let申明的变量具备暂存性死区的个性</title></head><body></body><script> let a = 20; if(true) { console.log(a) let a = 30; }</script></html> ...

September 29, 2020 · 1 min · jiezi

关于es6:ECMAScript-6新特性简介

简介ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代规范,正式公布与2015年6月。它的指标,是使得JavaScript语言能够用来编写简单的大型应用程序,成为企业级开发语言。 明天咱们将会解说一下ES6中引入的语法新个性。 ECMAScript和JavaScript的关系1996年11月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给国际标准化组织ECMA. 1997年, ECMA 公布262号标准文件 ECMAScript 1.0。 ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。 咱们看一下ECMAScript的发行历史: 从2015年ES2015,也就是ES6公布以来,ECMAScript以每年一个版本的发行速度发行到了ES2020。 前面的文章咱们会解说一下这些新版本的ECMAScript的新个性。 let和constES6中引入了let和const,是为了解决之前的var变量的种种问题。 在ES6之前,JS中变量的作用域有两种:全局作用域和函数作用域。 全局作用域很好了解,咱们在浏览器控制台或者 Node.js 交互终端中开始编写 JavaScript 时,即进入了所谓的全局作用域。 全局作用域的变量能够在任何其余作用域中拜访。 函数作用域就是定义在函数外部的变量,在函数外部都能够拜访到该变量。 这两种作用域会有一些问题: 变量晋升var命令会产生”变量晋升”景象,即变量能够在申明之前应用,值为undefined. // var 的状况 console.log(foo); // 输入undefined var foo = 2; 变量笼罩当咱们在函数作用域应用全局变量的时候,如果函数作用域中定义了同样名字的变量,不论是在哪里定义的,都会笼罩掉全局的变量。如下所示: var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = "hello world"; } } f(); // undefined变量泄露变量泄露的意思是,咱们原本只心愿在小范畴作用域应用的变量,后果泄露到了范畴里面,如下所示: ...

September 22, 2020 · 4 min · jiezi

关于es6:javascript高级5

ES6ES:全称ECMAScript,它是由ECMA国际标准化组织制订的一项脚本语言的标准化标准。 所谓的ES6,指的是2015年当前的版本 let关键字ES6中新增申明变量的关键字<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>let关键字申明变量</title></head><body></body><script> let num = 20; console.log(num) //20</script></html> 具备的特点 具备块级作用域所谓的块级作用域,简略而言 就是{} <!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <title>块级作用域</title> </head> <body> </body> <script> if (true) { let a = 20; console.log(a); if (true) { let b = 50; console.log(b) //50 } console.log(b) //b is not define } </script></html> 不存在变量晋升具备暂时性死区

September 20, 2020 · 1 min · jiezi

关于es6:使用-requirecontext实现自动化导入按文件夹导入

例:要导入的动态文件夹构造 const folderReader = require.context('../../../../assets/chartTypes/options',false,/\.js$/);folderReader返回一个办法webpackContext(req) 应用: const __chartTypes = folderReader.keys().map((k)=>{ return folderReader(k).default; });其中folderReader.keys()返回文件夹内的文件相对路径的数组: 应用返回的数组作为参数调用folderReader返回的办法,就能获得对应的文件内export default 的输入folderReader(k)的输入:最初取得__chartTypes的值: 还有要留神的是,我这里的动态option文件外部是附带了图片的援用,以不便生成带图片的选项。因为门路问题以及打包之后重命名的问题,option内是不能间接应用相对路径定位图片并传进去的。而是应该应用import:`import image from '@/pages/charts/assets/chartTypes/images/根底折线图.png'`

September 17, 2020 · 1 min · jiezi

关于es6:es6装饰器

配置babel 依赖包 "devDependencies": {"@babel/cli": "^7.11.6","@babel/core": "^7.11.6","@babel/preset-env": "^7.11.5","@babel/plugin-proposal-decorators": "^7.10.5","@babel/plugin-proposal-class-properties": "^7.10.4"}babel.config // .babelrc{"presets":["@babel/preset-env"],"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }],["@babel/plugin-proposal-class-properties", { "loose" : true }]]}编译文件 "scripts": {"start": "npx babel app.js -o index.js -w"}类装璜器新增办法@flagclass Animal {constructor(name) {this.name = name;}sayHi() {console.log(this.getName()+" say:'hi'")}} function flag(constructor) {constructor.prototype.getName = function(){return this.name}} let monkey = new Animal("monkey");monkey.sayHi(); 传参@flag({specie:"mammal"})class Animal {constructor(name) {this.name = name;}sayHi() {console.log(this.getName()+" say:'hi'")}} function flag(params) {console.log(params);return (constructor)=>{constructor.prototype.getName = function(){return this.name}}}办法装璜器@flagclass Animal {constructor(name) {this.name = name;}@beforesayHi() {console.log(this.getName()+" say:'hi'")}} function flag(constructor) {constructor.prototype.getName = function () {return this.name}} function before(target,property,descripot){let oldMthod = descripot.value;descripot.value = function(){console.log("before exect");oldMthod.call(this, ...arguments);}} let monkey = new Animal("monkey");monkey.sayHi();

September 13, 2020 · 1 min · jiezi

关于es6:ES6-Module-自定义元素-初体验

可能是最全最新的 “初体验”。 欸,一位敌人和我说,作者啊,你写这么多,指不定也没人看,一点意思都没有,还不如省下这点工夫坐下来 喝 杯 奶 茶 ,对吧。我气不过啊,收回来,就想看看有多少人,看了这篇文章,完事了还能给我点个 ???? ,气一气我这炫富的敌人。新一代 ECMAScript 和 Web Components 规范曾经倒退得十分全面,古代浏览器反对也非常宽泛。纯原生代码也能够写出 Vue 单文件组件的相似成果。 <game-character data-name="El Primo" data-image="//example.dev/el-primo.png"></game-character> import GameCharacter from '//example.dev/xxx.js'; GameCharacter.register('game-character'); Module + Components Example - CodePen (肯定要点开哦!) 元素,是组件的身躯HTML 虽是构建网页的根底技术,但不可否认地,其原生标签数和可扩展性相当无限。开发者总总不足一种主动将 JS 与 HTML 相关联的形式。 这所有继续到自定义元素的呈现。自定义元素(MDN)是 HTML 现代化过程中的里程碑,它将指定 HTML 元素与 ES Class 相绑定,加强了 Web 开发构造与性能的分割,是古代仿生学思维(人们钻研生物体的构造与性能工作的原理,发明先进技术) 在前端畛域的重要冲破,使得易于复用的 HTML 元素的创立和扩大分外简略。总总认同,通过原生自定义元素创立组件简略间接,合乎直觉,代码量小。 标准的命名为了区别原生元素、帮忙浏览器解析,HTML 标准明确而具体地制订了自定义元素的名称应遵循的规定: 自定义元素的名称必须蕴含连字符(-)。以字母结尾。不蕴含大写字母。不能是以下中的一个: <annotation-xml><color-profile> - <font-face> - <font-face-src> - <font-face-uri> - <font-face-format> - <font-face-name> - <missing-glyph>标准以 <math-> 和 <emotion-????> 为例,只有满足上述要求,名称都能够应用。 ...

September 13, 2020 · 10 min · jiezi

关于es6:es6笔记

let和const应用 var 带来的问题var 净化全局变量var a=1;console.log(window.a)var 会使变量晋升console.log(a) // undefinedvar a=1;var 能够被反复申明var a=1;var a=2;var a=3;var 作用域问题全局作用域 { var a=1;}console.log(a) // 1{ let b=2;}console.log(b) // b is not defined函数作用域 for(var i=0;i<3;i++){ setTimeout(()=>console.log(i),0) // 3,3,3}for(let i=0;i<3;i++){ setTimeout(()=>console.log(i),0) // 0,1,2}const 常量const 指向地址不变 开展运算符合并对象或数组 合并数组let a=[0,1];let b=[2,3];console.log([...a,...b]) //[0, 1, 2, 3]合并对象合并对象要辨别是深拷贝还是浅拷贝,开展运算符只拷贝对象一层,属于浅拷贝 let team={name:"Lakers",location:{city:"Los Angeles"}};let player=["LeBron","Davis"];let kuzma = {age:25};let coach = {name:"Frank Vogel",age:47};let Lakers = { ...team, ...coach, player:[...player,kuzma]}team.name="change"; // Lakers 批改失败,浅拷贝team.location.city = "change"; // Lakers 批改胜利,援用地址未变console.log(Lakers)实现深拷贝1、持续开展 ...

September 11, 2020 · 3 min · jiezi

关于es6:async函数返回值

methods: { start () { console.log(this.test()) // Promise {<fulfilled>: 123} }, async test () { return 123 // return Promise.resolve(123) // return new Promise((res, rej) => { // res(123) // }) }}如果间接执行this.test()(不论间接return 123还是return Promise.resolve(123)),都将返回Promise对象(会被包装为一个立刻resolve的Promise对象); 拿到return值的形式:1.Promise.then start () { this.test().then(res => { console.log(res) // 123 })}2.async-await async start () { console.log(await this.test()) // 123}

September 2, 2020 · 1 min · jiezi

关于es6:使用ES6的fetch-API读取数据时要注意的一个和cookie相关的坑

When I am doing a test of comparison between Stateful and Stateless BSP application ( mentioned in blog Stateless and Stateful – Different behavior in application side ), I meet with a strange issue. The conclusion is stateful BSP application will handle request sequentially. Suppose in client I send two request A and B to server. Request A takes 3 seconds to finish and B 2 seconds. ...

August 26, 2020 · 2 min · jiezi

关于es6:使用ES6的fetch-API读取数据时要注意的一个和cookie相关的坑

When I am doing a test of comparison between Stateful and Stateless BSP application ( mentioned in blog Stateless and Stateful – Different behavior in application side ), I meet with a strange issue. The conclusion is stateful BSP application will handle request sequentially. Suppose in client I send two request A and B to server. Request A takes 3 seconds to finish and B 2 seconds. ...

August 24, 2020 · 2 min · jiezi

关于es6:svgjs-拆分多个图形

当初有一个svg,数据是这样的 path d="M0,0 1,1 ...z M1,1 2,2 ...z"这面有多个开始和完结,我想再这个图形的边上任意点击4个点,做宰割图形,这样就会生成3个图形,请问怎么实现,怎么做,请高人指导,在线等。。。

August 4, 2020 · 1 min · jiezi

关于es6:数据去重

function dedupe(array) { return Array.from(new Set(array));}

August 4, 2020 · 1 min · jiezi

关于es6:你不知道的Symbol内置值的规范解读

首先先相熟一下Symbol类型的定义及其作用: 能够用作对象属性键的非字符串值的汇合。每个Symbol值都是惟一且不可变的。每个Symbol值都与一个[[Description]]的值关联,该值要么是undefined,要么是一个字符串。内置的Symbol值次要是用于ECMAScript标准算法扩大的。本文次要是通过对标准的解读来理解Symbol内置的值是如何应用及其标准定义的。 咱们先浏览一下标准里的Symbol内置的值: 标准名称Description值及其作用@@asyncIterator"Symbol.asyncIterator"一个返回异步迭代器的办法,次要用于for await@@hasInstance"Symbol.hasInstance"用于确认对象是否为该构造函数实例的办法,次要用于instanceof@@isConcatSpreadable"Symbol.isConcatSpreadable"一个Boolean值,标识是否能够通过Array.prototype.concat进行扁平化解决@@iterator"Symbol.iterator"一个返回异步迭代器的办法,次要用于for of@@match"Symbol.match"用于String.prototype.match调用@@replace"Symbol.replace"用于String.prototype.replace调用@@search"Symbol.search"用于String.prototype.search调用@@species"Symbol.species"一个用来返回创立派生对象的构造函数的办法@@split"Symbol.split"用于String.prototype.split调用@@toPrimitive"Symbol.toPrimitive"用于ToPrimitive形象办法@@toStringTag"Symbol.toStringTag"用于形容一个对象的字符串,次要用于Object.prototype.toString调用@@unscopables"Symbol.unscopables"用于with环境绑定中排除的属性名称下面有些形容比拟形象,不要急,咱们将一一来认真理解其标准定义和作用 Symbol.hasInstance(@@hasInstance)作用和下面形容的一样,用于确认对象是否为该构造函数实例的办法,次要用于instanceof,当调用instanceof时,外部办法会调用对象上的Symbol.hasInstance办法。 咱们来看一个例子 class MyArray { static [Symbol.hasInstance](val){ return val instanceof Array; }}[1,2,3] instanceof MyArray; // true标准解读在执行instanceof (V instanceof target) 操作时,Es6标准规定以下步骤: 判断target是否为对象,如果不是抛出TypeError exception.let instOfHandler = GetMethod(target, @@hasInstance). // GetMethod为外部的形象办法,获取对象的指定办法如果instOfHandler不等于undefined,返回调用target的@@hasInstance办法,并将后果返回Boolean值,算法完结。<font color="red">留神:这里会将后果值进行隐式转换</font> 判断对象是否IsCallable(能够看着是否是Function的实例), 如果不是抛出TypeError exception.这里进入Es5中对instanceof的标准,Es6中称之为OrdinaryHasInstance。紧接着咱们看一下OrdinaryHasInstance是怎么规定的: 判断target是否IsCallable,如果是下面算法进来的,必定是能够Callable的。判断是否有[[BoundTargetFunction]]外部属性,如果有, let BC = target.[[BoundTargetFunction]],返回 V instanceof BC, 算法完结。 <font color="red">留神: 这里的[[BoundTargetFunction]]其实是调用bind办法之前的原始办法</font> 看上面的例子阐明: function F1(){}const F2 = F1.bind({});const obj = new F2();obj instanceof F1 // true判断V是否为Object,如果不是 返回false。let P = target.prototype;判断P是否为Object,如果不是抛出TypeError exception;循环判断let V = V.__proto__;if (V === null) { return false;}if(P === V){ return true;}默认值Function.prototype[@@hasInstance] = function(V) { return OrdinaryHasInstance(this, V);}咱们能够看到在es6标准中,先尝试获取对象上的@@hasInstance办法,如果有,先调用对象上的@@hasInstance办法并返回。 ...

August 4, 2020 · 6 min · jiezi

关于es6:Symbol

SymbolSymbol的特点 Symbol 是一种根底的数据类型。也就是说:应用typeof失去的是symbol类型。每个Symbol都是惟一的,所以当比拟两个Symbol的时候,会失去falseSymbol值能够作为对象属性的标识符,这是Symbol存在的意义。// 'sym'是形容,跟值没有关系const sym = Symbol('sym') console.log(typeof sym) // symbolconst a = Symbol()const b = Symbol()console.log(a===b) // false console.log(a==b) // false const obj = { [Symbol()]: '姓名', age: 18}Symbol能做什么? Symbol定义一些 不心愿他人拜访的属性。 下面曾经说了Symbol能够作为对象属性的标识符,然而为什么要用呢?咱们先看一个简略的例子。 [Symbol()]: '姓名', age: 18 } Object.keys(obj) // [ 'age' ] for(let key in obj) { console.log(key) // age } ``` - 通过代码咱们能够看到,通过Symbol定义的属性,是无奈通过for in or Object.keys 查找的,这样咱们就能够用Symbol定义一些 不心愿他人拜访的属性。同时咱们能够通过以下办法进行查问 ```js const obj = { [Symbol(1)]: '姓名1', [Symbol(2)]: '姓名2', age: 18 } console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol(1), Symbol(2) ] console.log(Reflect.ownKeys(obj)); // [ 'age', Symbol(1), Symbol(2) ] ```2. 应用Symbol 定义公有的属性和办法 ```js // 2.js const PASSWORD = Symbol() class Login { constructor(username, password) { this.username = username this[PASSWORD] = password } checkPassword(pwd) { return this[PASSWORD] === pwd } } module.exports = Login // 1.js const Login = require('./2.js') const PASSWORD = Symbol() const login = new Login('admin', '123456') console.log(login.checkPassword('123456')) // true console.log(login.username) // admin console.log(login['PASSWORD']) // undefined console.log(login[PASSWORD]) // undefined ``` - 下面代码分两个模块,通过commonjs引入,利用Symbol的唯一性,实现公有属性。checkPassword曾经检测以后的PASSWORD是123456,然而因为Symbol的唯一性,1.js模块无奈生成雷同的Symbol,所以拜访不到这个属性。

July 27, 2020 · 1 min · jiezi

关于es6:Symbol

SymbolSymbol的特点 Symbol 是一种根底的数据类型。也就是说:应用typeof失去的是symbol类型。每个Symbol都是惟一的,所以当比拟两个Symbol的时候,会失去falseSymbol值能够作为对象属性的标识符,这是Symbol存在的意义。// 'sym'是形容,跟值没有关系const sym = Symbol('sym') console.log(typeof sym) // symbolconst a = Symbol()const b = Symbol()console.log(a===b) // false console.log(a==b) // false const obj = { [Symbol()]: '姓名', age: 18}Symbol能做什么? Symbol定义一些 不心愿他人拜访的属性。 下面曾经说了Symbol能够作为对象属性的标识符,然而为什么要用呢?咱们先看一个简略的例子。 [Symbol()]: '姓名', age: 18 } Object.keys(obj) // [ 'age' ] for(let key in obj) { console.log(key) // age } ``` - 通过代码咱们能够看到,通过Symbol定义的属性,是无奈通过for in or Object.keys 查找的,这样咱们就能够用Symbol定义一些 不心愿他人拜访的属性。同时咱们能够通过以下办法进行查问 ```js const obj = { [Symbol(1)]: '姓名1', [Symbol(2)]: '姓名2', age: 18 } console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol(1), Symbol(2) ] console.log(Reflect.ownKeys(obj)); // [ 'age', Symbol(1), Symbol(2) ] ```2. 应用Symbol 定义公有的属性和办法 ```js // 2.js const PASSWORD = Symbol() class Login { constructor(username, password) { this.username = username this[PASSWORD] = password } checkPassword(pwd) { return this[PASSWORD] === pwd } } module.exports = Login // 1.js const Login = require('./2.js') const PASSWORD = Symbol() const login = new Login('admin', '123456') console.log(login.checkPassword('123456')) // true console.log(login.username) // admin console.log(login['PASSWORD']) // undefined console.log(login[PASSWORD]) // undefined ``` - 下面代码分两个模块,通过commonjs引入,利用Symbol的唯一性,实现公有属性。checkPassword曾经检测以后的PASSWORD是123456,然而因为Symbol的唯一性,1.js模块无奈生成雷同的Symbol,所以拜访不到这个属性。

July 27, 2020 · 1 min · jiezi

关于es6:ES6字符串拓展的方法

2019.05.27 10:14 一、子串的辨认ES6 之前判断字符串是否蕴含子串,用 indexOf 办法,ES6 新增了子串的识别方法。1、includes():返回布尔值,判断是否找到参数字符串。2、startsWith():返回布尔值,判断参数字符串是否在原字符串的头部。3、endsWith():返回布尔值,判断参数字符串是否在原字符串的尾部。以上三个办法都能够承受两个参数,须要搜寻的字符串,和可选的搜寻起始地位索引。 留神:这三个办法只返回布尔值,如果须要晓得子串的地位,还是得用 indexOf 和 lastIndexOf 。这三个办法如果传入了正则表达式而不是字符串,会抛出谬误。而 indexOf 和 lastIndexOf 这两个办法,它们会将正则表达式转换为字符串并搜寻它。例: let string = "apple,banana,orange";string.includes("banana"); // truestring.startsWith("apple"); // truestring.endsWith("apple"); // falsestring.startsWith("banana",6) // true二、字符串反复repeat() 将字符串反复指定次数后返回新的字符串。 //将字符串反复指定次数后返回新的字符串console.log("Hello,".repeat(2)); // "Hello,Hello,"//如果参数是 0 至 -1 之间的小数,会进行取整运算,0 至 -1 之间的小数取整失去 -0 ,等同于 repeat 零次console.log("Hello,".repeat(3.2)); // "Hello,Hello,Hello,"//如果参数是 0 至 -1 之间的小数,会进行取整运算,0 至 -1 之间的小数取整失去 -0 ,等同于 repeat 零次console.log("Hello,".repeat(-0.5)); // ""//如果参数是 NaN,等同于 repeat 零次console.log("Hello,".repeat(NaN)); // ""//如果参数是正数或者 Infinity ,会报错:console.log("Hello,".repeat(-1)); // RangeError: Invalid count valueconsole.log("Hello,".repeat(Infinity)); // RangeError: Invalid count value//如果传入的参数是字符串,则会先将字符串转化为数字console.log("Hello,".repeat("hh")); // ""console.log("Hello,".repeat("2")); // "Hello,Hello,"三、字符串补全1、padStart():返回新的字符串,示意用参数字符串从头部补全原字符串。2、padEnd() :返回新的字符串,示意用参数字符串从尾部补全原字符串。以上两个办法承受两个参数,第一个参数是指定生成的字符串的最小长度,第二个参数是用来补全的字符串。如果没有指定第二个参数,默认用空格填充。 ...

July 27, 2020 · 2 min · jiezi

关于es6:ES6-let-与-const

2019/05/14 14:31 ES2015(ES6) 新减少了两个重要的 JavaScript 关键字: let 和 const。 let 申明的变量只在 let 命令所在的代码块内无效。const 申明一个只读的常量,一旦申明,常量的值就不能扭转。let代码块内无效。let 是在代码块内无效,var 是在全局范畴内无效。 { let a = 0; var b = 1;}a // ReferenceError: a is not definedb // 1for循环计数器适宜用let: for (var i = 0; i < 10; i++) { setTimeout(function(){ console.log(i); })}// 输入十个 10for (let j = 0; j < 10; j++) { setTimeout(function(){ console.log(j); })}// 输入 0123456789变量 i 是用 var 申明的,在全局范畴内无效,所以全局中只有一个变量 i, 每次循环时,setTimeout 定时器外面的 i 指的是全局变量 i ,而循环里的十个 setTimeout 是在循环完结后才执行,所以此时的 i 都是 10。 变量 j 是用 let 申明的,以后的 i 只在本轮循环中无效,每次循环的 j 其实都是一个新的变量,所以 setTimeout 定时器外面的 j 其实是不同的变量,即最初输入12345。(若每次循环的变量 j 都是从新申明的,如何晓得前一个循环的值?这是因为 JavaScript 引擎外部会记住前一个循环的值)。 ...

July 27, 2020 · 1 min · jiezi

关于es6:ES6

明天有工夫又看了一下es6的语法,略微做了一点总结,便于日后查阅:let / const 申明变量,一下所讲的所有的特点都是相较于var来说的 var: 1:变量晋升: var/function 申明的变量会被晋升到它的调用之前 console.log(aa); //undefined var aa; ==等价于== var aa; console.log(aa); //undefined aa = 12; console.log(aa); //12 2: 全局作用域 / 函数作用域 函数外部能够拜访全局作用域的变量,大那是全局作用域只能够拜访全局变量,let 特点: 1 . 不存在变量的晋升 console.log(bb); //报错 let bb;2 . 暂时性死区 在一个块级作用域内申明的变量就会绑定在这个区域内了,在let没有申明变量之前这个变量都是不可用的 1) : console.log(aa); // 报错 let aa; 2) : function fn(aa){ let aa; } fn();// 报错,aa曾经申明过了,这也阐明了函数的参数实是在这个函数外部申明一个变量 3) : function bar(x = y, y = 2) { return [x, y]; } bar(); // 报错 在赋值x = y 的时候,y 还没有被申明. //function bar(x = 2, y = x) { // return [x, y]; //} 这样是可行的 3 . 不容许反复申明;在同一个块作用域( "{ }" )内不能够反复申明同一个变量 1) : let aa = 1; let aa; console.log(aa); //报错, aa曾经申明 2) : function fn(bb){ let bb; } fn();//报错 ,bb 曾经申明 4 . 块级作用域 会计作用域外部能够拜访蕴含它的组用域内的变量,然而却不能拜访蕴含于它的块级作用域的变量 let tmp = "hello"; //console.log(aa); //找不到aa //console.log(bb); //找不到bb function f() { console.log(tmp); //hello //console.log(bb); //找不到bb let aa = 123; if (true) { let bb = 567; console.log(tmp); //hello console.log(aa); //123 } } f();const 特点:根本以let是统一的,只有一点const申明的变量是只读的,一但申明就必须初始化(赋值),边切前面也不能够在从新赋值 ...

July 24, 2020 · 1 min · jiezi

关于es6:ES6

明天有工夫又看了一下es6的语法,略微做了一点总结,便于日后查阅:let / const 申明变量,一下所讲的所有的特点都是相较于var来说的 var: 1:变量晋升: var/function 申明的变量会被晋升到它的调用之前 console.log(aa); //undefined var aa; ==等价于== var aa; console.log(aa); //undefined aa = 12; console.log(aa); //12 2: 全局作用域 / 函数作用域 函数外部能够拜访全局作用域的变量,大那是全局作用域只能够拜访全局变量,let 特点: 1 . 不存在变量的晋升 console.log(bb); //报错 let bb;2 . 暂时性死区 在一个块级作用域内申明的变量就会绑定在这个区域内了,在let没有申明变量之前这个变量都是不可用的 1) : console.log(aa); // 报错 let aa; 2) : function fn(aa){ let aa; } fn();// 报错,aa曾经申明过了,这也阐明了函数的参数实是在这个函数外部申明一个变量 3) : function bar(x = y, y = 2) { return [x, y]; } bar(); // 报错 在赋值x = y 的时候,y 还没有被申明. //function bar(x = 2, y = x) { // return [x, y]; //} 这样是可行的 3 . 不容许反复申明;在同一个块作用域( "{ }" )内不能够反复申明同一个变量 1) : let aa = 1; let aa; console.log(aa); //报错, aa曾经申明 2) : function fn(bb){ let bb; } fn();//报错 ,bb 曾经申明 4 . 块级作用域 会计作用域外部能够拜访蕴含它的组用域内的变量,然而却不能拜访蕴含于它的块级作用域的变量 let tmp = "hello"; //console.log(aa); //找不到aa //console.log(bb); //找不到bb function f() { console.log(tmp); //hello //console.log(bb); //找不到bb let aa = 123; if (true) { let bb = 567; console.log(tmp); //hello console.log(aa); //123 } } f();const 特点:根本以let是统一的,只有一点const申明的变量是只读的,一但申明就必须初始化(赋值),边切前面也不能够在从新赋值 ...

July 24, 2020 · 1 min · jiezi

关于es6:ES6的功能varletconst关键字辨析

var、let、const关键字辨析var 能够反复定义同名变量var name='Bob';var name='Tom';console.log(name) //Tom 存在变量晋升//javascript 能够将变量晋升 a = 2console.log(a); //2 var a//然而初始化的变量是不能晋升的console.log(b); //undefinedvar b=3;没有块级作用域let arr=[];for(var i=0;i<2;i++){ arr[i]=function(){ console.log(i) }}arr[0](); //2arr[1](); //2//var 没有块级作用域,i是全局变量 又因为function不是立刻调用函数,循环会很快走到止境let 具备块级作用域let arr=[];for(let i=0;i<2;i++){ arr[i]=function(){ console.log(i) }}arr[0](); //0arr[1](); //1// 如果是var 后果就是2,2 因为var没有块级作用域,i是全局变量 又因为function不是立刻调用函数,循环会很快走到止境存在暂时性死区let b=10;function fn(){ console.log(b); let b=20}fn(); //会报错 Cannot access 'b' before initialization不存在变量晋升x=3;console.log(x); //会报错 Cannot access 'b' before initializationlet x;不能反复定义同名变量let name='Bob';let name='Tom';console.log(name) // 会报错 Identifier 'name' has already been declaredconst 具备块级作用域if(true){ const num=10;}console.log(num) //会报错 num is undefined申明的变量是只读并且须要赋值const PI console.log(PI) //会报错 Missing initializer in const declarationconst P=3.1415;p=3;console.log(p)//会报错 Assignment to constant variable.如果申明的是援用类型(简单类型数据)内容能够批改然而地址不能够批改const obj = { name: 'xm', age: 23 } obj.age = 24;console.log(obj); // 能够操作obj = {}; //欲批改地址,会报错console.log(obj);

July 23, 2020 · 1 min · jiezi

关于es6:Promise的一些理解Promiseall实现

1、Promise根本介绍及用法咱就不唠了,详见 传送门1唠一唠Promise的特点 两个特点 Promise对象的状态不受外界影响 > Promise对象代表一个异步操作,共三个阶段,pending(进行中)、fulfilled(已胜利)、rejected(已失败)。也就是只有异步操作的后果才能够决定以后是哪一种状态,其余操作都无奈扭转状态,所以才叫Promise(承诺)。状态一旦扭转,就不会再变,任何时候都能够失去这个后果那么看例子: let p2 = new Promise((resolve, reject) => { throw new Error('报错了');}).then(result => result).catch(e => e);// logundefined后果是undefined,此处尽管进行了throw err,然而没有在catch进行具体的操作,而只是e=>e,还是返回一个Promise实例。 再看: let p2 = new Promise((resolve, reject) => { throw new Error('报错了'); }) .then(result => result) .catch(e => e) .then(() => {console.log('111')}) .catch(() => {console.log('222')}) .then(() => {console.log('333')}) .catch(() => {console.log('444')}); // log 111 333也就是catch没有调用Promise.reject()扭转状态的话,Promise会始终默认走.then而不会走.catch。这也是Promise中的重头戏,咱们在用Promise的时候可能会发现,当then函数中return了一个值,咱们能够持续then上来,不过是什么值,都能在下一个then中获取,还有,当咱们不在then中放入参数,例:promise.then().then(),那么其前面的then仍旧能够失去之前then返回的值。 为什么呢,传送门2首先咱们要留神的一点是,then有返回值,then了之后还能在then,那就阐明之前的then返回的必然是个Promise。置信看完 传送门2 就不须要我多比比了,记得如果没扭转状态会始终默认走 then 而不会走 catch 就行了看例子: let p2 = new Promise((resolve, reject) => { throw new Error('报错了');}).then(result => result) .catch(e => {console.log(e);return Promise.reject('2')}) .then(() => {console.log('111')}) .catch(() => {console.log('222')}) .then(() => {console.log('333')}) .catch(() => {console.log('444')}); //log Error: 报错了 at <anonymous>:2:9 at new Promise (<anonymous>) at <anonymous>:1:10 222 333后果来看,可知进行Promise.reject()后,Promise实例状态从pending变为rejected了,所以才会走catch,然而走了catch之后还是能够持续.then,但此时Promise实例的状态曾经定格为rejected了,无奈再扭转了。先这样吧,后续补充,欢送斧正 ...

July 22, 2020 · 2 min · jiezi

ES6-module语法

这是读书笔记1、概述历史上,JavaScript始终没有模块(module)体系,无奈将一个大程序拆分成相互依赖的小文件,再用简略的办法拼装起来。ES6在语言规范的层面上,实现了模块性能,而且实现得相当简略,齐全能够取代CommonJS和AMD标准,成为浏览器和服务器通用的模块解决方案。ES6模块的设计思维是尽量的动态化,使得编译时就能确定模块的依赖关系,以及输出和输入的变量。CommonJS和AMD模块,都只能在运行时确定这些货色,比方,CommonJS模块就是对象,输出时必须查找对象属性。 // CommonJS模块let { start, exits } = require('fs');// 等同于let _fs = require('fs');let start = _fs.start;let exits = _fs.exits;下面代码的本质是整体加载fs模块(即加载fs的所有办法),生成一个对象(_fs),而后再从这个对象下面读取办法。这种加载称为“运行时加载”,因为只有在运行时能力失去这个对象,导致齐全没方法在编译时做“动态优化”。ES6模块不是对象,而是通过export命令显式指定输入的代码,再通过import命令输出。 // ES6模块import { start, exists } from 'fs';下面代码的本质是从fs模块加载两个办法,其余办法不加载。这种加载称为“编译时加载”或者动态加载,即ES6能够在编译时就实现模块加载,效率要比CommonJS模块的加载形式高。当然,这也导致了没法援用ES6模块自身,因为它不是对象。 2、严格模式ES6的模块主动采纳严格模式,不论你有没有在模块头部加上“use strict”。须要留神this的限度(禁止this指向全局对象)。ES6模块之中,顶层的this指向undefined,即不应该在顶层代码应用this。 3、export命令模块性能次要由两个命令形成:export和import。export命令用于规定模块的对外接口,import命令用于输出其余模块提供的性能。一个模块就是一个独立的文件。该文件外部的所有变量,内部无奈获取。如果你心愿内部可能读取模块外部的某个变量,就必须应用export关键字输入该变量。 // profile.jsexport var firstName = 'Michael';export var lastName = 'Jackson';下面代码是profile.js文件,保留了用户信息。ES6将其视为一个模块,外面用export命令对外部输入了三个变量。export的写法,还有另外一种。 // profile.jsvar firstName = 'Michael';var lastName = 'Jackson';export { firstName, lastName };须要特地留神的是,export命令规定的是对外的接口,必须与模块外部的变量建设一一对应关系。 // 报错export 1;// 报错var m = 1;export m;下面这两种写法都会报错,因为没有提供对外的接口。第一种写法间接输入1,第二种写法通过变量,,还是间接输入1。1只是一个值,不是接口。 // 写法一export var m = 1;// 写法二var m = 1;export {m};// 写法三var n = 1;export { n as m };下面三种写法都是正确的,规定了对外的接口m。其余脚本能够通过这个接口,取到值1。它们的本质是,在接口名与模块外部变量之间,建设了一一对应的关系。同样的,function和class的输入,也必须恪守这样的写法。 ...

July 15, 2020 · 2 min · jiezi

什么是模块化

模块化ES6的模块化的基本规则或特点:1:每一个模块只加载一次, 每一个JS只执行一次, 如果下次再去加载同目录下同文件,直接从内存中读取。 一个模块就是一个单例,或者说就是一个对象; 2:每一个模块内声明的变量都是局部变量, 不会污染全局作用域; 3:模块内部的变量或者函数可以通过export导出; 4:一个模块可以导入别的模块一、导入和导出 1.导出导入: 2.只取需要的 3.导出数目太多时(无需一一对应) 4.推荐写法 1.什么是AMD、CMD、CommonJs?AMD(异步模块定义)是RequireJS在推广过程中对模块定义的规范化产出,它是一个概念,而RequireJS实现这个概念。可以通过require引用加载。RequireJS特点是依赖前置,即在定义前面通过数组的形式加载所有的依赖。 CMD(同步模块定义)是SeaJS在推广过程中对模块定义的规范化产出,SeaJS是CMD这个概念的实现。特点是就近依赖,即哪里用到依赖就在哪里引入,即用即返回(同步概念) CommonJs规范通过module.exports定义,前端浏览器并不支持,推荐在后端nodeJs中使用

June 7, 2020 · 1 min · jiezi

Set-使用方法及特性

Set是ES6中新增的类型,和数组类似,唯一不同在于该类型不会有重复的数据,一般常用来对数组去重****以下几个set常用方法 1. 数组去重 :单一数组的去重。let set1 = new Set([1, 2, 2, 3, 4, 3, 5]) console.log('distinct 1:', set1)结果:distinct 1: { 1, 2, 3, 4, 5 } 多数组的合并去重let arr1 = [1, 2, 3, 4] let arr2 = [2, 3, 4, 5, 6] let set2 = new Set([...arr1, ...arr2]) console.log('distinct 2:', set2)结果 :distinct 2: { 1, 2, 3, 4, 5, 6 } 2. 类型转换set给数组去重以后得到的结果不是数组结构 , 需要转换成数组 , 方法如下 : ...

June 7, 2020 · 1 min · jiezi

class基本语法与继承

一丶Class的基本语法1.简介基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已.来个例子对比一下:ES6之前,生成实例对象的传统方法是通过构造函数。 function Point(x, y) { this.x =x; this.y=y;}Point.prototype.toString = function() { return '('+this.x+','+this.y+')';}var p = new Point(1,2)上面的代码用ES6改写: class Point { constructor(x,y){ this.x = x; this.y = y; } toString(){ return '('+this.x+','+this.y+')'; }}ES6的类,完全可看作构造函数的另一种写法(在类的实例上面调用方法,其实就是调用原型上的方法),这两句话用代码说明: ##demo1class liumz(){}typeof liumz //"function"liumz === liumz.prototype.constructor //true##demo2class B {}let b = new B();b.constructor === B.prototype.constructor // true构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。class Point { constructor() { // ... } toString() { // ... } toValue() { // ... }}// 等同于Point.prototype = { constructor() {}, toString() {}, toValue() {},};由于类的方法都定义在prototype对象上,所以类的新方法可以添加在protype对象上面: ...

June 5, 2020 · 2 min · jiezi

cass的基本语法

生成实例对象的传统方法是通过构造函数,下面是一个案例:function Point(x, y) { this.x = x this.y = y}Point.prototype.toString = function() { return '(' + this.x + ', ' + this.y + ')'}var p = new Point(1, 2)弊端:和传统的面向对象语言写法差异很大,容易让刚入门的程序员产生困惑。ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。实例一:class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; }}好处:可以让对象原型的写法变得更清晰更像面向对象编程的语法私有属性es6不支持私有属性;在属性名之前,使用#,为class加了私有属性 this 的指向,类的方法内部如果含有this,它默认指向类的实例。实例一: class Logger { printName(name = 'there') { this.print(`Hello ${name}`); } print(text) { console.log(text); }}const logger = new Logger();const { printName } = logger;printName(); // TypeError: Cannot read property 'print' of undefined单独使用有可能报错 ...

June 4, 2020 · 1 min · jiezi

cass基本语法与继承

变量 语法:$变量名:值 注意: $也是变量名的一部分!注释数组变量:(),(),(),… 例:$arr:(1,值1,值2),(2,值3,值4); 条件语句if条件@if 变量==值 { 样式}if-else条件@if 变量==值 { 样式}@else{样式}if-else if-else条件@if 变量==值 { 样式}@else if 变量==值{样式}@else{样式} 循环语句for-to循环@for 变量 from 数字 to 数字{ 样式 }包含第一个数字,不包含第二个数字在选择器里使用变量时候 格式为: #{变量}在样式中使用直接使用变量即可 for-through循环@for 变量 from 数字 through 数字{ 样式 }包含第一个数字,也包含第二个数字 each循环 选择器的嵌套后代选择器嵌套语法: 父级 { 后代 {} } 子代选择器嵌套语法: 父级 { > 子代 {} } 连字符选择器嵌套伪类选择器和伪元素选择器嵌套当你需要的伪类和伪元素和选择器连接再一起的时候使用 & 连接符操作语法: 选择器 { &:hover {} } 群组选择器的嵌套语法: 群组选择器 { 子级 {} }语法: 选择器 { 群组选择器 {} }语法: 群组选择器 { 群组选择器 {} } ...

June 4, 2020 · 1 min · jiezi

JavaScript-新旧替换五函数嵌套

引子看了 Redux 的 applyMiddleware 方法的实现,里面函数嵌套的写法都用了新语法,就想关注一下函数嵌套一类新旧的不同。 上一篇 JavaScript 新旧替换四:继承。 OriginMy GitHubES5 方式普通嵌套 function find(value) { return { in: function(arr) { return { combine: function(obj) { var result = arr.indexOf(value); obj.index = result; return obj; } }; } }; } var data = find(6).in([1,2,3,4,5,6]).combine({}); console.info(data); // {index: 5}管道机制管道机制(pipeline)是指前一个函数的输出是后一个函数的输入。 const plus = a => a + 1; const minus = a => a - 2; const multi = a => a * 3; const div = a => a / 4; function pipeline() { for (var len = arguments.length, funcs = [], key = 0; key < len; key++) { funcs[key] = arguments[key]; } return function(val) { var result = funcs.reduce(function(a, b) { return b(a); }, val); return result; }; } var cal = pipeline(plus,minus,multi,div); var result = cal(5); console.info(result); // 3ES2015+ 方式普通嵌套 const find = (value) => ( { in: (arr) => ( { combine: (obj) => { const result = arr.indexOf(value); obj.index = result; return obj; } } ) } ); const data = find2(6).in([1,2,3,4,5,6]).combine({}); console.info(data); // {index: 5}管道机制 const plus = a => a + 1; const minus = a => a - 2; const multi = a => a * 3; const div = a => a / 4; const pipeline = (...funcs) => val => funcs.reduce(function(a,b) { return b(a); }, val); const cal = pipeline(plus,minus,multi,div); const result = cal(5); console.info(result); // 3参考资料ReduxECMAScript StandardMDN Arrow_functionsECMAScript 6 functionBabel Online

June 3, 2020 · 2 min · jiezi

ES6中Objectassign

Object.assign() 语法:Object.assing(target,…sources) 一、合并对象 const first = { name: "Bob" };const last = { lastName: "Smith" };let person = Object.assign(first, last);console.log(person);/\*{ name: 'Bob', lastName: 'Smith' }\*/二、克隆对象(浅拷贝!!!) const obj = { person: "Bob Smith"};const clone = Object.assign({}, obj);console.log(obj);/\*{ person: 'Bob Smith' }\*/ 三、"null或undefined源被视为空对象一样对待,不会对目标对象产生任何影响。" const test = null;const test1 = Object.assign({},test);console.log(test1);/\*{}\*/ const test2=undefined;const test4=Object.assign({},test2);console.log(test4);/\*{}\*/ 通过以上可以看出,test1和test4依然空对象

June 2, 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

重学ES6之出来混迟早要还的六

本系列博客为ES6基础语法的使用及总结,如有错误,欢迎指正。重学ES6之出来混迟早要还的(六)主要包括 Generator、Set/Map、Proxy等。 其他笔记:重学ES6之出来混迟早要还的(一)重学ES6之出来混迟早要还的(二)重学ES6之出来混迟早要还的(三)重学ES6之出来混迟早要还的(四)重学ES6之出来混迟早要还的(五) 异步编程Javascript语言的执行环境是"单线程"(single thread)。 所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。 "同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的; "异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。"异步模式"非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。 异步编程的方法通过回调函数优点是简单,容易理解和部署;缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程混乱,而且每个任务只能指定一个回调函数。 通过事件监听任务的执行不取决于代码的顺序,而取决于某个事件是否发生。 通过事件监听,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。 采用发布/订阅模式我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。 这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。 Promise不多赘述,这里有说 GeneratorGenerator 函数是 ES6 提供的一种异步编程解决方案 顾名思义,它是一个生成器,它也是一个状态机,内部拥有值及相关的状态。生成器返回一个迭代器Iterator对象,我们可以通过这个迭代器,手动地遍历相关的值、状态,保证正确的执行顺序。 1.用法Generator 函数不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。 整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用 yield 关键字注明。 yield关键字可以让 Generator内部的逻辑能够切割成多个部分。function* listNum() { let i = 1; yield i; i++; yield i; i++; yield i;}const num = listNum();console.log(listNum()); 通过调用迭代器对象的next方法执行一个部分代码,执行哪个部分就会返回哪个部分定义的状态const num = listNum();console.log(num.next());console.log(num.next());console.log(num.next()); 如上代码,定义了一个listNum的生成器函数,调用之后返回了一个迭代器对象(即num) 调用next方法后,函数内执行第一条yield语句,输出当前的状态done(迭代器是否遍历完成)以及相应值(一般为yield关键字后面的运算结果) 每调用一次next,则执行一次yield语句,并在该处暂停。 2.Generator 函数遍历数组2.1 可以发现,如果不调用next方法,那么函数中封装的代码不会立即被执行(下例中的console.log(arr);没有运行) let arr = [ {name: 'zs',age: 38,gender: 'male'}, {name: 'yw',age: 48,gender: 'male'}, {name: 'lc',age: 28,gender: 'male'},];function* loop(arr) { console.log(arr); for(let item of arr){ yield item; }}let repoGen = loop(arr);console.log(repoGen); ...

November 3, 2019 · 3 min · jiezi

JavaScript之多线程和Event-Loop

引子几乎在每一本JS相关的书籍中,都会说JS是单线程的,JS是通过事件队列(Event Loop)的方式来实现异步回调的。 对很多初学JS的人来说,根本搞不清楚单线程的JS为什么拥有异步的能力,所以,我试图从进程、线程的角度来解释这个问题。 CPU说到CPU和进程、线程,对计算机操作系统有过学习和了解的同学应该比较熟悉。 计算机的核心是CPU,它承担了所有的计算任务。 它就像一座工厂,时刻在运行。 假定工厂的电力有限,一次只能供给一个车间使用。 也就是说,一个车间开工的时候,其他车间都必须停工。 背后的含义就是,单个CPU一次只能运行一个任务。 进程就好比工厂的车间,它代表CPU所能处理的单个任务。 进程之间相互独立,任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。 CPU使用时间片轮转进度算法来实现同时运行多个进程。 CPU、进程、线程之间的关系从上文我们已经简单了解了CPU、进程、线程,简单汇总一下。 进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)不同进程之间也可以通信,不过代价较大单线程与多线程,都是指在一个进程内的单和多浏览器是多进程的我们已经知道了CPU、进程、线程之间的关系,对于计算机来说,每一个应用程序都是一个进程, 而每一个应用程序都会分别有很多的功能模块,这些功能模块实际上是通过子进程来实现的。 对于这种子进程的扩展方式,我们可以称这个应用程序是多进程的。 而对于浏览器来说,浏览器就是多进程的,我在Chrome浏览器中打开了多个tab,然后打开windows控制管理器: 如上图,我们可以看到一个Chrome浏览器启动了好多个进程。总结一下: 浏览器是多进程的每一个Tab页,就是一个独立的进程浏览器包含了哪些进程主进程 协调控制其他子进程(创建、销毁)浏览器界面显示,用户交互,前进、后退、收藏将渲染进程得到的内存中的Bitmap,绘制到用户界面上处理不可见操作,网络请求,文件访问等第三方插件进程 每种类型的插件对应一个进程,仅当使用该插件时才创建GPU进程 用于3D绘制等渲染进程,就是我们说的浏览器内核 负责页面渲染,脚本执行,事件处理等每个tab页一个渲染进程那么浏览器中包含了这么多的进程,那么对于普通的前端操作来说,最重要的是什么呢? 答案是渲染进程,也就是我们常说的浏览器内核 浏览器内核(渲染进程)从前文我们得知,进程和线程是一对多的关系,也就是说一个进程包含了多条线程。 而对于渲染进程来说,它当然也是多线程的了,接下来我们来看一下渲染进程包含哪些线程。 GUI渲染线程 负责渲染页面,布局和绘制页面需要重绘和回流时,该线程就会执行与js引擎线程互斥,防止渲染结果不可预期JS引擎线程 负责处理解析和执行javascript脚本程序只有一个JS引擎线程(单线程)与GUI渲染线程互斥,防止渲染结果不可预期事件触发线程 用来控制事件循环(鼠标点击、setTimeout、ajax等)当事件满足触发条件时,将事件放入到JS引擎所在的执行队列中定时触发器线程 setInterval与setTimeout所在的线程定时任务并不是由JS引擎计时的,是由定时触发线程来计时的计时完毕后,通知事件触发线程异步http请求线程 浏览器有一个单独的线程用于处理AJAX请求当请求完成时,若有回调函数,通知事件触发线程当我们了解了渲染进程包含的这些线程后,我们思考两个问题: 为什么 javascript 是单线程的为什么 GUI 渲染线程为什么与 JS 引擎线程互斥为什么 javascript 是单线程的首先是历史原因,在创建 javascript 这门语言时,多进程多线程的架构并不流行,硬件支持并不好。 其次是因为多线程的复杂性,多线程操作需要加锁,编码的复杂性会增高。 而且,如果同时操作 DOM ,在多线程不加锁的情况下,最终会导致 DOM 渲染的结果不可预期。 为什么 GUI 渲染线程与 JS 引擎线程互斥这是由于 JS 是可以操作 DOM 的,如果同时修改元素属性并同时渲染界面(即 JS线程和UI线程同时运行), 那么渲染线程前后获得的元素就可能不一致了。 因此,为了防止渲染出现不可预期的结果,浏览器设定 GUI渲染线程和JS引擎线程为互斥关系, 当JS引擎线程执行时GUI渲染线程会被挂起,GUI更新则会被保存在一个队列中等待JS引擎线程空闲时立即被执行。 ...

November 2, 2019 · 1 min · jiezi

不只是块级作用域你不知道的let和const

ES6新增了两个重要的关键字let和const,相信大家都不陌生,但是包括我在内,在系统学习ES6之前也只使用到了【不存在变量提升】这个特性。 let声明一个块级作用域的本地变量const语句声明一个块级作用域的本地常量,不可以重新赋值支持块级作用域var定义的变量会提升到整个函数作用域内,let/const则支持块级作用域。 块级作用域: 由{}包裹的作用域(函数那种{}不算)来看一个var的例子: { var a = 1;}console.log(a);此时输出1,因为var没有块级作用域。 来看一个let的例子(const效果一样): { let a = 1;}console.log(a);此时会报错ReferenceError,因为let/const支持块级作用域,所以let定义的a只在{}可以访问 不存在变量提升与var不同的是,let/const声明的变量不存在变量提升,也就是说{}对于let/const是有效的。 来看一个var的例子: console.log(a);var a = 1;此时会输出undefined,因为var声明的变量会提升到作用域顶部(只提升声明,不提升赋值) 来看一个let的例子(const效果也一样): console.log(a);let a = 1;此时会报错ReferenceError,因为let不存在变量提升 同一作用域内不可以重复声明同一作用域内let/const不可以重复声明,var可以。 来看一个var的例子: var a = 1;var a = 2;console.log(a);此时会输出2,var是支持重复声明的,后面声明的值会覆盖前面声明的值。 来看一个let的例子(const效果也一样): let a = 1;let a = 2;console.log(a);此时会报错SyntaxError,因为同一作用域内let/const不可以重复声明。 再来看一个不同作用域的例子: let a = 1;{ let a = 2;}console.log(a);此时输出1,因为两者作用域不同 暂存死区暂存死区TDZ(Temporal Dead Zone)是ES6中对作用域新的语义。 通过let/const定义的变量直到执行他们的初始化代码时才被初始化。在初始化之前访问该变量会导致ReferenceError。该变量处于一个自作用域顶部到初始化代码之间的“暂存死区”中。 来看以下例子: function do_something() { console.log(bar); // undefined console.log(foo); // ReferenceError var bar = 1; let foo = 2;}do_something();var定义的变量声明会提升到作用域顶部,所以bar是undefined,而let定义的变量从作用域开始到let foo=2这中间都无法访问,访问会报错ReferenceError ...

October 22, 2019 · 1 min · jiezi

JavaScript之对象继承

JavaScript对象继承的方法有很多,这里总结一下几种比较常用的方法。现在有一个"动物"对象的构造函数。 function Animal(){ this.species = "动物";}Animal.prototype.voice = function(){ console.log('voice');}还有一个"猫"对象的构造函数。 function Cat(name, color){ this.name = name; this.color = color;}怎样才能使"猫"继承"动物"呢? 一、原型链和构造函数继承使用call/apply和Object.create()第一种方法使用call或apply方法,改变了 this 的指向而实现继承,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行: function Cat(name, color){ Animal.apply(this, arguments); this.name = name; this.color = color;}var cat1 = new Cat("大毛","黄色");alert(cat1.species); // 动物到目前为止一切看起来都还行,但是我们很快会发现我们遇到问题了,当我们调用cat1.voice()的时候报错了,显然Cat并没有继承Animal的原型对象里的方法。 我们已经定义了一个新的构造器,这个构造器默认有一个空的原型属性。我们并没有让Cat从Animal的原型对象里继承方法。 Cat.prototype = Object.create(Animal.prototype);这里我们的老朋友create()又来帮忙了——在这个例子里我们用这个函数来创建一个和Animal.prototype一样的新的原型属性值(这个属性指向一个包括属性和方法的对象),然后将其作为Cat.prototype的属性值。这意味着Cat.prototype现在会继承Animal.prototype的所有属性和方法。 接下来,在我们动工之前,还需要完成一件事 — 现在Cat()的prototype的constructor属性指向的是Aniaml(),这是由我们生成Animal()的方式决定的。(这篇 Stack Overflow post 文章会告诉您详细的原理) Cat.prototype.constructor = Cat;此时再输入Cat.prototype.constructor就会得到Cat()。 顺带一提,这是很重要的一点,编程时务必要遵守。下文都遵循这一点,即如果替换了prototype对象,那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。 o.prototype = {}; o.prototype.constructor = o;对上面构造函数继承代码做一个封装: function extend(C, P) { function C(){ P.apply(this, arguments); } C.prototype = Object.create(P.prototype); C.prototype.constructor = C;}不使用call或apply方法第二种方法更常见,但是不使用apply和call,而是使用prototype属性。 ...

October 17, 2019 · 2 min · jiezi

快速进阶Vue30

在2019.10.5日发布了Vue3.0预览版源码,但是预计最早需要等到 2020 年第一季度才有可能发布 3.0 正式版。 可以直接看 github源码。 新版Vue 3.0计划并已实现的主要架构改进和新功能: 编译器(Compiler) 使用模块化架构优化 "Block tree"更激进的 static tree hoisting 功能 (检测静态语法,进行提升)支持 Source map内置标识符前缀(又名"stripWith")内置整齐打印(pretty-printing)功能移除 Source map 和标识符前缀功能后,使用 Brotli 压缩的浏览器版本精简了大约10KB运行时(Runtime) 速度显著提升同时支持 Composition API 和 Options API,以及 typings基于 Proxy 实现的数据变更检测支持 Fragments (允许组件有从多个根结点)支持 Portals (允许在DOM的其它位置进行渲染)支持 Suspense w/ async setup()目前不支持IE111.剖析Vue Composition API可以去看官方地址 Vue 3 使用ts实现了类型推断,新版api全部采用普通函数,在编写代码时可以享受完整的类型推断(避免使用装饰器)解决了多组件间逻辑重用问题 (解决:高阶组件、mixin、作用域插槽)Composition API 使用简单先尝鲜Vue3.0看看效果 <script src="vue.global.js"></script><div id="container"></div><script> function usePosition(){ // 实时获取鼠标位置 let state = Vue.reactive({x:0,y:0}); function update(e) { state.x= e.pageX state.y = e.pageY } Vue.onMounted(() => { window.addEventListener('mousemove', update) }) Vue.onUnmounted(() => { window.removeEventListener('mousemove', update) }) return Vue.toRefs(state); } const App = { setup(){ // Composition API 使用的入口 const state = Vue.reactive({name:'youxuan'}); // 定义响应数据 const {x,y} = usePosition(); // 使用公共逻辑 Vue.onMounted(()=>{ console.log('当组挂载完成') }); Vue.onUpdated(()=>{ console.log('数据发生更新') }); Vue.onUnmounted(()=>{ console.log('组件将要卸载') }) function changeName(){ state.name = 'webyouxuan'; } return { // 返回上下文,可以在模板中使用 state, changeName, x, y } }, template:`<button @click="changeName">{{state.name}} 鼠标x: {{x}} 鼠标: {{y}}</button>` } Vue.createApp().mount(App,container);</script>到这里你会发现响应式才是Vue的灵魂2.源码目录剖析packages目录中包含着Vue3.0所有功能 ...

October 16, 2019 · 6 min · jiezi

JS-口袋书第-6-章JS-中的闭包与模块

作者:valentinogagliardi译者:前端小智来源:github阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/... 为了保证的可读性,本文采用意译而非直译。 全局变量使用容易引发bug,咱们经常教导尽量不要使用全局变量,尽管全局变量在某些情况下是有用的。 例如,在浏览器中使用JS时,咱们可以访问全局window对象,window中有很多有用的方法,比如: window.alert('Hello world'); // Shows an alertwindow.setTimeout(callback, 3000); // Delay executionwindow.fetch(someUrl); // make XHR requestswindow.open(); // Opens a new tab这些方法也像这样使用: alert('Hello world'); // Shows an alertsetTimeout(callback, 3000); // Delay executionfetch(someUrl); // make XHR requestsopen(); // Opens a new tab这是方便的。Redux是另一个“好”全局变量的例子:整个应用程序的状态存储在一个JS对象中,这个对象可以从整个应用程序(通过Redux)访问。但是当在一个团队如果同时有50个编写代码时,以如何处理这样的代码: var arr = [];function addToArr(element) { arr.push(element); return element + " added!";}咱们同事在另一个文件中创建一个名为arr的新全局数组的几率有多大?我觉得非常高。JS中的全局变量非常糟糕的另一个原因是引擎足够友好,可以为咱们创建全局变量。如果忘了在变量名前加上var,就像这样: name = "Valentino";JS引擎为会创建一个全局变量,更糟糕的是,可以在函数中创建了“非预期”变量: function doStuff() { name = "Valentino";}doStuff();console.log(name); // "Valentino"无辜的功能最终污染了全球环境。 幸运的是,可以用“严格模式”来消除这种行为, 在每个JS文件使用“use strict”足以避免愚蠢的错误: ...

October 16, 2019 · 3 min · jiezi

es6的入门学习1

es6的学习环境Linux nodejs1) vi hello.js2) node hello.js模块化机制(CommonJS) 1) 模块定义 在任意一个js文件或目录都可以为一个模块在模块文件中,都有一个module对象表示当前模块id filename 路径+文件名parent 父模块children 子模块paths 路径exports 模块向外暴露的接口*2)模块引用 require("")参数: 1)路径 require("./module1") 按照指定的路径加载所需的模块 2)模块名称 require("module1") 按照paths中的路径依次寻找所需模块,直到找到为止npm(nade package manager) $ npm init 在当前目录下产生一个package.json,这个文件是当前模块的核心配置文件,记录模块的基本信息,依赖信息,脚本信息 $ npm install xxx --save 本地安装xxx模块,默认将xxx安装到当前目录下的node_modules目录中,如果当前目录中没有node_modules会自动创建,--save表示这个xxxx模块是一个产品依赖,维护在package.json中的dependecies属性$ npm install xxx -g 全局安装xxx模块,默认会将xxx安装到node的安装目录中 /opt/node-v10.14.2/lib/node_modules /opt/node-v10.14.2/bin /opt/node-v10.14.2/share 效果: 全局安装的模块可以在命令行中直接调用,一般用于命令行工具的安装,比如cnpm,babel-cli,vue-cli,create-react-app的安装cnpmnpm淘宝镜像 1) 安装 $ npm install -g cnpm --registry=https://registry.npm.taobao.org报错: EACCES: permission denied, access '/opt/node-v10.14.2/lib/node_modules/cnpm/node_modules/address'原因: 当前用户是普通用户,但是全局安装需要将第三方依赖安装到/opt/xxx,没有权限!解决方案: sudo npm 失败 将 /opt/node-v10.14.2/lib/node_modules /opt/node-v10.14.2/bin /opt/node-v10.14.2/share 的拥有者变为当前用户(larry) $ sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share} $ sudo chown -R xxx /opt/node-v10.14.2/{lib/node_modules,bin,share} 2) 使用 使用方式与cnpm完全一致,只不过原先用npm现在用cnpmbabel ...

October 15, 2019 · 2 min · jiezi

5-个-JS-不良编码习惯你占几个呢

作者:Dmitri Pavlutin 译者:前端小智 来源:dmitripavlutin阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/... 在阅读JavaScript代码时,你是否有过这种感觉 你几乎不明白代码的作用?代码使用了很多 JavaScript 技巧?命名和编码风格太过随意?这些都是不良编码习惯的征兆。 在这篇文章中,我描述了JavaScript中常见的5种不良编码习惯。重要的是,本文会给出一些可行的建议,如何的摆脱摆脱这些习惯。 1.不要使用隐式类型转换JavaScript是一种松散类型的语言。 如果使用得当,这是一个好处,因为它给你带来了灵活性。 大多数运算符+ - * / ==(不包括 ===)在处理不同类型的操作数时会进行隐式转换。 语句if(condition){...},while(condition){...}隐式地将条件转换为布尔值。 下面的示例依赖于类型的隐式转换,这种有时候会让人感到很困惑: console.log("2" + "1"); // => "21"console.log("2" - "1"); // => 1console.log('' == 0); // => trueconsole.log(true == []); // -> falseconsole.log(true == ![]); // -> false过度依赖隐式类型转换是一个坏习惯。 首先,它使你的代码在边缘情况下不太稳定。 其次,增加了引入难以重现和修复的bug的机会。 现在咱们实现一个获取对象属性的函数。如果属性不存在,函数返回一个默认值 function getProp(object, propertyName, defaultValue) { if (!object[propertyName]) { return defaultValue; } return object[propertyName];}const hero = { name: 'Batman', isVillian: false};console.log(getProp(hero, 'name', 'Unknown')); // => 'Batman'getProp() 读取name属性的值,即'Batman'。 ...

October 15, 2019 · 3 min · jiezi

前端面试每日-31-第182天

今天的知识点 (2019.10.15) —— 第182天[html] 举例说明HTML5的标签meter的用法[css] 让你手写一个reset的文件,你应该怎么写?要考虑哪些方面呢?[js] 为什么说js是弱类型语言,它的优缺点分别是什么?[软技能] 你知道什么是ECMAScript吗?《论语》,曾子曰:“吾日三省吾身”(我每天多次反省自己)。 前端面试每日3+1题,以面试题来驱动学习,每天进步一点! 让努力成为一种习惯,让奋斗成为一种享受!相信 坚持 的力量!!!欢迎在 Issues 和朋友们一同讨论学习! 项目地址:前端面试每日3+1 【推荐】欢迎跟 jsliang 一起折腾前端,系统整理前端知识,目前正在折腾 LeetCode,打算打通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢迎大家前来讨论,如果觉得对你的学习有一定的帮助,欢迎点个Star, 同时欢迎微信扫码关注 前端剑解 公众号,并加入 “前端学习每日3+1” 微信群相互交流(点击公众号的菜单:进群交流)。 学习不打烊,充电加油只为遇到更好的自己,365天无节假日,每天早上5点纯手工发布面试题(死磕自己,愉悦大家)。希望大家在这浮夸的前端圈里,保持冷静,坚持每天花20分钟来学习与思考。在这千变万化,类库层出不穷的前端,建议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢迎大家到Issues交流,鼓励PR,感谢Star,大家有啥好的建议可以加我微信一起交流讨论!希望大家每日去学习与思考,这才达到来这里的目的!!!(不要为了谁而来,要为自己而来!)交流讨论欢迎大家前来讨论,如果觉得对你的学习有一定的帮助,欢迎点个[Star] https://github.com/haizlin/fe...

October 15, 2019 · 1 min · jiezi

15万字概括ES6全部特性

注:原文来自小编的掘金博客,可查阅《1.5万字概括ES6全部特性》 前言第三次阅读阮一峰老师的《ES6标准入门》了,以前阅读时不细心,很多地方都是一目十行。最近这次阅读都是逐个逐个字来读,发现很多以前都没有注意到的知识点,为了方便记忆和预览全部ES6特性,所以写下本文。 以下提到的《ES6标准入门》统一使用《ES6》这个名称来代替,而最新的ES6版本也是截止到当前的ES2019本文的知识点完全是参考或摘录《ES6》里的语句,有部分语句为了方便理解和记忆,进行了相同意思的转义,同时对知识点进行归类划分。为了让大家能集中精力来记住这些特性,全文一句废话和题外话都没有,全部模块以笔记的形式进行书写,如果看得不是很惯建议对照《ES6》的内容来学习。 本文整理出来的笔记都是书中的精华内容,囊括了整个ES6体系的所有特性,非常方便大家重新认识全部ES6特性。半小时的阅读就可以对ES6有一个全面的了解,可以认为是一本ES6特性小字典,收藏后可随时查阅。即使看不完也要拉到本文末尾喔,有个大彩蛋,嘻嘻! 修正ES6是ECMA为JavaScript制定的第6个标准版本,相关历史可查看此章节《ES6-ECMAScript6简介》。 标准委员会最终决定,标准在每年6月正式发布并作为当年的正式版本,接下来的时间里就在此版本的基础上进行改动,直到下一年6月草案就自然变成新一年的版本,这样一来就无需以前的版本号,只要用年份标记即可。ECMAscript 2015是在2015年6月发布ES6的第一个版本。以此类推,ECMAscript 2016是ES6的第二个版本、 ECMAscript 2017是ES6的第三个版本。ES6既是一个历史名词也是一个泛指,含义是5.1版本以后的JavaScript下一代标准,目前涵盖了ES2015、ES2016、ES2017、ES2018、ES2019。 所以有些文章上提到的ES7(实质上是ES2016)、ES8(实质上是ES2017)、ES9(实质上是ES2018)、ES10(实质上是ES2019),实质上都是一些不规范的概念。从ES1到ES6,每个标准都是花了好几年甚至十多年才制定下来,你一个ES6到ES7,ES7到ES8,才用了一年,按照这样的定义下去,那不是很快就ES20了。用正确的概念来说ES6目前涵盖了ES2015、ES2016、ES2017、ES2018、ES2019。 另外,ES6更新的内容主要分为以下几点 表达式:声明、解构赋值内置对象:字符串扩展、数值扩展、对象扩展、数组扩展、函数扩展、正则扩展、Symbol、Set、Map、Proxy、Reflect语句与运算:Class、Module、Iterator异步编程:Promise、Generator、AsyncES2015 声明const命令:声明常量let命令:声明变量作用作用域 全局作用域函数作用域:function() {}块级作用域:{}作用范围 var命令在全局代码中执行const命令和let命令只能在代码块中执行赋值使用 const命令声明常量后必须立马赋值let命令声明变量后可立马赋值或使用时赋值声明方法:var、const、let、function、class、import重点难点不允许重复声明未定义就使用会报错:const命令和let命令不存在变量提升暂时性死区:在代码块内使用let命令声明变量之前,该变量都不可用解构赋值字符串解构:const [a, b, c, d, e] = "hello"数值解构:const { toString: s } = 123布尔值解构:const { toString: b } = true对象解构 形式:const { x, y } = { x: 1, y: 2 }默认:const { x, y = 2 } = { x: 1 }改名:const { x, y: z } = { x: 1, y: 2 }数组解构 ...

October 14, 2019 · 5 min · jiezi

JS-口袋书第-5-章JS-对象生命周期的秘密

作者:valentinogagliardi译者:前端小智来源:github阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/...为了保证的可读性,本文采用意译而非直译。 一切皆对象咱们经常听到JS中“一切皆对象”? 有没有问想过这是什么意思? 其它语言也有“一切皆对象”之说,如Python。 但是Python中的对象不仅仅是像JS对象这样的存放值和值的容器。 Python中的对象是一个类。 JS中有类似的东西,但JS中的“对象”只是键和值的容器: var obj = { name: "Tom", age: 34 }实际上,JS中的对象是一种“哑”类型,但很多其他实体似乎都是从对象派生出来的。 甚至是数组,在JS中创建一个数组,如下所示: var arr = [1,2,3,4,5]然后用typeof运算符检查类型,会看到一个令人惊讶的结果: typeof arr"object"看来数组是一种特殊的对象! 即使JS中的函数也是对象。 如果你深入挖掘,还有更多,创建一个函数,该函数就会附加一些方法: var a = function(){ return false; }a.toString()输出: "function(){ return false; }"咱们并没有在函数声明toString方法,所以在底层一定还有东西。它从何而来? Object有一个名为.toString的方法。 似乎咱们的函数具有相同的Object方法。 Object.toString()这时咱们使用浏览器控制台来查看默认被附加的函数和属性,这个谜团就会变得更加复杂: 谁把这些方法放在函数呢。 JS中的函数是一种特殊的对象,这会不会是个暗示? 再看看上面的图片:我们的函数中有一个名为prototype的奇怪命名属性,这又是什么鬼? JS中的prototype是一个对象。 它就像一个背包,附着在大多数JS内置对象上。 例如 Object, Function, Array, Date, Error,都有一个“prototype”: typeof Object.prototype // 'object'typeof Date.prototype // 'object'typeof String.prototype // 'object'typeof Number.prototype // 'object'typeof Array.prototype // 'object'typeof Error.prototype // 'object'注意内置对象有大写字母: ...

October 14, 2019 · 5 min · jiezi

使用-Arrayfill-填充对象的问题

当你想使用 Array.fill( ) 来填充一个全是空白对象的数组时需要特别注意Array(length).fill({ }) 这样填充创建的数组,里面每一项{ }都完全相同let arr = Array(6).fill({});console.log(arr[1] === arr[2]) //true//哪怕是使用 new Object() 来创建每一项,一旦使用fill(), 则每一项也全等let other = Array(6).fill( new Object() )console.log(other[1] === other[2]) //true //即使使用 Object.create({ }), 也是一样的效果let arr_new = Array(6).fill( Object.create({}) )console.log(arr_new[1] === arr_new[2]) //true既然这样行不通,那么我们使用 map 来填充数据吧 Array(6).map(item => return new Object() ) // 返回 (6) [empty × 6]Array(6).map(item => { console.log("走不走?") return new Object()})//发现如果只声明了数组的长度,没有填充任何项的话, map方法直接跳过了, 且forEach方法也是一样直接跳过最终的解决办法: 先给数组的每一项都填充为 null,让这个数组有数据项,而不仅仅只有长度再用 map 替换各个项为 new Object( )let _arr = new Array(6).fill(null).map(item => new Object());怎么感觉怪怪的?????

October 8, 2019 · 1 min · jiezi

结合React的Effect-Hook分析组件副作用的清除

一个订阅好友在线的组件我们在DidMount的时候通过ID订阅了好友的在线状态并且为了防止内存泄漏,我们需要在WillUnmount清除订阅 但是当组件已经显示在屏幕上时,friend prop 发生变化时会发生什么? 我们的组件将继续展示原来的好友状态。这是一个 bug。而且我们还会因为取消订阅时使用错误的好友 ID 导致内存泄露或崩溃的问题。 class FriendStatus extends React.Component { constructor(props) { super(props); this.state = { isOnline: null }; this.handleStatusChange = this.handleStatusChange.bind(this); } componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); } handleStatusChange(status) { this.setState({ isOnline: status.isOnline }); } render() { if (this.state.isOnline === null) { return 'Loading...'; } return this.state.isOnline ? 'Online' : 'Offline'; }}优化订阅好友在线的组件为了解决props更新导致的BUG我们需要在DidUpdate中进行修改订阅 componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentDidUpdate(prevProps) { // 取消订阅之前的 friend.id ChatAPI.unsubscribeFromFriendStatus( prevProps.friend.id, this.handleStatusChange ); // 订阅新的 friend.id ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); }引入Hooks代码会变得十分简单Effect HookuseEffect() 可以让你在函数组件中执行副作用操作默认情况下,它在第一次渲染之后和每次更新之后都会执行。 ...

October 8, 2019 · 2 min · jiezi

重磅从0实现一个axios网络请求框架百分之七十的功能

我们知道,axios是前端一个非常优秀的对于网络请求的框架,其特点主要是请求方便、功能多(如拦截器)。那么作为一枚前端开发人员,了解并能够使用axios其实是基础,深入了解其实现原理才是比较重要的,当然,如果能徒手撸一个axios类似的框架出来,那就是相当的不错了。这篇文章会从以下几个大的点来实现一个axios框架: axios的本质是什么?axios默认值、参数的实现常见请求方式:get、post、delete在axios中的实现真正请求(XMLHttpRequest)的实现axios拦截器的实现打包发布同时希望你了解以下的一些知识点: webpackaxios框架的基本使用Es6的Proxy、Class等XMLHttpRequesthttp协议...等axios的本质是什么使用axios框架的时候,我们大部分情况都是以模块的形式引入进行使用,如: import axios from 'axios'发出一个get请求,如: axios.get('/user')或axios('/user')从中可以看出,axios的本质就是一个函数,那么就先来实现一个axios的雏形。(本篇文章实现利用es6的calss去实现)。 axios.js class Axios{ constructor(){ }}export default new Axios();index.js import axios from './axios'这里毫无疑问可以看出,axios现在只是一个Axios的实例,并不是一个函数,那么要怎样将axios变成一个函数?这就需要两个知识点:Axios的构造函数是可以进行返回值操作、利用ES6的Proxy。更进一步的Axios类的代码如下: class Axios{ constructor(){ return new Proxy(function(){},{ apply(fn,thisArg,agrs){ } }) }}export default new Axios();这样我们得到的一个Axios实例axios就是一个函数了。这里简单提一下,Proxy在进行函数处理的使用,apply是很有用的,使用它我们就可以对一个函数进行代理处理了。 看看打印出来的内容: 接下来,要怎样才能够实现axios('/user')或axios.get('/user')这样的效果呢?,我们知道了axios是一个函数,那么给一个函数增加一个属性(也是函数),就能够解决这个问题了。先来简单看下函数式的写法: 继续完善Axios类中的代码: class Axios{ constructor(){ const _this = this; return new Proxy(function(){},{ apply(fn,thisArg,agrs){ }, get(fn,key){ return _this[key]; }, set(fn,key,val){ _this[key] = val; return true; } }) } get(){ console.log('get request'); }}export default new Axios();这样就实现了axios('/user')或axios.get('/user')这样的效果了。 ...

October 6, 2019 · 3 min · jiezi

从JS继承实现一个VueJs的render函数

市面上的主流框架,相信作为一个前端搬砖人员,或多或少都会有所接触到。如ReactJs、VueJs、AngularJs。那么对于每个框架的使用来说其实是比较简单的,还记得上大学时候,老师曾经说过:"技术就是窗户纸,捅一捅就破了",也就是说,任何一门技术,只要深入去研究,那么它也不再是很神秘的东西了。我个人在工作中用VueJs是比较多的,当然React也会,那今天就为大家来实现一个Vuejs框架中的render函数首先来看一段代码: <div id="div1"> <span>test</span> <Tab></Tab> <UserLogin></UserLogin> </div>最终在页面上的呈现是怎样的呢? 毫无疑问,只看到了test这一段文本内容。因为html不认识Tab、UserLogin这两个"异类"元素。那么假如现在要实现的是,通过一个render方法: render({ root:'#div1', components:{ Tab,UserLogin } })将Tab、UserLogin这两个组件的内容渲染出来,该去怎样实现呢?这里涉及到的知识点如下: 类型判断DOM操作Js的继承、多态组件化思想首先通过Js的继承及组件化思想来定义两个类Tab、UserLogin,它们都有一个自身的render方法(从父类Component)继承而来并进行了重写。直接上代码: Component类: class Component{ render(){ throw new Error('render is required'); } }Tab类: class Tab extends Component{ render(){ let div1 = document.createElement('div'); div1.innerHTML = '我是Tab组件'; return div1; } }UserLogin类: class UserLogin extends Component{ render(){ let div2 = document.createElement('div'); div2.innerHTML = "我是登录组件" return div2 } }到这里,相信大家学过ES6的,对这样的代码都是感觉很熟悉的,重点是render函数究竟该怎样去实现。再来看一下render函数的基本骨架: render({ root:'#div1', components:{ Tab,UserLogin } })render函数接收了一个参数(对象类型),里面包括两个属性root(挂载的元素),以及components(带渲染的组件类)。对于render的实现,先从root这个属性入手。灵魂拷问,root属性一定是某个元素的id吗?对于一个函数的参数来说,使用者传递什么类型都是可以的,但只要符合规定的参数才能有效,说那么多其实就是需要对render函数对象参数的root属性进行校验。代码如下: ...

September 20, 2019 · 2 min · jiezi

vue项目betterscroll使用注意点

1.应该在何时创建BScroll对象1)created : 中请求数据,ajax是异步的,这个时候可能mounted已经执行完了,也就是dom挂载完了,但数据还没请求回来,无法获取到内部元素(数据渲染出来的dom)高度. 无法渲染内部元素,无法滚动2)updated:数据发生改变时执行;数据改变,dom也要重新渲染,并执行updated,但无法保证是先dom渲染还是先updated, //解决:this.$nextTick(()={ //操作 this.scroll = new BScroll(this.$refs.className,{})})3)最佳方式: mounted() { this.scroll = new BScroll(this.$refs.scrollWrapper,{})}watch: { shuju() { this.$nextTick(() => { this.scroll.refresh(); }) }}2.拆分better-scroll组件----//scroller.vue <template> <div ref="wrapper"> <div> //vue 感知不到slot变化,但能感知数据变化 <slot></slot> </div> </div></template><script> import BScroll from 'better-scroll' export default { props: ['shuju'], mounted() { this.scroll = new BScroll(this.$refs.wrapper,{}) }, watch: { //保障数据加载dom渲染,刷新 shuju() { this.$nextTick(() => { this.scroll.refresh(); }) } } }</script><style></style>

September 10, 2019 · 1 min · jiezi

你或许不知道的ES6解构

相信大家对解构赋值并不陌生:阮大佬ECMAScript 6 入门里面有讲七种用途,用得最多莫过于json数据处理 json数据处理let jsonData = { id: 42, status: "OK", data: [867, 5309]};let { id, status, data: number } = jsonData;console.log(id, status, number);// 42, "OK", [867, 5309]当然变换变量的值,也是用得较多的。 交换变量的值let x = 1;let y = 2;[x, y] = [y, x];let x3 = "a";let y3 = "b";let z3 = "c";[x3,y3,z3] = [z3,y3,x3];console.log(x3,y3,z3);//c,b,afor..of中使用const arrC = ["a", "b"];for(const [index, element] of arrC.entries()){ console.log(index,element);}//0 "a"//1 "b"还可以对象解构原始值(字符长度等。。)const {length: len} = "abc";console.log(len);//3对象的剩余属性构造const objA = {a: 1, b: 2, c: 3};const {a:propValue, ...remaining}= objA;console.log(propValue,remaining);//1 {b: 2, c: 3}remaining被分配一个对象,该对象具有在模式中未提及其键的所有数据属性。 ...

September 10, 2019 · 1 min · jiezi

深入-JS-对象属性

译者:前端小智作者:Dr.Axel来源:2ality为了保证的可读性,本文采用意译而非直译。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 为了回馈读者,《大迁世界》不定期举行(每个月一到三次),现金抽奖活动,保底200,外加用户赞赏,希望你能成为大迁世界的小锦鲤,快来试试吧属性决定JS中对象的状态,本文章主要分析这些属性是如何工作的。 JS几种不同的属性JS有三种不同的属性:数据属性,访问器属性和内部属性。 1.1 数据属性(properties)对象的普通属性将字符串名称映射到值。例如,下面对象obj有一个数据属性,名称为 prop,对应的值为 123: var obj = { prop: 123};可以用以下方式读取属性的值: console.log(obj.prop); // 123console.log(obj["prop"]); // 123当然也可以用以下方式来设置属性的值: obj.prop = "abc";obj["prop"] = "abc";1.2 访问器属性另外,可以通过函数处理获取和设置属性值。 这些函数称为访问器函数。 处理获取的函数称为getter。 处理设置的函数称为setter: var obj = { get prop () { return 'Getter'; }, set prop (value) { console.log('Setter: ' + value); }}访问 obj 属性: > obj.prop 'Getter'> obj.prop = 123; Setter: 1231.3 内部属性一些属性只是用于规范,这些属于“内部”的内部,因为它们不能直接访问,但是它们确实影响对象的行为。内部属性有特殊的名称都写在两个方括号,如: 内部属性[[Prototype]]指向对象的原型。它可以通过Object.getPrototypeOf()读取。它的值只能通过创建具有给定原型的新对象来设置,例如通过object.create()或__proto__ 。内部属性[[Extensible]]决定是否可以向对象添加属性。可以通过Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。可以通过Object.preventExtensions()方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。2. 属性特性(attribute)属性的所有状态,包括数据和元数据,都存储在特性(attribute)中。它们是属性具有的字段,就像对象具有属性一样。特性(attribute)键通常用双括号编写: 以下特性是属于数据属性: [[Value]]:该属性的属性值,默认为undefined。[[Writable]]:是一个布尔值,表示属性值(value)是否可改变(即是否可写),默认为true。以下特性是属于访问器属性: [[Get]]:是一个函数,表示该属性的取值函数(getter),默认为undefined ...

September 10, 2019 · 2 min · jiezi

JavaScript中如何反转数组

如果您需要反转数组元素的顺序,可以使用数组方法reverse()⏪,如下所示: 修改原始数组需要注意的一点是它会改变原始数组。 如何在不改变原始数组的情况下反转数组以下是一些不会改变原始数组的做法。我们来看看 使用 slice 和 reverse 使用 ...扩展运算符 和 reverse 使用 reduce 和 ...扩展运算符 使用 reduceRight 和 ...扩展运算符 或者使用push 参考资源: MDN Web Docs: reversew3schools: reverseStack Overflow: Reverse array in Javascript without mutating original array还可以关注头条号:「前端知否」

September 9, 2019 · 1 min · jiezi

36-个JS-面试题为你助力金九银十面试必读

来源:javapoint译者:前端小智为了保证的可读性,本文采用意译而非直译。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 为了回馈读者,《大迁世界》不定期举行(每个月一到三次),现金抽奖活动,保底200,外加用户赞赏,希望你能成为大迁世界的小锦鲤,快来试试吧1.JS中let和const有什么用?在现代js中,let&const是创建变量的不同方式。 在早期的js中,咱们使用var关键字来创建变量。 let&const关键字是在ES6版本中引入的,其目的是在js中创建两种不同类型的变量,一种是不可变的,另一种是可变的。 const:它用于创建一个不可变变量。不可变变量是指其值在程序的整个生命周期中永不改变的变量。 let: let用于创建一个可变变量,可变变量是像var这样的普通变量,可以任意次数地更改。 2. JS 中的主要有哪几类错误JS有三类的错误: 加载时错误:加载web页面时出现的错误(如语法错误)称为加载时错误,它会动态生成错误。 运行时错误:由于滥用HTML语言中的命令而导致的错误。 逻辑错误:这些错误是由于对具有不同操作的函数执行了错误的逻辑而导致的 3. 如何通过类别名获取 dom 元素在 JS 中使用document.getElementsByClassName() 方法来获取具有类名的元素。 4.JS的作用域链是什么及其作用一般情况下,变量取值到创建这个变量的函数的作用域中取值。但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。 JS中的作用域链主要用于解析变量的值。 如果没有这个,在不同的作用域内定义了许多变量,JS很难为变量选择某个值。 5.解释JS中的MUL函数MUL表示数的简单乘法。在这种技术中,将一个值作为参数传递给一个函数,而该函数将返回另一个函数,将第二个值传递给该函数,然后重复继续。例如:x*y*z可以表示为 function mul (x) { return function (y) { return function (z) { return x * y * z; } }}6.用纯JS编写一个程序来反转字符串使用内置函数:内置函数reverse()直接反转字符串。 str="jQuery";str = str.split("")str = str.reverse()str = str.join("")alert(str);首先将字符串拆分为数组,然后反转数组,最近将字符连接起来形成字符串。 使用循环:首先,计算字符串中的字符数,然后对原始字符串应用递减循环,该循环从最后一个字符开始,打印每个字符,直到count变为零。 7.JS中如何将页面重定向到另一个页面?使用 location.href:window.location.href =“https://www.onlineinterviewquestions.com/”使用 location.replace: window.location.replace(" https://www.onlineinterviewquestions.com/;");8. 列出JS中的一些设计模式:设计模式是软件设计中常见问题的通用可重用解决方案,以下是一些设计模式是: 创建模式:该模式抽象了对象实例化过程。 结构型模式:这些模式处理不同的类和对象以提供新功能。 行为模式:也称发布-订阅模式,定义了一个被观察者和多个观察者的、一对多的对象关系。 并行设计模式:这些模式处理多线程编程范例。 架构设计模式:这些模式用于处理架构设计。 ...

September 9, 2019 · 3 min · jiezi

前端资源汇总

项目地址https://github.com/abc-club/f... 本文收集学习过程中使用到的资源。 持续更新中…… 目录vuereactWeextypescript常用库jses6移动端h5游戏微信公众号webpackGraphQL性能与监控高质文章趋势动效可视化数据结构与算法js core代码规范工具canvas测试网络请求pwa数据库其他必备知识vue官方awesome-vuenuxt(vue服务端渲染)mpvue(vue小程序)vuepressvue-i18nawesome-nuxt组件库或框架electron-vueuni-app(uni-app 是一个使用 Vue.js 开发小程序、H5、App的统一前端框架)chameleon(滴滴一套代码运行多端,一端所见即多端所见)overwatch-uielementiview *22k+vuetifymint-ui *14k+bootstrap-vueant-design-vuecube-uiv-chartsvue-awesome-swipervee-validatevue-lazyloadvue-quill-editor文章逐行分析vue(vue源码分析)learnVue(vue源码分析)vue-analysis(vue源码分析)Vue3.0 前的 TypeScript 最佳入门实践浅谈使用 Vue 构建前端 10w+ 代码量的单页面应用开发底层VUE单页应用骨架屏方案一个Vue引发的性能问题【2019 前端进阶之路】Vue 组件间通信方式完整版Vue.js 组件精讲剖析 Vue.js 内部运行机制Vuejs建议和最佳实践Vue 项目性能优化 — 实践指南(网上最全 / 详细)开源项目vue-sellvue2-elm *29k+iview-adminvue-element-admin *38k+vue-data-boardbilibili-vuebest-resume-ever vue2-manageJSUImall-admin-webvue-framework-wzVue-cnodejsreact官网React官网 https://reactjs.org/React中文网 https://react.docschina.org/React-router https://reacttraining.com/rea...redux https://redux.js.org/introduc...redux中文 http://cn.redux.js.org/umi https://umijs.org/dva https://dvajs.comimmutable https://github.com/immutable-...react-devtools-tutorial参考资料React 源码解析awesome https://github.com/enaqx/awes...react-hook https://github.com/streamich/...React.js 小书 https://juejin.im/post/58c7a1...React入门看这篇就够了 https://segmentfault.com/a/11...掘金最污的 React16.x 图文视频教程(2万5千字长文-慎入) https://juejin.im/post/5d085b...react demo https://gist.github.com/sAbak...一文速览React全栈 https://juejin.im/post/5d0ee2...React同构与极致的性能优化 https://segmentfault.com/a/11...阿里开源项目 https://segmentfault.com/a/11...一文速览React全栈掘金最污的 React16.x 图文视频教程(2万5千字长文-慎入)你要的 React 面试知识点,都在这了如何优化你的超大型React应用 【原创精读】React 实战:设计模式和最佳实践21个让React 开发更高效更有趣的工具在react/redux中使用Immutable从头开始,彻底理解服务端渲染原理(8千字汇总长文)React 的性能优化(一)当 PureComponent 遇上 ImmutableJSProfiling React performance with React 16 and Chrome Devtools.React 性能优化技巧总结介绍React Profiler组件库ant-design https://ant.design/index-cnant-design-mobile https://mobile.ant.design/ind...react-intlrc-form https://github.com/react-comp...nivo(React 数据可视化库)框架umi https://umijs.org/飞冰 https://ice.work/next.js https://github.com/zeit/next.jsbeidou https://github.com/alibaba/be...egg-react-ssr https://github.com/ykfe/egg-r...react-server https://github.com/redfin/rea...Vulcan.js(The full-stack React+GraphQL framework)Demotypescript官网参考资料typescript中文 https://www.tslang.cn/typescript中文 https://ts.xcatliu.com/ https://zhongsp.gitbooks.io/t...typescript https://www.html.cn/doc/types...typescript进阶 https://www.jianshu.com/p/13a...awesome https://github.com/dzharii/aw...深入理解 TypeScript https://github.com/jkchao/typ... https://jkchao.github.io/type... https://github.com/basarat/ty...TypeScript入门指南(基础篇) https://juejin.im/post/5d3bb5...TypeScript 入门指南 https://mp.weixin.qq.com/s/Oy...react+typescript demoReact+redux+typescript https://github.com/piotrwitek...https://github.com/fi3ework/b...typescript-tutorial https://github.com/xcatliu/ty...https://github.com/Lemoncode/...https://github.com/rokoroku/r...文章三千字讲清TypeScript与React的实战技巧常用库数据Immutablejs https://github.com/immutable-...富文本编辑器simditor https://github.com/mycolorway...时间moment物联网mosca https://github.com/mcollina/m...MQTT https://github.com/mqttjs/MQT...demojavascript-mqtt-demo-wearingTip https://github.com/coolnameis...面试官(7): 聊一聊 Babel? https://juejin.im/post/5c03b8...js正则表达式learn-regex ★22k+ 正则表达式30分钟入门教程2019 年常用 JavaScript 正则大全正则表达式不要背2019年JS正则大全(常用)this嗨,你真的懂this吗?函数式编程「前端进阶」彻底弄懂函数组合函数式编程,真香深入学习javascript函数式编程一文带你了解 JavaScript 函数式编程不要再尝试函数式编程了其他【译】JavaScript的工作原理:事件循环及异步编程的出现和 5 种更好的 async/await 编程方式优秀 JavaScript 开发人员应掌握的 9 个技巧浅拷贝与深拷贝JS中轻松遍历对象属性的几种方式你不懂JS(系列丛书)前端开发变量命名系列 - JavaScript篇一文带你了解 JavaScript 函数式编程es6前端模块化详解(完整版)一口(很长的)气了解 babelPromise源码详解最后一次搞懂 Event Loop移动端文章移动端适配深度探究第三代移动端布局方案移动端1px解决方案常用库lib-flexible https://github.com/amfe/lib-f...h5游戏开源项目Hilo - HTML5 互动游戏引擎微信公众号实战项目wechaty https://github.com/Chatie/wec...wechatBot https://github.com/gengchen52...webpack官网webpackwebpack官方文档webpack 中文文档(https://webpack.docschina.org/)文章前端构建秘籍【Cute-Webpack】Webpack4 入门手册(共 18 章)GraphQL文章前端er了解GraphQL,看这篇就够了GraphQL 入门看这篇就够了awesome-graphql性能与监控文章前端性能优化原理与实践GMTC 大前端时代前端监控的最佳实践你必须懂的前端性能优化前端性能优化不完全手册那些你不知道的meta标签前端静态资源缓存最优解以及max-age的陷阱node实战前端缓存总结浏览器缓存彻底理解浏览器的缓存机制前端异常监控解决方案研究 – 腾讯CDC从 0 到 1 的前端异常监控项目实战监控开源库https://github.com/BetterJShttps://github.com/iv-web/aeg...https://github.com/RicardoCao...文章捕获未处理的Promise错误方法前端异常监控、上报及js压缩代码定位常用工具阿里云监控 (网站性能、错误等监控)growingio (网站访问量监控)sentry (错误监控)fundebug (错误监控)gtmetrix (网站访问速度)zanePerfor (网站访问速度)pingdom (网站状况监控)开源库hiper *2k+高质文章if 我是前端团队 Leader,怎么制定前端协作规范?阿里大佬浅谈大型项目前端架构设计年终回顾,为你汇总一份「前端技术清单」8年前端开发的知识点沉淀(不知道会多少字,一直写下去吧...)fullstack tutorial五星推荐的系列文章清单端动态化方案详细设计让虚拟DOM和DOM-diff不再成为你的绊脚石彻底理清前端单页面应用(SPA)的实现原理 【精读源码】原来 CSS 与 JS 是这样阻塞 DOM 解析和渲染的使用 postMessage 解决 iframe 跨域通信问题基于工程经验的『RESTful接口设计规范』RESTful API 编写指南前端技术栈干货文章链接(精品)新时代下前端工程师的推荐书籍和必备知识趋势微前端 https://www.cnblogs.com/zhuan... https://github.com/neuland/mi... ...

September 7, 2019 · 2 min · jiezi

ES6新特性之Proxy

基本概念字面意思的理解就是代理。 用于定义基本操作的自定义行为,就是我们可以自定义某些行为,比如属性的查找,赋值,枚举,函数调用等。实际上我们利用这个Proxy实现对编程语言进行编程,就是把一些内部的方式,内置的方法改变了,这种编程就叫做语言编程。属性代理就做拦截。关于Proxy需要注意的地方有:Proxy内部的this关键字的指向是Proxy代理本身;它的构建方式需要借助一个Proxy的构造函数new Proxy(target,handler),其中target叫做目标对象,Proxy构造函数返回的是一个包装过后的目标对象,handler是代理的行为的函数。 let handler = { get: function(target, name) { return name in target ? target[name] : 'Eric'; }};let p = new Proxy({}, handler);p.name;// Eric let proxy = new Proxy({}, { get: function(target, property) { return 'Eric'; }});let obj = Object.create(proxy);obj.name;// Eric (说明Proxy是可以继承的)代理操作get, 拦截某个属性的读取操作,接收三个参数:target(目标对象)、property(属性名)、receiver(一般是Proxy对象本身,可选参数) let teacher = { name: "Eric" }; let proxy = new Proxy(teacher, { get: function(target, property) { if (property in target) { return target[property]; } else { throw new ReferenceError("\"" + property + "\" does not exist."); } } }); proxy.name; // Eric proxy.age; // ReferenceError: "age" does not exist. get属性拦截可以继承,需要注意的一点是,当某个对象不可配置(configurable)或者不可写(writable),使用get会报错。 ...

August 21, 2019 · 2 min · jiezi

JS箭头函数之为何用怎么用何时用

在现代JS中最让人期待的特性就是关于箭头函数,用=>来标识。箭头函数有两个主要的优点: 更简短的函数;更直观的作用域和this的绑定(不绑定this)因为这些优点,箭头函数比起其他形式的函数声明更受欢迎。比如,受欢迎的airbnb eslint configuration库会强制使用JavaScript箭头函数创建匿名函数。然而,箭头函数有优点,也有一些“缺点”。这就需要在使用的时候做一些权衡。下面就从为何用、怎么用、何时用,这个三部分做一些总结。 为何用?引入箭头函数有两个方面的作用:更简短的函数并且不绑定this更简短的函数var elements = ['h1', 'div', 'span', 'section'];elements.map(function(el) { return el.length; // 返回数组: [2, 3, 4, 7]});// 从上面的普通函数可以改写为如下的箭头函数elements.map((el) => { return el.length; // [2, 3, 4, 7]});// 当箭头函数只有一个参数时,可以省略参数的圆括号elements.map(el => { return el.length; // [2, 3, 4, 7]});// 当箭头函数体只有一个`return`语句时,可以省略`return`关键字和方法体的花括号elements.map(el => el.length); // [2, 3, 4, 7]// 在这个例子中,因为我们只需要`length`属性,所以可以使用参数结构// 需要注意的是字符串`"length"`是我们想要获得的属性名称,而`elLength`则只是个变量名,可以替换成任意合法的变量名elements.map(({ "length": elLength }) => elLength); // [2, 3, 4, 7]不绑定this在箭头函数出现之前,每个新定义的函数都有它自己的this值(在构造函数的情况下是一个新对象,在严格模式的函数调用中则为undefined,如果该函数被作为"对象方法"调用则为基础对象等)。而箭头函数并没有它自己的执行上下,实际上,这就意味着代码中的this和arguments都是继承它的父函数。 const obj = { name: 'test object', createAnonFunction: function() { return function() { console.log(this.name); return this; } }, createArrowFunction: function() { return () => { console.log(this.name); return this; } }}const anon = obj.createAnonFunction();anon(); // undefinedanon() === window // true const arrow = obj.createArrowFunction();arrow(); // 'test object'arrow() === obj // true第一个匿名参数有自己的上下文(指向的并非obj对象),当被赋值给anon变量且调用时,this发生了改变,指向了window。另一个,箭头函数与创建它的函数有相同的上下文,故指向obj对象。 ...

August 21, 2019 · 3 min · jiezi

vue项目-es6语法报错

代码库迁移时遇到的问题 1.不识别es6语法 扩展运算符...报错 ...是es6的对象扩容运算符,目前babel暂不支持,需要引入新的包来解决,要安装一个babel插件翻译对象展开运算符语法。 解决方法: npm install babel-plugin-transform-object-rest-spread根目录下创建 .babelrc文件 .babelrc文件中写: { "presets": [ ["es2015", { "modules": false }] ], "plugins": ["transform-object-rest-spread"] //不能解析es6语法关键解决}2.报错 ModuleBuildError: Module build failed: Error: No PostCSS Config found in:XXX 解决方法: 根目录下创建postcss.config.js文件postcss.config.js中写 module.exports = { plugins: { 'autoprefixer': {browsers: 'last 5 version'} } }好爽 !!!

August 20, 2019 · 1 min · jiezi

commonjs-ES-module-babel转码-webpack转码

js模块发展历程-javaScript模块七日谈前端模块化开发那点历史 #588现代ES模块也需要各种转码工具才可以在浏览器里正常运行,下面是转码现代ES模块需要了解到的知识点 commonjs & ES module & babel转码 & webpack转码 CommonJS简述CommonJS 模块输出的是一个值的 拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值了如果输出的是对象,改变其属性的话,外部引用的地方是会发生变化的如果直接改变输出的引用,那外界引用的地方是不会变化的(取缓存里面的结果)CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成commonjs 一个模块就是一个文件,require 命令第一次执行加载该脚本就会执行整个脚本,然后在内存中生成一个对象{ id: '...', // 模块名 exports: {}, // 真实的模块 loaded: true // 是否加载完毕}以后再次 require 该模块时,就会去缓存里取该对象的 exports 的属性无论 require 多少次,模块都只会运行一次,后续加载都是从缓存里面取module.exports 与 exports 的关系commonjs 规范仅仅定义了 exportsmodule.exports 是 nodejs 对 commonjs 规范的实现我们把这种实现称为 commonjs2https://github.com/webpack/webpack/issues/1114#issuecomment-105509929exports 只是在初始化对 module.exports 的引用初始化指向同一片内存空间模块导出的是 module.exports 如果对 module.exports 重新赋值,exports 上,挂的方法/属性将会失效require 引入的是 module.exports 导出的东西为避免混乱/错误,一般导出模块只建议用 module.exports 一般第三方包都用这种方式导出 modules.exports = exports = {}循环引用问题 (某个模块出现循环加载,就只输出已经执行的部分,还未执行的部分不会输出)// 代码如下// a.jsexports.A = '我是a模块';var b = require('./b.js');console.log('在 a.js 之中, 输出的 b模块==> ', b.B);exports.A = '我是后期修改过的a模块';console.log('a.js 执行完毕');// b.jsexports.B = '我是b模块';var a = require('./a.js');console.log('在 b.js 之中,输出a模块 ==>', a.A);exports.B = '我是修改后的b模块';console.log('b.js 执行完毕');// main.jsvar a = require('./a.js');var b = require('./b.js');console.log('在 main.js 之中,输出的 a模块=%j, b模块=%j', a.A, b.B);// 输出结果如下:➜ webpack-plugin git:(master) ✗ node src/babel/index 在 b.js 之中,输出a模块 ==> 我是a模块b.js 执行完毕在 a.js 之中, 输出的 b模块==> 我是修改后的b模块a.js 执行完毕在 main.js 之中,输出的 a模块="我是后期修改过的a模块", b模块="我是修改后的b模块"// 执行过程如下:执行 a.js 遇到 require b.js,暂停 a.js 执行,去执行 b.jsb.js 执行到第二行,遇到 require a.js ,从缓存中拿出刚刚 a.js 导出的模块,在 b.js 里面使用继续执行 b.js 后面的代码待 b.js 执行完毕后,控制权交还 a.js,继续执行拿到 b.js 导出的模块,在 a.js 继续使用 ... 直到结束 循环引用注意点:由于 commonjs 模块遇到循环加载时,返回的是当前已经执行的部分的值,而不是全部代码之后的值,两者可能会有差异,所以输入变量的时候必须非常小心,使用 var a = require('a') 而不是 var a = require('a').fooES6 Module基本使用export default A // 用户不需要知道导出模块的变量名import a from 'a.js'// 可以导出多个export var a = 1 // 这种方式可以直接导出一个表达式或var a = 1export {a} // 必须用花括号包起来import {a} from 'a.js'// as 关键字重命名模块export { a as A }// 导入导出合并export { default as Comps } from '../xxx'相当于import Comps from './xx'export { Comps }// 执行 loadsh 模块,但并不输出任何值import 'lodash';// 整体加载所有模块,访问时用 circle.xxx 访问import * as circle from './circle';简述: ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入,它的接口只是一种静态定义,在代码静态解析阶段就会生成。// ES6模块import { stat, exists, readFile } from 'fs';上面代码的实质是从fs模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。由于 ES6 模块是编译时加载,使得静态分析成为可能import命令具有提升效果,会提升到整个模块的头部,首先执行import命令是编译阶段执行的,在代码运行之前。由于 import 是静态执行,所以不能使用表达式和变量(这类只有在运行时才能得到结果的语法结构)静态加载模块的好处:1. 不再需要UMD模块2. 浏览器API可以用模块格式提供,不必再做成全局变量,不再需要全局对象如:Math (可以像Python一样用模块导入)动态 import动态import() 是非常有用的。而静态型的 import 是初始化加载依赖项的最优选择,使用静态 import 更容易从代码静态分析工具和 tree shaking 中受益import(模块路径) 返回 promise,从 then 的结果里拿到加载的模块webpack 2.x 之后,有一个魔力注释的功能,会把加载的模块重命名为你注释里的文字ES6模块的浏览器加载传统方法加载js脚本script type="application/javascript"异步加载: async defer脚本异步加载,不会阻塞dom结构的解析async:加载完立即执行,渲染引擎中断,待之脚本执行完继续渲染defer:加载完会等待页面渲染完毕及页面其他脚本执行完毕才会执行多个 async 执行没有顺序保证,多个 defer 有顺序保证 es6 模块加载script type="module"浏览器对 type="module" 的处理和 defer 标志一致es6 模块的循环加载ES6 处理“循环加载”与 CommonJS 有本质的不同。ES6 模块是动态引用,如果使用import从一个模块加载变量(即import foo from 'foo'),那些变量不会被缓存,而是成为一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。es6 模块会在使用使用时才去加载对应的模块如果是循环应用,可以将对应的输出改写成函数形式,利用函数的变量提升功能CommonJS 与 ES Module 的对比// 此处是对比CommonJS 模块时运行时加载 -- 值得拷贝ES6模块时 编译时 输出接口 -- 值得引用commonjs 模块只会加载一次,以后在 碰到 require 同样的东西就从缓存里面加载如果把原模块导出的东西改变,引入模块不会跟着改变,还是从缓存里面取原来的值ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个动态的只读引用。等到真的需要用到时,再到模块里面去取值JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6的输入有点像Unix系统的“符号连接”,原始值变了,import输入的值也会跟着变。ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。commonjs: module.exports = {} exports 运行阶段才加载模块,可以使用逻辑语句 模块就是对象加载的就是该对象 加载的是整个模块即将所有的接口都加载进来 输出的是值得拷贝,原模块发生变化不会影响已经加载的 this 指向当前的模块es6 模块 export 可以输出多个 {} export default 解析阶段确定对外的接口,解析阶段输出接口,不可以使用逻辑语句 加载的模块不是对象 可以单独加载其中的几个模块 静态分析,动态引用输出的是值得引用,原模块变化会影响已加载的模块 this 指向 underfinedBabel 转换 ES6 的模块化语法Babel 对 ES6 模块转码就是转换成 CommonJS 规范模块输出语法转换Babel 对于模块输出的转换,就是把所有输出都赋值到 exports 对象的属性上,并加上 ESModule: true 的标识表示这个模块是由 ESModule 转换来的 CommonJS 输出对于解构赋值输入import {a} from './a.js'转义为var _c = require('./a.js')然后取 _c.a 对于 defaultimport a from './a'import {default as a} from './a'babel转义时的处理,引入了一个 函数function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : {'default': obj}}var _a = _interopRequireDefault(require("./a.js"));console.log(_a["default"]);// 意思就是如果不是 esmodule 就为其手动添加个 default 属性,取值时统一取 default有个疑问:babel 为什么 会把 export export.default 导出的模块转换为 exports.xxx 和 exports.default 呢?而不是 module.exports ???我没有找到解释,如果您知道,麻烦给我留言下webpack 对 es6 模块和commonjs 的处理webpack本身维护了一套模块系统,这套系统兼容所有历史进程下的前端规范写一个简单的webpack配置module.exports = { entry: "./index.js", output: { path: path.resolve(__dirname, "dist"), filename: "[name].[contenthash:8].js" }, mode: "development"};执行打包命令 webpack --config webpack.config.js --env=dev 输出 main.[hash].js// 打包后代码简化如下// 首先是一个 webpack 模块运行时代码(function(modules) { // webpackBootstrap // 缓存模块 var installedModules = {}; // 函数 __webpack_require__ 参数 模块 id,用于加载和缓存模块 function __webpack_require__(moduleId) { // Check if module is in cache if(installedModules[moduleId]) { return installedModules[moduleId].exports; } // Create a new module (and put it into the cache) var module = installedModules[moduleId] = { i: moduleId, l: false, exports: {} }; // Execute the module function modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // Flag the module as loaded module.l = true; // Return the exports of the module return module.exports; } /*** 所有加载的模块都存在于 installedModules 内,其结构为: id: { id, loaded: Boolean // 是否加载过 exports // 模块的导出 } */ // 省略... 定义各种工具函数和变量 // Load entry module and return exports // 加载 entry 模块,并返回其导出,我们写的模块才会被真正执行 return __webpack_require__(__webpack_require__.s = "./index.js");})({ "./index.js": (function(module, __webpack_exports__, __webpack_require__) { // ... }, "./src/a.js": (function(module, __webpack_exports__, __webpack_require__) { // ... }, // ...})这个自调用的函数的参数 modules,就是包含所有待加载模块的一个对象{ [id: string]: Function}异步加载: import ==> webpack.requireEnsure ==> webpackJsonphttps://www.njleonzhang.com/2018/12/30/webpack-bundle-1.html其他常见问题1. babel 与 webpack 的关系webpack:将 ES6、CommonJS、amd、cmd 等模块化通过自己内部的机制统一成 webpack 的模块化。babel:转码 es6 语法,配合一些列 babel 工具链可以将新的 es2015+ 代码转换成所有浏览器支持的 es代码,babel 也可以将 es6 模块转换成 commonjs 模块2. es module 与 commonjs 为何可以混用因为 babel 会把 es module 转换成 commonjs 规范的代码babel 转码 es module 时如果遇到 export default 这种导出模块的书写方式后,会将其转换成 exports.default ,这时如果用 require 引入时,需要对其加上 .default 如 require('./a.js').a 这样才能获取 a 模块 export default 导出的 aimport 动态加载的模块也需要 .default 才能获取真实模块导出的值,如 import('./a.js').then(res => res.dafault)3. antd、element-ui 等ui框架的按需加载组件的实现需要 babel-plugin-component ...

August 18, 2019 · 4 min · jiezi

es6-常用语法

let & const建议,多用const,变量用let,不用var // let 没有变量提升 // console.log(a) // let a = 1; // b 声明常量,基本类型不可修改 // const b = 1; // b = 2; // 可以修改复杂类型 const c = [1] c[0] = 10; console.log(c) // ?deconstruct 解构赋值 const list = [11,22,33]; let [a,b] = list; let [a1, ...b1] = list; console.log(a, b ) console.log(a1, b1) const obj = { name: "david", age: 21, sex: 'male' } //const {name, age} = obj; // console.log(name, age) // 剩余参数 // const { // name, ...attrs // } = obj; // console.log(name) // console.log(attrs) // 默认值 const{name = 'admin'} = obj; console.log(name) // 扩展 // 怎么求一个数组最大值 const list1 = [11,2,444,5] // 原生 console.log(Math.max.apply(window,list1)) // es6 console.log( Math.max(...list1) ) // 扩展 react中的展开符 // 1. 给组件增加参数 // const attrs = { // name: '111', // age: 555 // } // <Component ...attrs />module 模块// 整个模块导出// eg state.jsexport default {}class State { list: []}export default new State()// 引入方法import $$State from "./state"import {list} from "./state"// 一个一个导出// eg. math.jsexport function add() {}export function minus() {}import {add, minus} from "./math"String let string = "apple,banana,orange"; string.includes("banana"); // true string.startsWith("apple"); // true string.endsWith("apple"); // false const str = 'david' const str1 = `${str} is a boy!` console.log(str1)Objectconst name = 'david' ,age = 11;// 变量创建对象const person = {name, age}// 对象里的方法const obj = { say(){ console.log("hello") }}// ES6允许用表达式作为属性名,但是一定要将表达式放在方括号内const fnName = 'list1'const obj2 ={ [`${fnName}_get`](){ console.log("hello world") }}obj2.list1_get()// 合并对象const obj1 = { a: 1}const obj11 = { ab: 1}const obj111 = {...obj1, ...obj11}console.log(obj111)const obj = { name: 'david', age: 11}console.log( Object.keys(obj))console.log( Object.values(obj))console.log(Object.entries(obj)) // 重要 Object.assignconst aa = Object.assign({}, obj1)aa.a = 111;console.log(aa)console.log(obj1)Array // Array.from() 类数组变成数组 const obj = {} obj[0] = 0; obj[1] = 1; obj.length = 2; console.log(obj) const arr = Array.from(obj) console.log(arr) // 合并数组 const arr1 = [111] const arr2 = [333] const arr3 = [...arr1, arr2] // 包含元素 console.log( arr3.includes(111) )function箭头函数this,指向上层箭头函数没有argumentsconst did = () => { console.log("dis something") } did() const doing = name => { console.log("I am doing " + name) } doing("cooking") const introduce = (name, age = 18) => { console.log( `I am ${name} and I am ${age}` ) } introduce("Tom") const talks = (market, ...others) => { console.log(market) console.log(others) } talks("家乐福", '河马生鲜', 'KFC') // 箭头函数this指向问题 name = "window" const obj = { name:'obj', say: () => { console.log(this) console.log(this.name) console.log("\n") }, tell(){ console.log(this) console.log(this.name) console.log("\n") } } obj.tell() obj.say()class class Animal{ constructor(){ this.name = "animal" } // 静态方法 static tell(){ console.log("Animal tell") } // 实例方法 gogo(){ console.log("gogogo") } } class Dog extends Animal { constructor(){ super() this.name = "Dog" } } const hsq1 = new Animal() const hsq2 = new Dog() console.log(hsq1.name) console.log(hsq2.name) hsq1.gogo() Animal.tell() Dog.tell()proxy可用来实现数据双向绑定 let target = { name: 'Tom', age: 24 } let handler = { get: function(target, key) { console.log('getting '+key); return target[key]; // 不是target.key }, set: function(target, key, value) { console.log('setting '+key); target[key] = value; } } let proxy = new Proxy(target, handler) console.log(proxy.name)// 实现数据双向绑定的两种实现 <input type="text" id="a"><script> const model = { } // view - model $("#a").on("keyup" ,function () { model.name = $(this).val() console.log(model) }) // let value = '' // // model - view // Object.defineProperty(model, 'name', { // set: function (v) { // value = v; // }, // get: function () { // return value // } // }) let handler = { get: function(target, key) { console.log('getting '+key); return target[key]; // 不是target.key }, set: function(target, key, value) { target[key] = value; $("#a").val(value) } } let proxy = new Proxy(model, handler) setTimeout(function () { proxy.name = 'hhhhhhhh' }, 3000) </script>

August 18, 2019 · 3 min · jiezi

javascript下条件编译的实现基于webpack的jsconditionalcompileloader插件

条件编译,是指 用同一套代码和同样的编译构建过程,根据设置的条件,选择性地编译指定的代码,从而输出不同程序的过程。一般用在C++、Java、C#这样的编译执行语言。对于javascript,我们也可以使用基于webpack的js-conditional-compile-loader插件实现类似的条件编译功能。 我们经常会遇到类似这样的需求:代码需要根据运行环境,运行不同的代码。比如,测试环境可以控制台输出一些信息,生产环境则不提示;同时又不希望输出的代码中存在判断环境的if-else代码使程序包体积增大。项目交付给多个客户使用,而某些客户会有一些定制模块。这些定制模块只给特定用户使用,不希望也一起打包在不相干客户的程序包中,但也不希望给定制客户单独维护一个特殊项目而增加维护成本。使用条件编译的方法,可以优雅地解决这样的问题,同时代码维护方便,发布的程序包中也不会有多余的代码存在。 插件原理js-conditional-compile-loader插件是一个webpack的loader插件,它会在webpack处理js代码之前,将js代码根据设置的条件进行修改,去掉当前条件下不需要的代码,保留需要的代码,从而实现条件编译的功能。 使用步骤可参考这里的中文文档。 1. 安装npm i -D js-conditional-compile-loader2. 配置webpack在rules中为js文件添加loader,作为第一步处理js文件,并配置编译条件。 module: { rules: [ { test: /\.js$/, include: [resolve('src'), resolve('test')], use: [ //step-2 'babel-loader?cacheDirectory', //step-1 { loader: 'js-conditional-compile-loader', options: { isDebug: process.env.NODE_ENV === 'development', // optional, this is default myFlag: process.env.ENV_COMPANY === 'ALI', // any name, used for /* IFTRUE_myFlag ...js code... FITRUE_myFlag */ } }, ] }, //other rules ]}3. 项目代码中使用插件支持IFDEBUG和IFTRUE两个条件编译指令。用法是:在js代码的任意地方以/*IFDEBUG或/*IFTRUE_xxx开头,以FIDEBUG*/或FITRUE_xxx*/结尾,中间是被包裹的js代码。xxx是在webpack中指定的条件属性名,如上面的myFlag。 举个例子,我们用这样的源代码: /* IFTRUE_forAlibaba */var aliCode = require('./ali/alibaba-business.js')aliCode.doSomething()/* FITRUE_forAlibaba */$state.go('win', {dir: menu.winId /*IFDEBUG , reload: true FIDEBUG*/})当webpack中插件的options配置为{isDebug: true, forAlibaba: true}时,构建后输出的内容: ...

August 17, 2019 · 1 min · jiezi

实现深度遍历和广度遍历

先画个树,然后解释 何为深度, 何为广度 第一层 子集 | __________________________ | | 第二层1 子集 第二层2 子集 | | ----------------- 第三层11,子集 第三层12 | 第四层111 图就不画太复杂了,最高四层的结构,如果换成html的形式的话可以理解成 <div>------第一层 <ul>----------第二层1 <li> -----------第三层 11 <span></span> -----------第四层 111 </li> <li>---------------第三层 12 </li> </ul> <p></p> ------------第一层2<div> 深度遍历,就是 从 第一层开始 -》 1 -》 11 -》111 -》 12 -》 2这个意思就是,如果有下一级优先探索下一级的,没有了话,再去探索兄弟层级(以此类推)就是做一道菜,需要菜和调料,调料是需要调制的,比如调料需要鸡汁和糖,鸡汁又需要调制,那么 正常流程 就是 ,1、开始做菜 -》 开始调料 -》 鸡汁 -》调制鸡汁的材料 2、等这些弄完了,再去加糖 ,完成调料步骤3、糖加完了,再去切菜,完成做菜步骤这个就是一个深度的过程 而广度遍历则相反, 顺序应该是 -> 1-> 2 -> 11 -> 12 -> 111 意思就是有兄弟层级优先解析兄弟层级,然后解析下一层级 ...

July 16, 2019 · 1 min · jiezi

前端知识总结

前端知识总结vuejsvue实现双向绑定原理1、Object.defineProperty()中的set/get设置属性值/获取属性值2、过程 Observer劫持并监听所有属性 发生变化,通知Dep观察者(update函数)Watcher负责向观察者列表添加对应更新函数Compile编译解析初始化/更新vue生命周期beforeCreate data和methods中的数据和方法还没初始化created data和methods初始化完成beforeMount 模板已经在内存编译好了,尚未挂载到页面mounted 页面挂载完成,可以操作DOMbeforeUpdate 页面数据是旧的,data数据是新的,页面和最新数据还没同步updated 页面和data已经保持最新beforeDestory 进入销毁阶段,data、methodes...还可用destroyed 组件已经完全销毁,data、methods以及过滤器,指令不可用vue组件通信父子通信 父组件绑定属性“:data-attr”数据子组件在props接收驼峰式dataAttr数据子与父通信 子组件$emit('to-parent',newMsg)绑定属性传输数据父组件绑定@to-parent="getChildren(e)"属性接收数据兄弟通信 在main.js建立一个Vue.prototype.bus事件总线(中间层)在borther1,this.bus.$emit('属性toborther2',值)在borther2接收,this.bus.$on('toborther2',function(val){ that.msg = val })vue的虚拟DOM虚拟DOM出现是为了减少频繁大面积的重绘引发的性能问题虚拟dom和真实dom的区别 1、虚拟dom不会排版与重绘 2、真实dom频繁排版与重绘效率相当低 3、虚拟dom进行频繁修改,然后一次性比较并修改真实dom中需要改的部分,最后并在真实dom中进行排版与重绘,减少过多dom节点排版与重绘损耗 4、虚拟dom有效降低大面积的重绘与排版,因为最终与真实dom比较差异,可以只渲染局部DOM Diff 指的是通过Diff算法去比较虚拟DOM的变化vue怎么更新节点 1、先根据真实DOM生成virtual DOM 2、当virtual DOM某个节点的数据改变后会生成一个新的Vnode 3、Vnode和oldVnode作对比,发现有不一样的就直接修改在真实的DOM,然后使oldVnode的值为Vnode路由全局路由拦截(路由守卫) router.beforeEach(( to, from, next )=>{}) //跳转前 to: 即将进入的目标(路由对象)from:当前导航正要离开的路由next()进行下一个钩子,next(false)中断当前导航,如果此时URL改变,则会重置为from后的路由地址, next('/') next(path: '/')终止当前导航,跳转到一个不同的地址,next(error)如果参数为一个error实例,则会终止导航beforeResolve(( to, from, next )=>{}) //跳转成功afterEach(( to, from, next )=>{}) //跳转后局部路由拦截 路由内部钩子: beforeEnter(( to, from, next )=>{})组件内部钩子 beforeRouteEnter(( to, from, next )=>{}) //从另外的组件进入该组件前触发该钩子beforeRouteUpdate(( to, from, next )=>{}) //同一个组件,参数不一样,不一样数据beforeRouteLeave(( to, from, next )=>{}) //该组件离开跳转到另外的组件时触发该钩子路由传参 ...

July 16, 2019 · 2 min · jiezi

字符串扩展

ES6给字符串带来了很多实用性的扩展:模板字符串,标签模板,repeat函数、includes函数,startsWith函数,endsWith函数,codePointAt函数,String.fromCodePoint函数,String.raw函数。Unicode编码的知识。 1.模板字符串//变量放入${ }即可let name = "Jacky";let occupation = "doctor";//模板字符串拼接let str = `He is ${name},he is a ${occupation}`;2.标签模板(新特性)var name = "张三";var height = 1.8;tagFn`他叫${name},身高${height}米。`;//标签+模板字符串——标签模板(新的语法规范)//定义一个函数,作为标签function tagFn(arr,v1,v2){ console.log(arr); //结果:[ "他叫",",身高","米。" ] console.log(v1); //结果:张三 console.log(v2); //结果:1.8}规律了:第一个参数arr是数组类型,它是内容是模板字符串中除了${ }以外的其他字符,按顺序组成了数组的内容,所以arr的值是[ "他叫", ",身高" , "米。" ];第2,3个参数则是模板字符串中对应次序的变量name和height的值。3.repeat函数:将目标字符串重复N次,返回一个新的字符串,不影响目标字符串。var name1 = "1"; //目标字符串var name2 = name1.repeat(3);//变量name1被重复三次;console.log(name1); //结果:1console.log(name2);//结果:1114.includes函数:判断字符串中是否含有指定的子字符串,返回true表示含有和false表示未含有。第二个参数选填,表示开始搜索的位置。var name = "123"; //目标字符串name.includes('3'); //true, 含有name.includes('4'); //false, 不含有name.includes('1',1); //false, 从第2个字符开始搜索, 不含有传统的做法我们可以借助indexOf( )函数来实现,如果含有指定的字符串,indexOf( )函数就会子字符串首次出现的位置,不含有,则返回-1。我们通过返回值是否为-1来判断字符串中是否含有指定的子字符串,但是,我们现在可以用includes( )函数代替indexOf( )函数,因为它的返回值更直观(true或false),况且我们并不关心子字符串出现的位置。注意,上面最后一句代码,第二个参数为1,表示从第2个字符“端“开始搜索,第一个字符”前“的位置是0;5.startsWith函数:判断指定的子字符串是否出现在目标字符串的开头位置,第二个参数选填,表示开始搜索的位置。var name = "123"; //目标字符串name.startsWith('1'); //true,出现在开头位置name.startsWith('2'); //false,不是在开头位置name.startsWith('2',1); //true,从第2个字符开始6.endsWith函数:判断子字符串是否出现在目标字符串的尾部位置,第二个参数选填,表示针对前N个字符。var name = "123456"; //目标字符串name.endsWith('1');//false,不在尾部位置name.endsWith('6'); //true,在尾部位置name.endsWith('6',5); //false,只针对前5个字符name.endsWith('6',6);//true,针对前6个字符7.codePointAt函数var str1 = "前端";var str2 = "????";str1.length; //length为2str2.length; //length为2str1.charAt(0); //前str1.charAt(1); //端str2.charAt(0); //'�'str2.charAt(1); //'�'=========================var str = "????";str.codePointAt(); //结果:1340718.String.fromCodePoint函数String.fromCodePoint(134071); //结果:"????"9.String.raw函数console.log(`hello\nworld`); //输出:hello worldconsole.log(String.raw`hello\nwolrd`);//输出:hello\nwolrd

July 15, 2019 · 1 min · jiezi

译ES6-模块化入门

ES6 模块系统在 ES6 之前,我们已经知道了 RequireJS,AngularJS 的依赖注入,以及 CommonJS,具体可以看笔者的上一篇文章《JS模块化历史简介》。当我们学习 ES6 的模块化,就会发现它的发展深受 CommonJS 的影响。通过这篇文章,我们将看到 export 和 import 语句,以及 ES6 模块是怎么与 CommonJS 模块兼容的。 严格模式在 ES6 模块系统中,严格模式是默认开启的。严格模式是语言从语法层面限制你使用一些不好的写法,所以它更严格(==)。它也让编译器更好地处理代码。下面是 MDN上关于严格模式的解释:严格模式 变量必须显式声明函数的形参必须有唯一的名称(否则会报语法错误)不能使用with给只读的属性赋值会报错像 00840 这样的八进制数字会报语法错误试图 delete 无法删除的属性会报错delete prop 会报语法错误,可以使用 delete global[prop]eval 不会在所在的词法作用域引入新的变量eval 和 arguments 不能被改变或赋值arguments 不会跟踪方法的参数变化arguments.callee 不再支持,会报 TypeErrorarguments.caller 不再支持,会报 TypeError传入方法内部的 this 不再被强制转换成 Objectfn.caller 和fn.arguments 不再支持保留关键字 protected,static ,interface 不能被绑定即使在 ES6 中严格默认是默认开启的,也推荐在每个模块中都使用 use strict 关键字。 让我们先来看下 export 关键字吧~ export在 CommonJS 中,导出模块可以用 module.exports 。从下面的代码可以看出,你可以导出任何值: module.exports = 1module.export = NaNmodule.exports = 'foo' module.exports = { foo: 'bar' } module.exports = ['foo', 'bar'] module.exports = function foo () {}像 CommonJS 模块一样,ES6 模块也是暴露 API 的文件。同样的,ES6 模块内部的声明只在模块内部有效。这就意味着,某个模块中的变量,如果没有被导出,在其他模块中就无法使用。 ...

July 14, 2019 · 2 min · jiezi

es6迭代器iterator和生成器generator1-什么是迭代器和生成器

我个人认为迭代器和生成器是es6新增的特性里面,非常重要的部分,充分地掌握和使用迭代器和生成器,是十分必要和重要的,所以我会写关于二者的一系列文章。话不多说,先来了解一下基本概念:一:什么是迭代器 1: 迭代器是一个对象2: 迭代器有一个属性:next()方法,它的返回值是一个对象,我姑且叫它‘next返回对象’,以便在下文使用3: ’next返回对象有2个属性:value和done4: ’next返回对象‘的value:表示迭代器的数据集里面下一个将要返回的值5: ’next返回对象‘的done:如果这轮调用next(),有数据返回,那么done为false;如果这轮调用next(),已经没有可返回的数据了,done为true,相应地value为undefined根据以上描述,我们可以用ES5的语法创建一个方法,这个方法的参数是一个数组,返回值是一个迭代器对象: function createIterator(items) { var i = 0; return { next: function () { var done = i >= items.length; var value = done ? undefined : items[i++]; return { value: value, done: done } } }}var iterator = createIterator([1, 2, 3]);console.log(iterator.next());//{value: 1, done: false}console.log(iterator.next());//{value: 2, done: false}console.log(iterator.next());//{value: 3, done: false}//没有更多可返回的值console.log(iterator.next());//{value: undefined, done: true}二:什么是生成器在上面的内容里我们了解到了什么是迭代器,并且根据迭代器的定义用es5的语法自己创建了一个生成迭代器的方法:createIterator()。在es6里面呢,我们不用再手动创建这个createIterator()方法,生成器就是用来做这个工作的。照旧,我们来看看生成器的具体定义和语法: 1: 生成器是一个函数2: 生成器返回迭代器3: function关键字后面紧挨着或者留一个空格后,必须有一个星号(*)4: 函数体里面会用到关键字yield,来依次返回想要迭代的值根据上面的定义,我们来使用生成器创建一个迭代器,取代前面的es5的语法: function* createIterator() { yield 1; yield 2; yield 3;}let iterator = createIterator();console.log(iterator.next());//{value: 1, done: false}console.log(iterator.next());//{value: 2, done: false}console.log(iterator.next());//{value: 3, done: false}//没有更多可返回的值console.log(iterator.next());//{value: undefined, done: true}以上,我们就用生成器创建了一个迭代器,生成器创建的迭代器会按照yield语句的顺序,依然返回迭代的值。当然这个例子与我们前面的es5的例子,并不是完全一样,这里我们没有传入参数,而是方法体里面写死了迭代的值。当然我们也可以传入参数: ...

July 14, 2019 · 1 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

关于varletconst

首先,分清楚js中存在两种作用域,即全局作用域和方法作用域varvar定义的变量是方法作用域,比如: function() { var str = 'I am var'; console.log(str); // I am var}console.log(str); // undefined这是在函数中,但是需要注意的是在for循环中的问题: function calcute({price: [2,4,3]}) { var totalPrice = []; for (var i = 0;i < price.length; i++) { var finallyPrice = price[i] * 2; totalPrice.push(finallyPrice); } console.log(i); // 3 console.log(price); // [2,4,3] console.log(finallyPrice); // [4,8,6];}这个函数中都能访问到i、price、finallyPrice,这是我们不期望的,这就是var方法作用域的弊端 letlet就正好解决了这个问题,它是块级作用域,即{}内可以访问 function calcute({price: [2,4,3]}) { let totalPrice = []; for (let i = 0;i < price.length; i++) { let finallyPrice = price[i] * 2; totalPrice.push(finallyPrice); } console.log(i); // i is not defined console.log(price); // [2,4,3] console.log(finallyPrice); // finallyPrice is not defined;}还需要注意的是:var定义的变量在定义之前访问是undefined,但是let定义变量在定义之前访问会报错Uncaught ReferenceError ...

July 12, 2019 · 1 min · jiezi

现代WebGIS开发教程之ES6基础2开发环境

开端 Node.js环境配置好以后,可以在命令行通过交互式方法编写代码,没有语法检查,没有提示,效率比较低,因此需要一个趁手的IDE,我不打算在这里讨论什么IDE好,高手用vim,全靠命令也比你快。我这里介绍的是WebStorm/IntelliJ的基本配置。基本操作 WebStorm/IntelliJ官网免费下载试用。地址:https://www.jetbrains.com/web... https://www.jetbrains.com/idea 下载安装后,就可以用了打开后应该长这样,中介略去初始插件配置,美化配置,授权环节若干步骤... 接下来就可以新建项目了,做开发英语是基本的素质,不要问我有没有汉化版,菜单在哪里。这货支持的项目类型挺多 我偏喜欢从头开始,项目走起 然后自己在项目下面新建一个目录,IDE在下方可以激活Terminal窗口,进入子目录,敲命令 cd path/to/dir真正的新建项目 IDE新建项目时为了方便IDE的管理,而作为Web项目,真正的管理工具是npm,在terminal中敲 npm init 在一系列提示和输入之后就完成创建了,至于提问部分:项目名,版本,简述,入口文件,测试命令,git库地址,关键词,作者,开源协议。好吧,做项目要本着开源精神。总之最后yes后面回车就ok了。再看看IDE,打开生成package.json,就是这样了,这里我删除了test命令。 接下来在目录面新建src目录,创建index.js,编写代码,可以看到有语法提示了 let result = console.log('Hello, World!');console.log(result); 配置运行 然后运行 输出的结果和上篇交互式环境中一样输出,我们可以理解为交互式环境默认都加了console.log输出语句结果,因此出现了undefined。 到目前为止只是运行,三分代码,七分调试,IDE的调试功能很重要,把代码改成 const greeting = `Hello, World!`;let result = console.log(`${greeting}`);console.log(result); 在let result = console.log(${greeting});处设置断点,点击调试按钮,弹出调试面板,程序运行到此处就会停止,可以添加监视变量,逐过程,逐语句调试,各种调试功能就出现了。 以上就是WebStorm/IntelliJ的基本操作,本篇npm创建了项目,但是运行调试还没有用上,为什么要npm配置项目呢,后面会介绍。

July 11, 2019 · 1 min · jiezi

现代WebGIS开发教程之ES6基础1环境配置1

缘起 打算开坑,这个坑是我以前想开的,因为以下几点: 学校学习偏学术,以至于到单位的新人需要从基础培养,缺少实用教材。网络的文章,不系统,以讹传讹多WebGIS开发人员很多满足于肤浅的api使用,对开发知识学习不够深入当前传统WebGIS开发人员对Web新技术了解太少 学习WebGIS第一步要打好基础,不要一开始做网页看个地图,那样虽说有了兴趣,但是头绪太多,javascript、html、css、还有各种api(openlayers、leaflet、arcgis js api、mapbox-gl),容易浮在表面api的使用忽略了设计、架构以及原理性的知识,我不希望我的组员是一名只会调用api的开发人员。因此,我想开个坑,一方面是之前学习和指导开发人员的技术总结,一方面也是给自己备份些心得。 基本环境 ES6基础系列以ES6语法和库为主,不打算和网页结合,例子以命令行为主要形式,因此本文的环境知识满足以上需求而配置 闲话休提,我们不用浏览器怎么运行javascript,就像运行java需要jre一样,我们需要一个运行时来运行javascript,这就是Node.js,相信大家都听说过这个。下载嘛https://nodejs.org/ ,懒人这个最方便,当然linux有dnf、yum啥的谁用谁知道。版本嘛LTS的技术保守点,贵在稳定,有bug会长期有人修复。Current,嗯,我这种不折腾不舒服的人最喜欢。总之看个人喜好了,安装完了咋知道,命令行很重要,在win cmd,在li terminal,在mac 嗯,还是terminal,打开后敲入命令: node -v 然后呢,看到版本号,就是装成功了 这两年的Node.js会把副产品带上,这个附产品很有用叫npm,所有的项目都是通过npm去创建的,还是在命令行,敲以下命令: npm -v 于是能看到npm的版本。 恭喜你,装好了第一句代码 环境好了,照惯例,有个Hell, World!才算是真的好,那咱们就来吧,命令行(真的很重要,bash要学好),输入命令 node 就会出现交互式界面,有提示符> 我们第一句代码就是打印Hello, World!,在提示符后敲入代码 console.log('Hello, World!'); 再看看有什么结果 嗯,确实打印了Hello, World!,完美,我学会javascript。 然鹅,你就这么忽略了后面的undefined么?相信很多人都会选择忽略。出现undefined的原因是什么呢?node交互时界面返回的是输入语句返回值,打印出Hello, World是console.log执行的操作,但是console.log的返回值是undefined,因此才会有这两行输出。 凡事不要大而化之,差不离,一定要深究,这才是学习的态度 最后退出环境,在命令行输入: .exit 如图退出 以上,各位算是javascript入门了,后面我将逐步讲解ES6的相关知识,希望大家关注。

July 11, 2019 · 1 min · jiezi

『ES6知识点总结』Promise

『ES6知识点总结』变量的解构赋值 本文主要内容如下:1 Promise是什么?1.1 特点:1.2 三种状态:1.3 用处:1.4 Promise缺点:1.5 历史过程2 生成promise实例3 promise实例的then()方法4 resolve函数的参数可以是另一个Promise实例5 Promise的方法(多种)5.1 Promise.all()5.2 Promise.race()5.3 Promise.reject(reason)5.4 Promise.resolve(obj)6 Promise.prototype.catch()的概念6.1 尽量不定义then的reject方法6.2 catch方法返回的还是一个Promise对象,因此后面还可以接着调用then方法。7 7.1 如果前面的promise和then()没有报错,则会跳过catch方法。7.2 抛错的冒泡性质7.2.1 如果Promise状态已经变成resolved,再抛出错误是无效的。7.2.2 Promise在下一轮“事件循环”再抛出错误7.2.3 如果没有处理错误的回调函数,就没有反应7.2.4 catch方法之中,还能再抛出错误。8 node.js的unhandledRejection9 done()10 finally() Promise是什么?01、是一个对象,用来传递异步操作的消息。02、代表了某个未来才会知道结果的事件(通常是一个异步操作)。03、提供一个统一的API,可以进一步处理,控制异步操作。 特点: 01、对象的状态不受外界影响。 02、代表一个异步操作。 三种状态: Pending(进行中)Resolved(已完成,又称Fulfilled)Rejected(已失败)。(1)默认的Promise对象是等待态(Pending)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“许诺”,表示其他手段无法改变。 (2)一旦状态改变了,就不会再变了,会一直保持这个结果。任何时候都可以得到这个结果。 Promise对象的状态改变,只有两种: 从Pending变为Resolved。从Pending变为Rejected。这与事件(Event)不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。 用处:用Promise对象可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。可以判断多个异步事件的完成, Promise缺点:无法取消Promise,一旦新建它就会立即执行,无法中途取消。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 历史过程 生成promise实例Promise是一个构造函数,可以生成Promise实例。 接受一个函数A作为参数,该函数A有2个参数,是resolve和reject(拒绝),它们是函数,由JS引擎提供,不用自己部署。 resolve(value)函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操作成功时被调用,并将异步操作的结果,作为自己的参数。 reject(error)函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为自己的参数。 reject函数的参数通常是Error对象的实例,表示抛出的错误。 例子:reject(new Error(this.statusText)); 在promise实例的构造函数中,可以只返回resolve(value)或reject(error);例子:let pro = new Promise((resolve,reject)=>{resolve(value)}); 写法:创造了一个Promise实例。 const promise = new Promise(function(resolve, reject) { if ( /* 异步操作成功 */ ) { resolve(value); } else { reject(error); }});promise实例的then()方法这个方法在实例的状态改变时会触发它的参数函数。当promise实例转为成功(Resolved)状态时,触发then()的第一个函数参数。当promise实例转为失败(Rejected)状态时,触发then()的第二个函数参数。(第二个函数参数可选) ...

July 10, 2019 · 4 min · jiezi

Vue-项目功能实现router-传递参数并解决刷新页面参数丢失问题

Vue Router 传参方式:1. this.$router.push({ name: '模块名称', params: { // 各参数 } })router.js:export default new Router({ routes: [ { path: '/paramsPassingByRouter', component: ParamsPassingByRouter, children: [ { path: 'paramsMode', name: 'paramsMode', component: ParamsMode } ] } ]})ParamsPassingByRouter.vue:<!-- html --><button @click="paramsMode(testData)">params传参</button><!-- js --><script>export default { data () { return { testData: { id: '20180101', name: '张三', aka: 'z3', age: '18' } } }, methods: { paramsMode (data) { this.$router.push({ name: 'paramsMode', params: this.testData }) } }}</script>ParamsMode.vue:<!-- html --><div class="params-mode">{{ testData }}</div><!-- js --><script>export default { data () { return { testData: {} } }, created () { this.testData = this.$route.params }}</script>效果:url:http://localhost:8081/#/paramsPassingByRouter/paramsMode 页面显示:{"id":"20180101","name":"张三","aka":"z3","age":"18"} ...

July 8, 2019 · 2 min · jiezi

JS基础Proxy

Proxy 用于修改某些操作的默认行为(基本操作有属性查找,赋值,枚举,函数调用等)。 /** target 目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)* handler 一个对象,其属性是操作对应的自定义代理函数*/let p = new Proxy(target, handler);基本操作1、get(target, propKey, receiver):拦截对象属性的读取 /** target 目标对象* propKey 对象属性名* proxy 实例本身(严格地说,是操作行为所针对的对象)*/get(target, propKey, receiver)var obj = {name : 'Lucy'}var p = new Proxy(obj,{ get : function(target,key,receive){ return key === 'name' ? 'Hello '+target[key] : target[key] }})p.name //Hello Lucy需要注意的是,如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性。 var obj = Object.defineProperties({}, { name: { value: 'Lucy', writable: false, configurable: false },});var p = new Proxy(obj, { get : function(target,key){ return key === 'name' ? 'Hello '+target[key] : target[key] }});p.name //报错2、set: function(obj, prop, value,receive) : 拦截某个属性的赋值操作 ...

July 5, 2019 · 2 min · jiezi

ES6知识拾遗再读ES6入门书籍总汇

1.var,let,const区别 答:(1).var有变量声明提升,let&&const没有,这样导致了let,const必须声明后才可以访问使用(tdz) => 暂时性死区”也意味着typeof不再是一个百分之百安全的操作,如果一个变量没有被声明,使用typeof反而不会报错(值会变为'undefined')(没有遇到let/const),(2)var,let可以在定义后重新赋值,const是个常量,它不可以(但是如果他是复杂数据类型,改变它的属性值是没问题的,与定义概念并不冲突),(3).var可以重复声明,取值去最后的声明,let不允许在相同作用域内,重复声明同一个变量,(3).块状作用域 => {}这句话有异议,但是说的很有道理,块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。Object.freeze({}); => 冻结对象,(4).未定义就声明的变量会默认为window全局的变量,var的变量都归window所有,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性即不会归window所有 总结:es6的六种声明变量 => var let const function import class 注意:在浏览器环境指的是window对象,在 Node 指的是global对象。2.变量的解构赋值 => es6允许一定的模式,从数组中和对象中提取,对变量进行赋值,这被称为解构 => 只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值,如果解构失败,变量的值等于 undefined(1).数组的模式匹配 模式匹配”,只要等号两边的模式相同(数据结构),左边的变量就会被赋予对应的值 let [a, b, c] = [1, 2, 3](2).对象的解构赋值 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的 属性没有次序,变量必须与属性同名,才能取到正确的值 let {foo, too} = {foo: 'foo', too: 'too'}(3).字符串的解构赋值 字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象3.模板字符串 `${变量1},{变量2}` => `${fn()}` {}最终会调用toString的方法,可嵌套4.字符串扩展

July 4, 2019 · 1 min · jiezi

Objectentries

1.什么是entryentries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。 2.示例Object.entries() 传入对象 const obj = { foo: 'bar', baz: 42 };Object.entries(obj)//输出 [ ["foo", "bar"], ["baz", 42] ]Array.entries() 传入数组 const arr = ['a', 'b', 'c']; console.log(Object.entries(arr)); // [[ '0', 'a' ], [ '1', 'b' ], [ '2', 'c' ] ]const arr1 = [{ a: 1 }, 2, 3]; console.log(Object.entries(arr1)); // [['0', { a: 1 }], ['1', '2'], ['2', '3']]const arr2 = [{ a: 1 }, { b: 2 }, { c: 3 }]; console.log(Object.entries(arr2)); // [['0', { a: 1 }], ['1', { b: 2 }], ['2', { c: 3 }]]将 Object 转化为 Mapnew Map() 构造函数接受一个可迭代的 entries 。 借助 Object.entries 方法你可以很容易的将 Object 转换为 Map: ...

July 4, 2019 · 2 min · jiezi

JS引擎它们是如何工作的从调用堆栈到Promise需要知道的所有内容

为了保证可读性,本文采用意译而非直译。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 有没有想过浏览器如何读取和运行JS代码? 这看起来很神奇,我们可以通过浏览器提供的控制台来了解背后的一些原理。 在Chrome中打开浏览器控制台,然后查看Sources这栏,在右侧可以到一个 Call Stack 盒子。 JS 引擎是一个可以编译和解释我们的JS代码强大的组件。 最受欢迎的JS 引擎是V8,由 Google Chrome 和 Node.j s使用,SpiderMonkey 用于Firefox,以及Safari/WebKit使用的 JavaScriptCore。 虽然现在 JS 引擎不是帮我们处理全面的工作。但是每个引擎中都有一些较小的组件为我们做繁琐的的工作。 其中一个组件是调用堆栈(Call Stack),与全局内存和执行上下文一起运行我们的代码。 Js 引擎和全局内存(Global Memory)JavaScript 是编译语言同时也是解释语言。信不信由你,JS 引擎在执行代码之前只需要几微秒就能编译代码。 这听起来很神奇,对吧?这种神奇的功能称为JIT(及时编译)。这个是一个很大的话题,一本书都不足以描述JIT是如何工作的。但现在,我们午饭可以跳过编译背后的理论,将重点放在执行阶段,尽管如此,这仍然很有趣。 考虑以下代码: var num = 2;function pow(num) { return num * num;}如果问你如何在浏览器中处理上述代码? 你会说些什么? 你可能会说“浏览器读取代码”或“浏览器执行代码”。 现实比这更微妙。首先,读取这段代码的不是浏览器,是JS引擎。JS引擎读取代码,一旦遇到第一行,就会将几个引用放入全局内存。 全局内存(也称为堆)JS引擎保存变量和函数声明的地方。因此,回到上面示例,当 JS引擎读取上面的代码时,全局内存中放入了两个绑定。 即使示例只有变量和函数,也要考虑你的JS代码在更大的环境中运行:在浏览器中或在Node.js中。 在这些环境中,有许多预定义的函数和变量,称为全局变量。 全球记忆将比num和pow更多。 上例中,没有执行任何操作,但是如果我们像这样运行函数会怎么样呢: var num = 2;function pow(num) { return num * num;}pow(num);现在事情变得有趣了。当函数被调用时,JavaScript引擎会为全局执行上下文和调用栈腾出空间。 JS引擎:它们是如何工作的? 全局执行上下文和调用堆栈刚刚了解了 JS引擎如何读取变量和函数声明,它们最终被放入了全局内存(堆)中。 但现在我们执行了一个JS函数,JS引擎必须处理它。怎么做?每个JS引擎中都有一个基本组件,叫调用堆栈。 ...

July 1, 2019 · 3 min · jiezi

Nodejs中的ES模块现状

作者:Tobias Nießen翻译:疯狂的技术宅 原文:https://jaxenter.com/es-modul... 未经允许严禁转载 几乎每种编程语言都能将组成程序的代码拆分为多个文件。 在 C 和 C++ 中 #include 指令就用于这个目的,而 Java 和 Python 有 import 关键字。 JavaScript 是迄今为止为数不多的例外之一,但新的 JavaScript 标准(ECMAScript 6)通过引入所谓的 ECMAScript 模块来改变这一点。所有主流浏览器都支持这个新标准 —— 只有 Node.js 似乎落后了。这是为什么?新的 ECMAScript(ES)模块与以前的语言版本不完全兼容,因此使用的 JavaScript 引擎需要知道每一个文件是“旧” JavaScript 代码还是“新”模块。 例如在 ECMAScript 5 中引入的许多程序员首选的严格模式曾经是可选的,必须明确启用才行,同时它在 ES 模块中始终处于活动状态。因此,以下代码段在语法上可以解释为传统的 JavaScript 代码和 ES 模块: a = 5;作为经典的 Node.js 模块,这相当于 global.a = 5,因为未声明变量 a 并且未明确激活严格模式,因此 a 被视为全局变量。如果你尝试加载与 ES 模块相同的文件,则会收到错误 “ReferenceError:a is not defined”,因为未声明的变量可能无法在严格模式下使用。 浏览器通过<script> 标记的扩展解决了区别问题:没有 type 属性或带有 type="text/javascript" 属性的脚本仍然在传统模式下运行,而当脚本使用 type ="module" 属性时则作为模块处理。由于这种简单的分离,现在所有流行的浏览器都支持新的模块。 Node.js 中的实现要困难得多:2009年发明的 JavaScript 应用程序框架使用 CommonJS 标准模块,该标准基于 require 函数。此函数可以随时根据其相对于当前运行模块的路径加载另一个模块。新的 ES 模块也是由它们的路径定义的,但是 Node.js 是如何知道正在加载的模块是遗留的 CommonJS 还是 ES 模块的呢?仅仅基于语法是不够的,因为即使不使用新关键字的 ES 模块也不兼容CommonJS模块。 ...

June 28, 2019 · 3 min · jiezi

浅析promise与自定义promise

promise的用法简单介绍一下,我觉得如果有人愿意看这篇文章,对promise的用法多多少少也了解; new Promise((res, rej) => { try{ 执行函数; res(data) } catch(e){ rej(e); }}).then(resCb, rejCb).then(cb);心血来潮,今天去自己试着写了一下promise。先说下我个人对promise的理解 1.promise 从表现形式上看,是将执行函数的返回值通过resolve或者reject 抛出data,再在then 函数里面处理data2.promise 可以链式调用then,上一个then的返回值作为下一个then中函数的实参 但实际上,promise 并非一定是在then 里面执行的,尤其是异步的时候,理应在实例函数中执行,才符合我们对单线程的理解。 promise简单点说分为两部分。一个是实例化 时候,传入的执行函数, 另一部分为then中传入的回调函数 这个关系就好比 监考老师 和 学生如果监考老师 先到了教室,那么自然而然,学生是直接依次进入教室;(实例函数执行较快,超过了then的声明)如果监考老师 在学生们后面到,那么学生们只能按顺序排队在门口等监考老师;(实例函数执行较慢)也就是说,执行函数和then函数的声明,先后顺序并非固定(一般情况下then声明先完成)这个时候就需要一个状态码去判断到底是哪种情况('default', 'resolve' ,'reject')为了方便理解,可以把resolve 和 reject看成同一类型我先直接发代码写注释时间有限,本次先不考虑then 中函数 存在异步的问题 // 简述下逻辑: //1.定义一个state 是用来判断then 和 实例化时候传入的函数 哪一个先完成 //也就是刚刚说的监考老师和学生的问题。默认值为default, 默认老师没到(实例函数未执行完成) //2.定义resolve_ 用来存放then 中定义的方法,相当于学生排队的过道,便于按顺序执行,reject_同理,以下不再重复 //3.定义resolveData用来记录抛出值,也就是res(data) 中的data,作为then中方法的参数 //4.在res抛出值的时候,将state改成resolve,相当于表明监考老师到教室了 //如果resolve_队列中已经有定义函数就依次执行它们,相当于如果有学生就进教室。 //5.then 方法声明时候,检测状态state 是不是 default ,如果是,说明还没有抛出值, //相当于监考老师还没到,学生都去排队,加入到resolve_队列; //如果状态已经不是default ,那么说明监考老师已经到了,学生不用排队,直接进教室;也就是方法直接执行 new promise_( (res, rej) => res(3)).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6针对实际例子说一下上面的例子明显就是 res(3) 先执行完成,然后执行then 的函数相当于监考老师先到了教室,那么,then 中的定义的函数就应该直接执行 ...

June 28, 2019 · 2 min · jiezi

es6之class类的理解

传统的javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。这样的写法相对于其他传统面向对象语言来讲,很有一种独树一帜的感觉,非常容易让人困惑!如果要生成一个对象实例,需要先定义一个构造函数,然后通过new操作符来完成。构造函数示例: //函数名和实例化构造名相同且大写(非强制,但这么写有助于区分构造函数和普通函数)function Person(name,age){ this.name = name this.age = age}Person.prototype.say = function(){ return "我的名字叫"+this.name+"今年"+this.age+"岁了"}var obj = new Person("hebei",23) //通过构造函数创建对象,必须使用new运算符console.log(obj.say())//我的名字叫hebei今年23岁了构造函数生成实例的执行过程: 1、当使用了构造函数,并且new 构造函数(),后台会隐式执行new Object()创建对象2、将构造函数的作用域给新对象,即 new Object()创建出来的对象,而函数体内的this就代表new Object()出来的对象3、执行构造函数的代码4、返回新对象(后台直接返回)es6引入了Class(类)这个概念,通过class关键字可以定义类。该关键字的出现使得其在对象写法上更加清晰,更像是一种面向对象的语音。如果将之前的代码该写文es6的写法就会是这样子: class Person{ //定义了一个名字为Person的类 constructor(name,age){ //constructor是一个构造方法,用来接收参数 this.name = name this.age = age } say(){// 这是一个类的方法,注意千万不要加上function return "我的名字叫"+this.name+"今年"+this.age+"岁了" }}var obj = new Person("hebei",23)console.log(obj.say())//我的名字叫hebei今年23岁了注意项:1、在类中声明方法的时候,千万不要给该方法加上function关键字2、方法之间不要用逗号分隔,否则会报错 由下面代码可以看出类实质上就是一个函数。类自身指向的就是构造函数。所以可以认为es6中的类其实就是构造函数的另外一种写法! console.log(typeof Person)//functionconsole.log(Person === Person.prototype.constructor)//true以上代码说明构造函数的prototype属性,在es6的类中依然存在着实际上类的所有方法都定义在类的prototype属性上。代码证明下: Person.prototype.say=function(){//定义与类中相同名字的方法,成功实现了覆盖! return "我是来证明的,你叫"+this.name+"今年"+this.age+"岁了"}var obj = new Person("hebei",23)console.log(obj.say())//我是来证明的,你叫hebei今年23岁了当然也可以通过prototype属性对类添加方法。如下: Person.prototype.addFn = function (){ return "我是通过prototype新增加的方法,名字叫做addFn"}var obj = new Person("hebei",23)console.log(obj.addFn())//我是通过prototype新增加的方法,名字叫做hebei还可以通过Object.assign方法来为对象动态增加方法 ...

June 27, 2019 · 1 min · jiezi

前端小知识10点2019625

前言:这里记录我工作、学习中值得注意的小知识点,希望对你有所帮助。 1、 moment.js将某年某周转为具体日期 举例:将2019年第二周转为具体日期 <script src="moment.js"></script><script> const year=2019 const week=2 const start = moment() //年 .year(year) //周 .week(week) //周一 .isoWeekday(1) //日期格式 .format('M.D'); const end = moment() .year(year) .week(week) .isoWeekday(7) .format('M.D'); //2019第2周 //(1.7-1.13) console.log(`${year}第${week}周\n(${start}-${end})`) </script>(1)关于ISO 8601时间标准对周的定义,请参考:ISO 8601中周数的处理及 Joda-Time 的使用 (2)moment.js将某年某周转化为具体日期的方法,请参考:http://momentjs.cn/docs/#/get-set/iso-weekday/ 2、IE11导出excel表格和图片(兼容性) 导出 excel: const fileData = ['' + ('<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-mic' + 'rosoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta cha' + 'rset="UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:Exce' + 'lWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/>' + '</x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></' + 'xml><![endif]--></head><body>') + a.outerHTML + '</body></html>'];const blobObject = new Blob(fileData);window.navigator.msSaveOrOpenBlob(blobObject, `${tableTitle}.xls`);说明:a.outerHTML是<table id='a'>的outerHTML ...

June 26, 2019 · 2 min · jiezi

asyncawait详解

1、简介需先了解 Promise 【链接地址】JavaScript 中的异步函数方法。JavaScript 在很短的时间内从回调演变为 Promises ,从 ES2017(ES8) 开始,使用 async/await 语法让异步 JavaScript 变得更简单。async(异步) 函数是 promises 和 generator 的组合,基本上,它们是对 promises 的更高级别的抽象。注意:async/await 基于 promises。2、引入 async/await 的原因它们降低了 promises 对一些固定语法样板的要求,打破了链式 promise “不能切断链式”的限制。在 ES2015 中引入 Promise 时,它们旨在解决异步代码的问题,并且他们确实做到了,但在 ES2015 和 ES2017 的两年中,人们发现很明显 promises 不是最终的解决方案。引入 Promises 来解决著名的回调地狱问题,但是因为他们自身的复杂性,引入了更复杂的语法。它们是良好的原语,可以向开发人员公开更好的语法,所以当时机成熟时,我们就有了 异步函数(async functions)。它们使代码看起来像是同步,但它在后台是异步和非阻塞的。2、原理async(异步) 函数返回一个 promise,如下例1所示: const doSomethingAsync = () => { return new Promise((resolve) => { setTimeout(() => resolve('I did something'), 3000) }) }3、未写完,待续

June 21, 2019 · 1 min · jiezi

es6三个点扩展spread运算符和rest运算符

扩展运算符对象中的扩展运算符用于取出参数对象中的所有可遍历属性,拷贝到当前对象中。let value={a:1,b:2};let value1={...value} 等价于: let value={a:1,b:2};let value1=Object.assign({},value) (拷贝的是原对象的引用,原对象改变时,拷贝对象也会改变) 扩展运算符运用: 1. 将数组转换为参数序列add=(x,y)=>{return x+y} const num=[1,2]add(...num) 2. 复制数组const arr1=[1,2]const arr2=[...arr] 3.扩展运算符可以把字符串转换成数组[...'hello']// [ "h", "e", "l", "l", "o" ] rest运算符与应用rest运算符与扩展运算符作用相反,把逗号隔开的值序列拼成一个数组 1.利用结构合成数组,代替push将一个数组添加到另一个数组的尾部 但是rest运算符用于生成数组只能是参数的最后一位const [...rest, last] = [1, 2, 3, 4, 5];// 报错const [first, ...rest, last] = [1, 2, 3, 4, 5];// 报错 总结:等号左边是rest运算符,等号右边是扩展运算符

June 20, 2019 · 1 min · jiezi

箭头函数的写法特点

1、箭头函数简介用 => 来标识箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。2、通常函数的定义方法var fn1 = function(a, b){ console.log(a + b);};fn1(1, 2); // 3function fn2(a, b){ console.log(a - b);}fn2(2, 1);//13、简写写法对应上面两个//删掉了functionvar fn11 = (a, b)=>{ console.log(a+b);};fn11(1, 2); // 3//删掉了function和函数名,无意义(a,b)=>{ console.log(a-b)}4、基础语法附加规则 当函数参数只有一个时,可省略小括号,但没有时,不能省略。函数体(中括号)中有且只有一行return语句时,中括号和return关键字可以省略。函数返回json对象,且只有一行return语句时,返回的简写要加小括号;如let add = a =>({"a":2}) (参数1, 参数2, …, 参数N) => { 函数声明 } //相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; } (参数1, 参数2, …, 参数N) => 表达式(单一) // 当只有一个参数时,圆括号是可选的: (单一参数) => {函数声明} 单一参数 => {函数声明} // 没有参数的函数应该写成一对圆括号。 () => {函数声明} var add = function(a,b){ return a+b; }; // 即: var add = (a,b)=>{ return a+b }; // 即: var add = (a,b)=>a+b; --------------------------------------------------------------------------------------- var ret = function(a){ return a+1; }; // 即: var ret = a=>a+1; --------------------------------------------------------------------------------------- var non = function(){ return 2+1; }; // 即 var non = ()=>2+1; 函数体代码多于一行 let fun1 = function(){ console.log('1'); console.log('2'); return 1+2; } fun1(); // 简写为 let fun2 = ()=>{ console.log('1'); console.log('2'); return 1+2 } fun2(); 函数返回json对象时 let f1 = function(){ return {"a":2}; } let f2 = ()=>{"a":2} // 错误 let f2 = ()=>({"a":2}) 如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错: x => { foo: x } 因为和函数体的{ ... }有语法冲突,所以要改为: // ok: x => ({ foo: x }) 实例 let arr1 = [9,6,1,7]; let arr11 = arr1.sort( function(a,b){ return a-b; } ) console.log(arr11); let arr3= [2,3,9,5]; let arr33 = arr3.sort((a,b)=>a-b) console.log(arr33)5、总结箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。箭头函数写代码拥有更加简洁的语法。不会绑定this,或者说箭头函数中 不会改变this本来的绑定。

June 19, 2019 · 1 min · jiezi

手写一个符合promiseA规范的promise库

promsie使用及原理 / 手写一个符合promise/A+规范的promisepromise使用及原理分析:通过new关键字创建promise实例, 接受一个executor参数, executor方法返回两个方法 resolve, reject, 可用通过在executor方法中通过调用resolve(使成功)或调用reject(使失败),来控制promise状态let p = new Promise((resolve, reject) => { resolve(100)})executor中可以执行同步代码也可以执行异步代码let p = new Promise((resolve, reject) => { setTimeout(() => { resolve(100) })})promise原型对象上有then方法供promise实例调用, then方法接受两个参数onFulfilled, onRejectedonFulfilled默认为一个函数 data => dataonRejected默认为一个函数 err => {throw err}当promise状态为fulfilled时, 执行用户传入的onFulfilled方法当promise状态为rejected时, 执行用户传入的onRected方法当用户创建promise对象时采用异步,那么执行then方法时没有调用resolve方法或reject方法,所以promise状态依然为pending状态,所以需要在then方法中采取发布订阅模式,先保存then方法传来的onFulfilled和onReje又因为同一个promise实例可以调用多次then方法,从而传多个onFulfilled和onRected,所以发布订阅采用数组保存onFulfilled和onRejected方法中可能throw Error, 所以在执行onFulfilled和onRejected时需要try catch捕获then方法返回一个新的Promise实现链式编程统一判断then方法传入的onFulfilled方法和onRejected方法中return的类型(resolvePromise)p.then(data => { console.log(data)}, err => { console.log(err)})let p1 = p.then(data => { return p1 // 报类型错误})p.then(data => { return new Promise((resolve, reject) => { resolve(100) })})catch方法接受一个错误回调,可以用then方法实现(语法糖)ES2018 中新增finally方法 也可以通过then方法实现(语法糖) finally要实现值得穿透, finally前如果有then方法,其返回值要穿过finally方法传给之后的thenp.then(data => { return 100}).finally(() => { console.log('finally')}).then(data => { console.log(data) // 100})all, race 方法都接受一个promise数组all方法要所有promise都返回才resolve一个全部是成功态的数组,只要有一个rejected就直接rejectrace方法只要有一个promise resolve就直接resolve完整代码如下:class Promise { constructor(executor) { this.status = Promise.PENDING this.value = undefined this.reason = undefined // 发布订阅的存储器onResolvedCallbacks, onRejectedCallbacks this.onResolvedCallbacks = [] this.onRejectedCallbacks = [] this.initBind() this.init(executor) } initBind() { this.resolve = this.resolve.bind(this) this.reject = this.reject.bind(this) } init(executor) { // 防止executor中抛错 try { executor(this.resolve, this.reject) } catch (e) { this.reject(e) } } resolve(data) { // 如果resolve中传入一个promise, 那么返回改promise结果 if (data instanceof Promise) data.then(this.resolve, this.reject) if (this.status === Promise.PENDING) { this.status = Promise.FULFILLED this.value = data this.onResolvedCallbacks.forEach(fn => fn()) } } reject(reason) { if (this.status === Promise.PENDING) { this.status = Promise.REJECTED this.reason = reason this.onRejectedCallbacks.forEach(fn => fn()) } } then(onFulfilled, onRejected) { const fulfilledHandle = (resolve, reject) => { // 此处用setTimeout异步才能拿到promise2 setTimeout(() => { try { let x = onFulfilled(this.value) Promise.resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } const rejectHandle = (resolve, reject) => { setTimeout(() => { try { let x = onRejected(this.reason) Promise.resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } // onFulfilled和onRejected定义默认值 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } let promise2 = new Promise((resolve, reject) => { if (this.status === Promise.FULFILLED) { fulfilledHandle(resolve, reject) } if (this.status === Promise.REJECTED) { rejectHandle(resolve, reject) } if (this.status === Promise.PENDING) { this.onResolvedCallbacks.push(() => { fulfilledHandle(resolve, reject) }) this.onRejectedCallbacks.push(() => { rejectHandle(resolve, reject) }) } }) // 返回一个新的promise return promise2 } catch (onRejected) { return this.then(null, onRejected) } static resolve() { return new Promise((resolve, reject) => { resolve() }) } static reject() { return new Promise((resolve, reject) => { reject() }) } finally(callback) { return this.then( data => Promise.resolve(callback()).then(() => data), err => Promise.resolve(callback()).then(() => { throw err }) ) } static all(promises) { return new Promise((resolve, reject) => { let result = [] let count = 0 const setResult = (key, value) => { result[key] = value if (++count === promises.length) { resolve(result) } } for (let i = 0; i < promises.length; i++) { let current = promises[i] if (Promise.isPromise(current)) { current.then(data => { setResult(i, data) }, reject) } else { setResult(i, current) } } }) } static race(promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { let current = promises[i] if (Promise.isPromise(current)) { current.then(resolve, reject) } else { resolve(current) } } }) }}Promise.PENDING = 'pending'Promise.FULFILLED = 'fulfilled'Promise.REJECTED = 'rejected'Promise.resolvePromise = (promise2, x, resolve, reject) => { // called防止他人的promise即执行resolve又执行 reject let called if (promise2 === x) throw new TypeError('xxx') if (typeof x === 'function' || typeof x === 'object' && x !== null) { try { let then = x.then if (typeof then === 'function') { then.call(x, y => { if (called) return called = true // 递归解析,总有一个结果then方法返回一个普通值 Promise.resolvePromise(promise2, y, resolve, reject) }, e => { if (called) return called = true reject(e) }) } else { resolve(x) } } catch (e) { if (called) return called = true reject(e) } } else { resolve(x) }}Promise.isPromise = (obj) => { return typeof obj === 'function' || typeof obj === 'object' && obj !== null && obj.then && typeof obj.then === 'function'}// 延迟对象Promise.deferred = () => { const defer = {} defer.promise = new Promise((resolve, reject) => { defer.resolve = resolve defer.reject = reject }) return defer}module.exports = Promise

June 17, 2019 · 3 min · jiezi

es6-rest参数和扩展运算符

ES6引入了rest参数(形式为“…变量名”)。其中rest参数搭配的变量是一个数组可以使用数组的一切操作。 ES6的扩展运算符则可以看作是rest参数的逆运算。可以将数组转化为参数列表。 扩展运算和rest参数注意对于三个点号...,三点放在形参或者等号左边为rest运算符; 放在实参或者等号右边为spread运算符,或者说,放在被赋值一方为rest运算符,放在赋值一方为扩展运算符。

June 17, 2019 · 1 min · jiezi

从webpack初始化到配置babel环境

一、新建项目文件夹,在文件夹打开终端运行npm init,一直回车二、安装babel所需要的包 npm install --save-dev @babel/core @babel/cli @babel/preset-envnpm install --save @babel/polyfill三、根目录下新建babel.config.js,填入: const presets = [ [ "@babel/env", { targets: { edge: "17", firefox: "60", chrome: "67", safari: "11.1", }, useBuiltIns: "usage", }, ],];module.exports = { presets };四、根目录下新建webpack.config.js,填入: const path = require('path');module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, mode: 'development'};五、执行,安装webpack,根据提示安装webpack-cli npm install webpack --save-dev 六、修改packge.json,script填入 "build": "webpack"七、命令行运行,npm run build

June 13, 2019 · 1 min · jiezi

解决vue项目在IE浏览器运行打开空白使用babelpolyfilll把ES6转ES5

IE的话一般需要将ES6转ES5。下面转换方法:需要安装babel-polyfill npm install --save babel-polyfill然后在main.js引入该插件 最后需要在webpack配置入口即可 app: ['babel-polyfill', './src/main.js'] 最后,重启一下项目 npm run dev

June 13, 2019 · 1 min · jiezi

JavaScript-的简洁之道

为了保证可读性,本文采用的音译而非直意。 简介如果你关注代码本身和代码的编写方式,而不是只关心它是否能工作,那么你写代码是有一定的水准。专业开发人员将为未来的自己和“其他人”编写代码,而不仅仅只编写当前能工作就行的代码。 在此基础上,简洁代码可以定义为自解释的、易于人理解的、易于更改或扩展的代码。 以下列表一些好编写方式,仅供参考,当然,如果你有更好的方式,欢迎留言。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 1. 强类型检查用===代替 == // 如果处理不当,它会极大地影响程序逻辑。这就像,你想向左走,但由于某种原因,你向右走0 == false // true0 === false // false2 == "2" // true2 === "2" // false// 例子const value = "500";if (value === 500) { console.log(value); // 条件不成立,不会进入}if (value === "500") { console.log(value); // 条件成立,会进入}2.变量用知名其意的方式为变量命名,通过这种方式,当一个人看到它们时,易于搜索和理解。 不好的方式: let daysSLV = 10;let y = new Date().getFullYear();let ok;if (user.age > 30) { ok = true;}好的方式: const MAX_AGE = 30;let daysSinceLastVisit = 10;let currentYear = new Date().getFullYear();...const isUserOlderThanAllowed = user.age > MAX_AGE;不要在变量名中添加额外的不需要的单词。 ...

June 10, 2019 · 4 min · jiezi

ES6-项目综合实战完结篇

上一篇通过TodoList的练习,目的是为了让大家理解ES6中各种新特性的实际用途。 最好的学习方法就是实践,所以这节课结合实际项目,来更好的理解和掌握ES6的用途和使用场景,达到灵活运用的目的。 1、模块化 以项目中普遍会有的config.js文件为例,实现export导出: const githubURL = "OUR GITHUB URL HERE";const staticServer = "http://xxx.com";const testsPath = `zaz-${type}-${name}/tests/index.htm?zaz[env]=tests`;const name = "stalker";const type = "mod";const version = "0.0.1";const state = "ok";const description = "JavaScript API to deal with user data";let globalpkg = null; const config = { _static: { name, version, state, description, docs: `${githubURL}/pages/terra/zaz-${type}-${name}`, source: `${githubURL}/Terra/zaz-${type}-${name}`, tests: `${staticServer}/fe/${testsPath}`, dependencies: ['mod.wilson'] }};export default config;再在其他文件中通过import实现导入: import config from './config';//导入ES6模块import { globalpkg } from './config';import factory from './factory'; zaz.use((pkg) => { "use strict"; config.dynamic.globalpkg = pkg; pkg.require(['modFactory'], (modFactory) => { modFactory.create(pkg.utils.deepMerge(config._static, factory)); }); });使用ES6统一的模块化规范,可以提高代码的可读性,更易于维护。 ...

June 9, 2019 · 5 min · jiezi