We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ES6 笔记一
思维导图
基本用法
function log(x, y='Worlds'){ console.log(x,y) } log('Hello'); // Hello, World function Poin(x=0,y=0){ this.x = x; this.y = y; } var p = new Point(); p // {x:0, y:0}
参数变量是默认声明的,不能用 let const 再次声明
let
const
function foo(x = 1){ let x = 2; // error const x = 3; // error }
与解构赋值默认值结合使用
function fetch(url, {method='GET'}={}){ console.log(method) } fetch('/index.html') // 'GET' function m({x=0,y=0}={}){ console.log([x,y]) } m() // [0,0] m({x:1, y:2}) // [1,2] m({x:3}) // [3,0] m({}) // [0,0] m({xx:1}) // [0,0]
参数默认值位置
通常把函数的尾参数作为有默认值的参数。因为这样比较容易看出到底忽略那些参数。
function f(x,y=1,z){ console.log([x,y,z]) } f() // [undefined, 1, undefined] f(1) // [1, 1, undefined] f(1,,2) // 出错 f(1,undefined,3) // [1, 1, 3]
上面的函数,有默认值的参数不是尾参数,因此无法省略该参数而不省略其后的参数,除非显式的输入 undefined
函数length属性
length
指定了默认值后函数的 length 属性将返回没有指定默认值的参数个数
(function(a){}).length // 1 (function(a,b,c=1){}).length //2
PS: rest参数不会计入 length 属性
作用域
如果参数默认值是一个变量,则该变量所处的作用域与其它变量的作用域规则是一样的,即先是当前函数的作用域,然后才是全局作用域。
var x = 1; function f(x, y=x){ console.log(y) } f(2) // 2
由于函数作用域内部的变量 x 已经生成所以 y 等于参数 x 而不是全局变量x。
let x = 1; function f(y=x){ let x= 2; console.log(y) } f() // 1
上述代码函数调用时 y 的默认值变量 x 尚未在函数内部生成,所以 x 指向全局变量。
如果函数A的默认值是函数B 那么由于函数的作用域是其声明时的作用域,函数B的作用域就不是函数A,而是全局作用域。如下:
let foo = 'outer'; function bar(func = x => foo){ let foo = 'inner'; console.log(func()); } bar(); // outer
上述代码等同于
let foo = 'outer'; let f = x => foo; function bar(func = f) { let foo = 'inner'; console.log(func()); } bar(); // outer
关于babel的一个bug
应用
可指定函数某一个参数不得省略,省略就会抛出错误
function throwIfMissing() { throw new Error('Missing parameter'); } function foo(mustBeProvided = throwIfMissing()) { return mustBeProvided; } foo() // Error: Missing parameter
上述代码可知参数 mustBeProvided 的默认值等于 throwIfMissing 函数的运行结果。这说明函数参数的默认值不是在定义时执行,而是在运行时执行。
mustBeProvided
throwIfMissing
如果把函数参数默认值设置为 undefined 则表示这个参数是可以省略的。
undefined
rest参数("...变量名"),用于获取函数的多余参数。rest参数搭配的变量是一个数组,该变量将多余的参数放入其中。
function push(array, ...items){ items.forEach(item => { array.push(item); }) } var a = []; push(a,1,2,3)
rest 参数只能作为最后一参数。
函数的 length 属性不包括 rest 参数。
(function(...a){}).length // 0 (function(a, ...b){}).length // 1
含义
扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。
console.log(...[1,2,3]) // 1 2 3 console.log(1, ...[2,3,4], 5) // 1 2 3 4 5
该运算符主要用于函数的调用
function add(x,y){ console.log(x+y); } var arr = [1,10]; add(...arr); // 11 ...运算符把arr数组变为参数序列
替代数组的 apply 方法
由于扩展运算符可以展开数组,所以不需要apply将数组转为函数的参数了。
// ES5 function f(x,y,z){} var args = [1,2,3]; f.apply(null, args)
// ES6 function f(x,y,z){} var args = [1,2,3]; f(...args)
使用 Math.max 求数组最大元素
Math.max
// ES5 Math.max.apply(null, [1,2,3,4])
// ES6 Math.max(null, ...[1,2,3,4])
通过 push 将一个数组添加到另一数组尾部
// ES5 var arr1 = [0,1,2]; var arr2 = [3,4,5]; Array.prototype.push.apply(arr1,arr2)
// ES6 var arr1 = [0,1,2]; var arr2 = [3,4,5]; arr1.push(...arr2)
扩展运算符的应用
合并数组
//ES5 [1,2].concat(more); arr1.concat(arr2,arr3) //ES6 [1,2, ...more] [...arr1, ...arr2, ...arr3)
与解构赋值结合生成数组
// ES5 a = list[0], rest = list.slice(1) // ES6 [a, ...rest] = list const [first, ...rest] = [1, 2, 3, 4, 5]; first // 1 rest // [2, 3, 4, 5] const [first, ...rest] = []; first // undefined rest // []: const [first, ...rest] = ["foo"]; first // "foo" rest // []
如果将扩展运算符用于数组赋值,只能放在参数的最后一位
字符串 将字符串转为真正的数组
[...'hello'] // [ "h", "e", "l", "l", "o" ]
还有一个好处是 能够正确识别32位的Unicode字符
其中Unicode字符如: 'x\uD83D\uDE80y' 也就是 "x🚀y"
'x\uD83D\uDE80y'
"x🚀y"
'x\uD83D\uDE80y'.length // 4 [...'x\uD83D\uDE80y'].length // 3
JavaScript会将32位Unicode字符,识别为2个字符,采用扩展运算符就没有这个问题。因此可以这样来写:
function length(str) { return [...str].length; } length('x\uD83D\uDE80y') // 3
凡是涉及到操作32位Unicode字符的函数,都有这个问题。因此,最好都用扩展运算符改写。
let str = 'x\uD83D\uDE80y'; str.split('').reverse().join('') // 'y\uDE80\uD83Dx' [...str].reverse().join('') // 'y\uD83D\uDE80x'
类似数组的对象
任何类似数组的对象都可以用扩展运算符转为真正的数组
[...document.quertSelectorAll('div')]; // [<div>, <div>, <div>]
Map和Set结构,Generator函数
扩展运算符内部调用的是数据结构的Iterator接口,因此只要具有Iterator接口的对象,都可以使用扩展运算符。
let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ]); let arr = [...map.keys()]; // [1, 2, 3]
Generator函数运行后,返回一个遍历器对象,因此也可以使用扩展运算符。
name属性返回该函数的函数名
匿名函数:
var fn = function(){} //ES5 fn.name // "" //ES6 fn.name // fn
Function构造函数返回的函数实例,name属性的值为“anonymous”。
(new Function).name // "anonymous"
bind返回的函数,name属性值会加上“bound ”前缀。
function foo() {}; foo.bind({}).name // "bound foo" (function(){}).bind({}).name // "bound "
var f = v => v; var f = function(v){ return v; }
由于大括号被解释为代码块,所以如果箭头函数要返回一个对象,必须在对象外面加上括号。
var getTempItem = id => ({ id: id, name: "Temp" });
与解构赋值一起使用:
const full = ({first, last}) => first + ',' + last; //等同于 function full(person){ return person.first + person.last; }
简化回调函数:
[1,2,3,4].map(x => x * x); //等同于 [1,2,3,4].map(function(x){ return x * x; }); var result = values.sort((a,b) => a-b); //等同于 var result = values.sort(function(a,b){ return a - b; })
结合rest参数使用
const numbers = (...nums) => nums; numbers(1,2,3,4,5) // [1,2,3,4,5] headAndTail(1, 2, 3, 4, 5); // [1,[2,3,4,5]]
注意点
第一条尤其重要。this对象的指向是可变的,但是在箭头函数内部是固定的。
function foo(){ setTimeout(() => { console.log("id:" + this.id) },1000) } foo.call({id:11}) //转为ES5代码 function foo() { var _this = this; setTimeout(function () { console.log("id:" + _this.id); }, 1000); }
如果是个普通函数,执行的this应该指向 window 对象,但是箭头函数导致this对象总是指向函数所在的对象。
再比如:
function Timer(){ this.seconds = 0; setInterval(()=>this.seconds++,1000) } var t = new Timer(); setTimeout(()=>console.log(t.seconds), 3100); // 3
Timer函数内的 setInterval 调用了 this.seconds 属性,通过箭头函数让this总是指向Timer的实例对象。否则输出0 而不是3.
this 指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正因为没有this,所以不能用作构造函数。
除了this,arguments super new.target 这三个变量在箭头函数中也是不存在的,分别指向外层函数对应的变量。
function foo() { setTimeout(() => { console.log('args:', arguments); }, 100); } foo(2, 4, 6, 8) // args: [2, 4, 6, 8]
箭头函数内部的变量 arguments 其实是函数 foo 的 arguments 变量。
由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。
(function() { return [ (() => this.x).bind({ x: 'inner' })() ]; }).call({ x: 'outer' }); // outer
上面的代码中箭头函数没有自己的 this,所以 bind 无效,内部的 this 指向外部的 this。
函数绑定
ES7提出了『函数绑定』运算符用来取代 call apply bind 调用。
函数绑定运算符是并排的双冒号 :: ,昨天冒号绑定一个对象,右边是一个函数。会自动将左边的对象作为上下文环境(this对象)绑定到右边的函数上。
foo::bar; bar.bind(foo); foo::bar(...arguments); bar.apply(foo, arguments); var foo = {ss: 112} var bar = function(){console.log(this.ss)}; foo::bar(); // 112
双冒号运算符返回的还是原对象,因此可以采用链式写法
let { find, html } = jake; document.querySelectorAll("div.classA") ::find("p") ::html("this is p");
The text was updated successfully, but these errors were encountered:
ccforward
No branches or pull requests
ES6 笔记二
ES6 笔记一
思维导图
1. 函数
1.1 函数参数默认值
基本用法
参数变量是默认声明的,不能用
let
const
再次声明与解构赋值默认值结合使用
参数默认值位置
通常把函数的尾参数作为有默认值的参数。因为这样比较容易看出到底忽略那些参数。
上面的函数,有默认值的参数不是尾参数,因此无法省略该参数而不省略其后的参数,除非显式的输入 undefined
函数
length
属性指定了默认值后函数的
length
属性将返回没有指定默认值的参数个数PS: rest参数不会计入 length 属性
作用域
如果参数默认值是一个变量,则该变量所处的作用域与其它变量的作用域规则是一样的,即先是当前函数的作用域,然后才是全局作用域。
由于函数作用域内部的变量 x 已经生成所以 y 等于参数 x 而不是全局变量x。
上述代码函数调用时 y 的默认值变量 x 尚未在函数内部生成,所以 x 指向全局变量。
如果函数A的默认值是函数B
那么由于函数的作用域是其声明时的作用域,函数B的作用域就不是函数A,而是全局作用域。如下:
上述代码等同于
关于babel的一个bug
应用
可指定函数某一个参数不得省略,省略就会抛出错误
上述代码可知参数
mustBeProvided
的默认值等于throwIfMissing
函数的运行结果。这说明函数参数的默认值不是在定义时执行,而是在运行时执行。如果把函数参数默认值设置为
undefined
则表示这个参数是可以省略的。1.2 rest 参数
rest参数("...变量名"),用于获取函数的多余参数。rest参数搭配的变量是一个数组,该变量将多余的参数放入其中。
rest 参数只能作为最后一参数。
函数的
length
属性不包括 rest 参数。1.3 扩展运算符
含义
扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。
该运算符主要用于函数的调用
替代数组的 apply 方法
由于扩展运算符可以展开数组,所以不需要apply将数组转为函数的参数了。
使用
Math.max
求数组最大元素通过 push 将一个数组添加到另一数组尾部
扩展运算符的应用
合并数组
与解构赋值结合生成数组
如果将扩展运算符用于数组赋值,只能放在参数的最后一位
字符串
将字符串转为真正的数组
还有一个好处是 能够正确识别32位的Unicode字符
其中Unicode字符如:
'x\uD83D\uDE80y'
也就是"x🚀y"
JavaScript会将32位Unicode字符,识别为2个字符,采用扩展运算符就没有这个问题。因此可以这样来写:
凡是涉及到操作32位Unicode字符的函数,都有这个问题。因此,最好都用扩展运算符改写。
类似数组的对象
任何类似数组的对象都可以用扩展运算符转为真正的数组
Map和Set结构,Generator函数
扩展运算符内部调用的是数据结构的Iterator接口,因此只要具有Iterator接口的对象,都可以使用扩展运算符。
Generator函数运行后,返回一个遍历器对象,因此也可以使用扩展运算符。
1.4 name 属性
name属性返回该函数的函数名
匿名函数:
Function构造函数返回的函数实例,name属性的值为“anonymous”。
bind返回的函数,name属性值会加上“bound ”前缀。
1.4 箭头函数
基本用法
由于大括号被解释为代码块,所以如果箭头函数要返回一个对象,必须在对象外面加上括号。
与解构赋值一起使用:
简化回调函数:
结合rest参数使用
注意点
第一条尤其重要。this对象的指向是可变的,但是在箭头函数内部是固定的。
如果是个普通函数,执行的this应该指向 window 对象,但是箭头函数导致this对象总是指向函数所在的对象。
再比如:
Timer函数内的 setInterval 调用了 this.seconds 属性,通过箭头函数让this总是指向Timer的实例对象。否则输出0 而不是3.
this 指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正因为没有this,所以不能用作构造函数。
除了this,arguments super new.target 这三个变量在箭头函数中也是不存在的,分别指向外层函数对应的变量。
箭头函数内部的变量 arguments 其实是函数 foo 的 arguments 变量。
由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。
上面的代码中箭头函数没有自己的 this,所以 bind 无效,内部的 this 指向外部的 this。
函数绑定
ES7提出了『函数绑定』运算符用来取代 call apply bind 调用。
函数绑定运算符是并排的双冒号 :: ,昨天冒号绑定一个对象,右边是一个函数。会自动将左边的对象作为上下文环境(this对象)绑定到右边的函数上。
双冒号运算符返回的还是原对象,因此可以采用链式写法
The text was updated successfully, but these errors were encountered: