函数的扩展
1.可以直接为函数的参数指定默认值
function Point(x,y='haha'){}
1.1. 注意
- 使用参数默认值时,函数不能有同名参数。
- 参数变量是默认声明的,所以不能用let或const再次声明。
- 注意一下参数默认值的位置,尽量放在尾部。否则放在前面需要用undefiend(null不行)才能触发默认值。
- 参数默认值可以和解构赋值默认值结合起来使用
function ha(x,y=1){const x=1;console.log(x)}
const p = new Gha(); // Uncaught SyntaxError: Identifier 'x' has already been declared
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo() // undefined 5
1.2. 函数的length属性
length属性的含义是,该函数预期传入的参数个数。
指定了默认值以后,函数的length属性,将返回指定默认值前的参数个数。如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。
即length属性会失真。
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1
(function(...args) {}).length // 0
1.3. 作用域
函数调用时,函数体内部的局部变量x影响不到默认值变量x。
let x = 1;
function f(y = x) {
let x = 2;
console.log(y);
}
f() // 1
var x = 1;
function foo(x = x) {
// ...
}
foo() // ReferenceError: x is not defined
请注意下面2个实例
var x = 1;
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo() // 3
x // 1
var x = 1;
function foo(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo() // 2
x // 1
1.4 应用
- 可以指定参数的默认值;
- 指定参数不得省略(方式1,将默认值设置为抛出错误的函数;方式2 设为undefiend)
2.函数的rest参数(...变量名)
含义:用于获取函数的多余参数.
rest参数(...变量名)搭配的变量是个数组
注意:
- rest 参数的位置,只能在函数参数的尾端
- 函数的length属性
- ...变量名,也叫扩展运算符
- 应用 数组可直接用在函数参数中
function add(...values) { // 这才是rest参数
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10 非此处是rest参数
add(...[2,5,3]) // 10 数组可直接用在函数参数中
3.严格模式
ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
原因:函数的执行顺序:函数参数--》函数体。有时候,参数中使用了非严格模式,参数却能执行,等到函数体才报错,这样不合适,故es6直接禁止掉。
- 解决方法1: 使用全局的严格模式,非函数的严格模式
- 解决方法2: 把函数包在一个无参数的立即执行函数里面。
'use strict';
function doSomething(a, b = a) {
// code
}
const doSomething = (function () {
'use strict';
return function(value = 42) {
return value;
};
}());
4.name属性--还有函数的name属性;
- es5 与 es6的区别 对于函数表达式的name属性
- 构造函数返回的函数实例,name属性值为anonymous
- bind返回的函数,name属性值前加bound前缀
var f = function () {};
// ES5
f.name // ""
// ES6
f.name // "f"
const bar = function baz() {};
// ES5
bar.name // "baz"
// ES6
bar.name // "baz"
(new Function).name // "anonymous"
function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "
5.箭头函数
5.1 写法:(参数)=> XXXX
若XXXX 只有一行, XXX就是返回值
若XXXX 超过一行, xxx就是函数体,返回值需要自己写
注意:当XXXX为{a:1}时,需要用小括号包一下,以免浏览器解析错误
5.2 与rest参数结合
应用1: 将函数参数变为数组
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]]
5.3 注意: 没有自己的this对象。可以绑定this对象
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。即传了啥,就是啥,和函数体无关。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
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
6.总结 es5 es6 函数有哪些属性:
- length属性,
- name属性
7.双冒号运算符::
es5中有自己的this ,可用call apply bind 进行改变。
es6 中用函数绑定运算符是并排的两个冒号(::),取代call apply bind;
函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。
obj::function();---obj就是this对象(上下文环境)
8.尾调用优化--未完待续
尾调用的概念:指某个函数的最后一步是调用另一个函数。
类class
类的作用:通过类生成实例对象;优点,比之前的通过构造函数的方式,清晰、形象。更加像面向对象语言。
1.定义类的2种方法:
1.1构造函数的写法
class Haha{
constructor(){}
lala(){}
...
}
let shili = new Haha();
shili.lala();
1.2 表达式的写法
let Gaga = class me{
constructor(){}
lala(){return me.name}
...
}
let shili = new Gaga();
shili.lala();
2.一些特性,主要是通过类生成实例对象
注意下constructor方法, 这个是类默认的方法,没有定义,也可以调用。
- 无变量提升
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。