文章目录
1. 重点提炼
- 函数参数
- 扩展运算符
- rest参数
- 箭头函数
2. 函数的参数
- 参数的默认值
- 与结构赋值结合
length
属性- 作用域
- 函数的
name
属性
2.1 参数的默认值
function foo(x, y){
console.log(x, y)
}
foo('hello')
但是针对不传的值就是undefined
,这种设计也非常不好。
es5
处理 => 逻辑或
function foo(x, y){
y = y || 'world'
console.log(x, y)
}
foo('hello')
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.38
Branch: branch02commit description:a1.38(函数的参数——es5处理针对不传的值就是undefined)
tag:a1.38
function foo(x, y){
y = y || 'world'
console.log(x, y)
}
foo('hello', 0)
如果第二个参数传递0
就会发生问题,0
也是false
。
因此es5
的这种写法并不严谨。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.39
Branch: branch02commit description:a1.39(函数的参数——es5处理针对不传的值不严谨)
tag:a1.39
es6
可以设置函数默认值
function foo(x, y = 'world'){
console.log(x, y)
}
foo('hello', 0)
note:函数参数是从左到右解析,如果没有默认值会被解析成
undefined
foo('hello')
综上es6
的函数默认值写法,写法更为简洁,并且对于阅读代码更为便捷,更好优化。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.40
Branch: branch02commit description:a1.40(函数的参数——es6参数默认值)
tag:a1.40
es6
函数参数的细节 =>
function foo(x = 5) {
let x = 1
}
foo()
设置了参数,就不可以在函数内部再声明一个同名变量了。
function foo(x = 5) {
const x = 1
}
foo()
const
常量同名也不允许。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.41
Branch: branch02commit description:a1.41(函数的参数——设置了参数,就不可以在函数内部再声明一个同名变量/常量了)
tag:a1.41
function foo(x, x, y = 5) {
}
foo(1, 2)
函数参数名不可以重名
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.42
Branch: branch02commit description:a1.42(函数的参数——函数参数名不可以重名)
tag:a1.42
function foo(x, y = 5, z) {
console.log(x, y, z)
}
foo(1, 2)
传多个参数,默认值放在中间,调用时无法跳过中间的参数去传后面的参数。因此参数的默认值一定要放在函数参数的末尾。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.43
Branch: branch02commit description:a1.43(函数的参数——传多个参数,默认值放在中间,调用时无法跳过中间的参数去传后面的参数。)
tag:a1.43
正确的传参方式 =>
function foo(x, z, y = 5) {
console.log(x, y, z)
}
foo(1, 2)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.44
Branch: branch02commit description:a1.44(函数的参数——参数的默认值一定要放在函数参数的末尾)
tag:a1.44
如果想让具体某个参数使用默认值,可以使用 undefined
进行赋值,如下段代码所示:.
function f(x, y = 7, z = 42) {
return x + y + z
}
console.log(f(1, undefined, 43)) // 51
在ES6
中不仅可以给参数默认赋值具体的数值,同时参数赋值支持参数的逻辑运算进行赋值,如下段代码所示:
function f(x, y = 7, z = x + y) {
return z * 0.5
}
console.log(f(1, 7)) // 4
应用 =>
function ajax(url, {
body = '',
method = 'GET',
headers = {}
} = {}) {
console.log(method)
}
ajax('http://www.abc.com', {
method: 'POST'
})
注意
在函数体内,有时候需要判断函数有几个参数,一共有2个办法。
在 ES5
中可以在函数体内使用 arguments
来判断。
function foo(a, b = 1, c) {
console.log(arguments.length)
}
foo('a', 'b') //2
然而在 ES6
中不再使用 arguments
来判断了,但可以借助 Function.length
来判断。
function foo(a, b = 1, c) {
console.log(foo.length)
}
foo('a', 'b') // 1
注意: Function.length 结果和 arguments 的结果不同!没错,Function.length 是统计第一个默认参数前面的变量数
function foo(a = 2, b = 1, c) {
console.log(foo.length)
}
foo('a', 'b') // 0
2.2 与解构赋值结合
function foo({x, y = 5}){
console.log(x, y)
}
foo({})
foo({
x: 1,
y: 2
})
解构空对象调用,则为undefined。
否则根据参数名一一对应即可。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.45
Branch: branch02commit description:a1.45(函数的参数——与结构赋值结合使用)
tag:a1.45
function foo({x, y = 5}){
console.log(x, y)
}
foo()
有参数不传必然报错,因此加上解构更为稳妥。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.46
Branch: branch02commit description:a1.46(函数的参数——有参数不传必然报错)
tag:a1.46
对于发送ajax请求,URL地址必传,剩下可以选传,定义为一个对象参数,里面的header也是一个对象,第二个参数定义一个对象如果不传默认值为空对象。
function ajax(url, {
body = '',
method = 'GET',
headers = {}
} = {}){
console.log(method)
}
ajax('http://www.abc.com', {
method: 'POST'
})
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.47
Branch: branch02commit description:a1.47(函数的参数——与解构配合的复杂传参)
tag:a1.47
2.3 length属性
length属性 => 返回参数个数
function foo(x, y, z){
console.log(x, y)
}
console.log(foo.length)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.48
Branch: branch02commit description:a1.48(函数的参数——length属性 => 返回参数个数)
tag:a1.48
function foo(x, y, z = 3){
console.log(x, y)
}
console.log(foo.length)
function foo1(x = 1, y = 2, z = 3){
console.log(x, y)
}
console.log(foo1.length)
注意:length返回的并不是参数个数,而是非默认值参数个数。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.49
Branch: branch02commit description:a1.49(函数的参数——length属性 => 注意:length返回的并不是参数个数,而是非默认值参数个数。)
tag:a1.49
2.4 作用域
在函数中一旦设置了参数默认值,就会形成参数单独的作用域。如果不设置默认参数,这种语法是不会出现的。
let x = 1
function foo(x, y = x){
console.log(y) // 2
}
foo(2)
在函数当作参数y
的默认值是x
,当调用函数时,参数会形成一个单独的作用域,这里面x
指向当前作用域的x
,而不是全局的x
。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.50
Branch: branch02commit description:a1.50(函数的参数——在函数中一旦设置了参数默认值,就会形成参数单独的作用域。)
tag:a1.50
let x = 1
function foo(y = x) {
let x = 2
console.log(y) // 1
}
foo()
当foo
在调用的时候,y = x
参数会形成一个单独的作用域,在这个作用域里x
并没有定义,这时会沿着作用域链往外去寻找x
,最终在全局作用域下就找到了对应的x
。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.51
Branch: branch02commit description:a1.51(函数的参数——在函数作用域链。)
tag:a1.51
function foo(y = x){
let x = 2
console.log(y)
}
foo()
在整个作用域链上外部都找不到x
,因此会报错。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.52
Branch: branch02commit description:a1.52(函数的参数——在函数作用域链上找不到参数对应变量。)
tag:a1.52
2.5 函数的name属性
console.log((new Function).name) //anonymous
通过new Function
定义一个方法,这个方法没有名字,直接获取name
属性。
匿名函数的name
属性 => anonymous
匿名的
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.53
Branch: branch02commit description:a1.53(函数的参数——anonymous。)
tag:a1.53
function foo(){}
console.log(foo.name)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.54
Branch: branch02commit description:a1.54(函数的参数——函数的name属性默认为函数名)
tag:a1.54
function foo(x, y){
console.log(this, x, y)
}
foo.bind({name: 'lisi'})(1, 2)
console.log(foo.bind({}).name)
通过bind
后的函数name
属性 => 多添加了一个单词bound
,后面才是函数名称。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.55
Branch: branch02commit description:a1.55(函数的参数——通过bind后的函数name属性 => 多添加了一个单词
bound
,后面才是函数名称)tag:a1.55
匿名函数通过bind
后的name
属性中只有bound
。
console.log((function(){}).bind({}).name)
bound
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.56
Branch: branch02commit description:a1.56(函数的参数——匿名函数通过bind后的name属性中只有bound。)
tag:a1.56
3. 扩展运算符与rest参数
…
=> 扩展运算符与rest
参数- 扩展运算符:把数组或者类数组展开成用逗号隔开的值 (特征:放在等号右边或者放在实参上)
rest
参数:把逗号隔开的值组合成一个数组 (特征:放在等号左边或者放在形参上)- Spread Operator 和 Rest Parameter 是形似但相反意义的操作符,简单的来说 Rest Parameter 是把不定的参数“收敛”到数组,而 Spread Operator 是把固定的数组内容“打散”到对应的参数。
3.1 扩展运算符
// 扩展运算符
function foo(a, b, c) {
console.log(a, b, c)
}
let arr = [1, 2, 3]
foo(...arr)
console.log(...arr)
…
=> 把数组或者类数组展开成用逗号隔开的值。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.57
Branch: branch02commit description:a1.57(扩展运算符与rest参数——
…
=> 把数组或者类数组展开成用逗号隔开的值。)tag:a1.57
合并两个数组
es5
语法 => 最简答的方法就是循环第一个数组,再从第二个数组中一个个push
进来即可。但是比较麻烦。
let arr1 = [1, 2, 3]
let arr2 = [4, 5, 6]
Array.prototype.push.apply(arr1, arr2)
console.log(arr1)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.58
Branch: branch02commit description:a1.58(扩展运算符与rest参数——es5语法 => 合并两个数组)
tag:a1.58
es6
=> 扩展运算符,合并两个数组。
let arr1 = [1, 2, 3]
let arr2 = [4, 5, 6]
arr1.push(...arr2)
console.log(arr1)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.59
Branch: branch02commit description:a1.59(扩展运算符与rest参数——es6 => 扩展运算符,合并两个数组。)
tag:a1.59
扩展运算符 => 将字符串打散放入数组。
let str = 'asdbbc'
var arr = [...str]
console.log(arr)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.60
Branch: branch02commit description:a1.60(扩展运算符与rest参数——扩展运算符 => 将字符串打散放入数组。)
tag:a1.60
实际上扩展运算符就是把字符串、数组、类数组打散。
…
=> rest
参数 => 将散着的元素合并。
3.2 rest参数
定义一个函数 => 求出所有参数的和,但是传入的参数个数可能不确定。
es5 =>
// rest参数
function foo(x, y, z) {
let sum = 0
Array.prototype.forEach.call(arguments, function(item){
sum += item
})
return sum
}
console.log(foo(1, 2))
console.log(foo(1, 2, 3))
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.61
Branch: branch02commit description:a1.61(扩展运算符与rest参数——es5 =>定义一个函数 => 求出所有参数的和)
tag:a1.61
function foo(x, y, z) {
let sum = 0
Array.from(arguments).forEach(function(item){
sum += item
})
return sum
}
console.log(foo(1, 2))
console.log(foo(1, 2, 3))
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.62
Branch: branch02commit description:a1.62(扩展运算符与rest参数——es6 =>定义一个函数 => 求出所有参数的和)
tag:a1.62
rest参数
=> 接收参数
function foo(...args){
console.log(args)
let sum = 0
args.forEach(function(item){
sum += item
})
return sum
}
console.log(foo(1, 2))
console.log(foo(1, 2, 3))
rest参数
刚好与扩展运算符相反,它把各个参数合并成了一个数组,而扩展运算符是将一个集合打散。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.63
Branch: branch02commit description:a1.63(扩展运算符与rest参数——es6 =>rest参数)
tag:a1.63
如果函数的第一个参数确定是可以传的,而后面不确定传几个参数。 => rest参数
function foo(x, ...args) {
console.log(x)
console.log(args)
}
foo(1, 2, 3)
foo(1, 2, 3, 4)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.64
Branch: branch02commit description:a1.64(扩展运算符与rest参数——如果函数的第一个参数确定是可以传的,而后面不确定传几个参数。 => rest参数)
tag:a1.64
rest参数
与解构联合使用
let [x, ...y] = [1, 2, 3]
console.log(x)
console.log(y)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.65
Branch: branch02commit description:a1.65(扩展运算符与rest参数——rest参数与解构联合使用)
tag:a1.65
4. 箭头函数
- this指向定义时所在的对象,而不是调用时所在的对象
- es5的this指向定义时所在的对象
- 实际在箭头函数中并没有this,箭头函数的this是它外面一层执行上下文的this。
- 不可以当作构造函数
- 不可以使用arguments对象
- 可以使用rest运算符
es5
中定义一个求和的函数 =>
console.log(sum(4, 5))
function sum(x, y) {
return x + y
}
以上这种方式无论是先声明后调用,还是先调用后声明都可。实际用这种方式声明函数,会存在一个函数的预定义。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.66
Branch: branch02commit description:a1.66(箭头函数——es5中定义一个求和的函数)
tag:a1.66
es5
中还可以把函数赋值给一个变量。
console.log(sum)
console.log(sum(4, 5))
let sum = function(x, y){
return x + y
}
但是这种方式,就必须先声明后调用。因为这里是将一个函数赋值给一个变量,哪怕是var
声明的变量,存在变量提升,变量值是undefined
的,也不可以调用,如果let
,根本都不存在变量提升,因此必然会报错了。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.67
Branch: branch02commit description:a1.67(箭头函数——es5中还可以把函数赋值给一个变量。)
tag:a1.67
箭头函数的左边是参数,右边是函数体。
let sum = (x, y) => {
return x + y
}
console.log(sum(3, 4))
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.68
Branch: branch02commit description:a1.68(箭头函数——基本使用)
tag:a1.68
箭头函数的函数体中只有一行代码,则可以简写代码,省略花括号和return
。
let sum = (x, y) => x + y
console.log(sum(3, 4))
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.69
Branch: branch02commit description:a1.69(箭头函数——简写)
tag:a1.69
4.1 笔试题1
let x = x => x
表示的意思 =>
let x = function(x){
return x
}
note: 如果只有一个参数,可以省略括号,如果大于一个参数一定要记得带括号
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.70
Branch: branch02commit description:a1.70(箭头函数——笔试题1)
tag:a1.70
4.2 箭头函数与普通函数的差别
this指向定义时所在的对象,而不是调用时所在的对象
但是普通函数和箭头函数对 this
的处理方式是截然不同的。
let foo = {
name: 'es',
say: function() {
console.log(this.name)
}
}
console.log(foo.say()) // es
say
在被调用之后,this
指向的是调用 say
方法的对象,显示是 foo
对象,所以 this === foo this.name
也就是 foo.name
。
let foo = {
name: 'es',
say: () => {
console.log(this.name, this)
}
}
console.log(foo.say()) // undefined
因为箭头函数中对 this
的处理是定义时,this
的指向也就是 foo
外层的所指向的 window
,而 window
没有 name
属性,所以结果是 undefined
。
es-demo\src\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES-CLI</title>
</head>
<body>
<h1>Hello ECMAScript</h1>
<button id="btn">点我</button>
</body>
</html>
es-demo\src\1-8.js
let oBtn = document.querySelector('#btn')
console.log(oBtn)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.71
Branch: branch02commit description:a1.71(箭头函数——dom操作获取元素)
tag:a1.71
添加按钮的点击事件
let oBtn = document.querySelector('#btn')
oBtn.addEventListener('click', function () {
console.log(this)
})
this 指向 当前触发的按钮。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.72
Branch: branch02commit description:a1.72(箭头函数——添加按钮的点击事件,this 指向 当前触发的按钮。)
tag:a1.72
触发事件中引入定时器 =>
let oBtn = document.querySelector('#btn')
oBtn.addEventListener('click', function () {
setTimeout(function(){
console.log(this)
}, 1000)
})
setTimeout
相当于Window
下的一个方法,当前调用的对象发生变化了,即this
指向当前调用的对象window
。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.73
Branch: branch02commit description:a1.73(箭头函数——添加按钮的点击事件,触发事件中引入定时器 。)
tag:a1.73
使用定时器后,不想this
发生改变,es5
方法 => bind
let oBtn = document.querySelector('#btn')
oBtn.addEventListener('click', function () {
setTimeout(function(){
console.log(this)
}.bind(this), 1000)
})
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.74
Branch: branch02commit description:a1.74(箭头函数——使用定时器后,不想this发生改变,es5方法 => bind)
tag:a1.74
箭头函数 => this
不发生变化
this指向定义时所在的对象,而不是调用时所在的对象
实际在箭头函数中并没有this,箭头函数的this是它外面一层执行上下文的this。
let oBtn = document.querySelector('#btn')
oBtn.addEventListener('click', function () {
setTimeout(() => {
console.log(this)
}, 1000)
})
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.75
Branch: branch02commit description:a1.75(箭头函数——使用定时器后, => this不发生变化)
tag:a1.75
不可以当作构造函数
在es5
中,定义一个类 => 函数
// 类
function People(name, age){
console.log(this)
this.name = name
this.age = age
}
let p1 = new People('zhangsan', 30)
console.log(p1)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.76
Branch: branch02commit description:a1.76(箭头函数——在es5中,定义一个类 => 函数)
tag:a1.76
用箭头函数
let People = (name, age) => {
this.name = name
this.age = age
}
let p1 = new People('zhangsan', 30)
console.log(p1)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.77
Branch: branch02commit description:a1.77(箭头函数——不可以当作构造函数)
tag:a1.77
不可以使用arguments对象
let foo = (...args) => {
console.log(arguments)
console.log(args)
}
foo(1, 2, 3)
因为webpack
中的eval
函数影响的,在浏览器中看看:
虽然箭头函数并不支持arguments
,但是可以使用rest
参数。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a1.78
Branch: branch02commit description:a1.78(箭头函数——不可以使用arguments对象)
tag:a1.78
(后续待补充)