ES6 随记(3.4.1)-- 函数的拓展(参数默认值,扩展运算符)

上一章请见:

1. ES6 随记(1)-- let 与 const

2. ES6 随记(2)-- 解构赋值

3. ES6 随记(3.1)-- 字符串的拓展

4. ES6 随记(3.2)-- 正则的拓展 & 数值的拓展

5. ES6 随记(3.3)-- 数组的拓展

4. 拓展

e. 函数的拓展

· 参数默认值。此节与结构赋值关系甚大,可去往前文再看一次

再来烧脑的重新打开这个蛋疼的案例,

function fn1({x = 0, y = 0} = {}) {
    console.log(x, y);
}
function fn2({x, y} = { x: 0, y: 0 }) {
    console.log(x, y);
}

fn1() // 0, 0
fn2() // 0, 0

fn1({x: 3, y: 8}) // 3, 8
fn2({x: 3, y: 8}) // 3, 8

fn1({x: 3}) // 3, 0
fn2({x: 3}) // 3, undefined

fn1({}) // 0, 0
fn2({}) // undefined, undefined

fn1({z: 3}) // 0, 0
fn2({z: 3}) // undefined, undefined 

但需要一提是函数参数作用域问题。

(写了好些次,还是无法清晰的描述这个现象,我尽力了)

参数,默认值,函数体是同一个作用域,所以不妨按严格的先后关系来运行,由参数开始先声明新变量,然后判断传参有无解析默认值,再运行函数体。

let a = 10;
function fn1(b = a+1) {
    let a = 100;
    console.log(b,a);
}
fn1();  // 11, 100
a = 20;
fn1();  // 21, 100

function fn2(a, b = a) {
    console.log(a, b);
}
fn2();  // undefined, undefined
fn2(1);  // 1, 1

// 同一作用域内同名变量不能声明两次
function fn3(x) {
    let x = 999;
    console.log(x);
}
fn3();  // 报错:Identifier ‘a‘ has already been declared,
// function fn4(x = x+1) 也会报错,同理

而默认值是函数时,这个问题就有些妖了,不过也还是符合规则的。

let a = 1;
function test(fn = x => a) { // 此 a 已解析,参数作用域里没有,向上寻找
    let a = 10;
    console.log(fn());  // 故而参数中的 a 和函数内的 a 早就没关系了
}
test();          // 1
console.log(a);  // 1

let x = 1;
function test2(x, y = function(){ x = 2; }) {
    var x = 3;
    y();    // y 中的 x 只与参数 x 有关,var x 后,就是新的 x 不是参数 x 了, 所以不改变 var x 的值
    console.log(x);
}
function test3(x, y = function(){ x = 2; }) {
    x = 3;
    y();    // 此处所有的 x 都是参数 x 的修改,所以可被修改
    console.log(x);
}

test2();        // 3
console.log(x); // 1  函数内都有自己的 x,在自己作用域中,所以就不影响商机作用域了
test3();        // 2
console.log(x); // 1

所以判断传参有无再解析默认值这个也可以有些其他应用,比如默认值是自运行函数

function throwIfMissing() {
    throw new Error(‘Missing parameter‘);
}
function foo(arg = throwIfMissing()) {
    return arg;
}
// 没有传参选用了默认值,所以解析直接运行了 throwIfMissing,
// 否则是不运行的那个自运行函数的
console.log(foo(1)); // 1
foo(); // Uncaught Error: Missing parameter

注:当传入参数为 null 时不会选用默认值,而 undefined 会。

function foo(x = 1, y = 1) {
    console.log(x, y);
}
foo(undefined, null); // 1, null

再者,非最后一位参数传入空值,会报错,显而易见的。

fn(, 3);    // 报错
fn(1, , 3); // 报错

函数的 length 属性会被默认值打断,虽然并不知道这个有啥实际用途,但还是抄下来吧

(function (a) {}).length; // 1
(function (a = 5) {}).length; // 0
(function (a, b, c = 5) {}).length; // 2
(function(...args) {}).length // 0

·  拓展运算符 ...

1. 剩余参数非常好理解,也非常好用

function add(first, ...items) {
    return first + items.reduce((pre, cur) => pre + cur);
}
console.log(add(10, 2,3,4));  // 19

2. 数组的拆分

console.log(...[1,2]); // 1 2

let point1 = [0, 0], point2 = [3, 4];
function distance(x1, y1, x2, y2){
    return Math.hypot((x2-x1), (y2-y1));
}
console.log(distance(...point1, ...point2));  // 5

3. 转化类数组数据

[...arguments]
[...document.querySelectorAll(‘div‘)]

4. 可取代 apply

Math.max.apply(null, [14, 3, 77]);
Math.max(...[14, 3, 77]);

Array.prototype.push.apply(arr1, arr2);
arr1.push(...arr2);

5. 解构赋值

const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first, rest); // 1 [2, 3, 4, 5]

6. 帮助解决字符串 UTF-16 问题

console.log([...‘x\uD83D\uDE80‘].length) // 2
console.log([...‘x\uD83D\uDE80‘].reverse().join(‘‘)); // ??x

  

· ‘use strict‘ 的不同

由于现在默认值的解析是在函数体之前的,所以默认值解析完再设定严格模式当然有时会产生错误。

因此,现在的 ‘use strict‘ 只能放在全局或者没有参数的函数里

本文部分转载自 阮一峰 的 ECMAScript 6 入门

时间: 2024-10-26 15:34:24

ES6 随记(3.4.1)-- 函数的拓展(参数默认值,扩展运算符)的相关文章

关于Java函数不支持参数默认值的讨论,最后一条亮了 2333

ES6笔记之参数默认值(译)

原文链接:http://dmitrysoshnikov.com/ 原文作者:Dmitry Soshnikov 译者做了少量补充.这样的的文字是译者加的,可以选择忽略. 在这个简短的笔记中我们聊一聊ES6的又一特性:带默认值的函数参数.正如我们即将看到的,有些较为微妙的CASE. ES5及以下手动处理默认值 在ES6默认值特性出现前,手动处理默认值有几种方式: function log(message, level) { level = level || 'warning'; console.lo

ES6: 参数默认值及中间域

下午看了一章 ECMA-262 by Dmitry Soshnikov, 现在稍稍来小结下ES6中的参数默认值以及由此产生的参数中间作用域. 原文地址: http://dmitrysoshnikov.com/ecmascript/es6-notes-default-values-of-parameters/#conditional-intermediate-scope-for-parameters ES6中的参数默认值用法和其他语言都差不多,直接在参数后赋值: 1 function log(me

ES6函数参数默认值作用域的模拟原理实现与个人的一些推测

一.函数参数默认值中模糊的独立作用域 我在ES6入门学习函数拓展这一篇博客中有记录,当函数的参数使用默认值时,参数会在初始化过程中产生一个独立的作用域,初始化完成作用域会消失:如果不使用参数默认值,不会产生这个作用域:产生疑问是因为这段代码: var x = 1; function foo(x, y = function () {x = 2;}) { var x = 3; y(); console.log(x); }; foo();//3 foo(4);//3 console.log(x);//

SQL 自定义函数(Function)——参数默认值

sql server 自定义函数分为三种类型:标量函数(Scalar Function).内嵌表值函数(Inline Function).多声明表值函数(Multi-Statement Function) 标量函数:标量函数是对单一值操作,返回单一值. 内嵌表值函数:内嵌表值函数的功能相当于一个参数化的视图.它返回的是一个表,内联表值型函数没有由BEGIN-END 语句括起来的函数体. 多声明表值函数:它的返回值是一个表,但它和标量型函数一样有一个用BEGIN-END 语句括起来的函数体,返回值

C# 函数参数默认值

namespace 函数参数默认值 { class Program { public static void Test(int i =100) { Console.WriteLine("{0}",i); } static void Main(string[] args) { Test(); Test(222); Console.Read(); } } } 输出:100 222

java函数参数默认值

java通过函数的重载来实现函数参数默认值 public class ParameterDefault { /** * @param args */ public String getName(String givenName,String familyName){ return givenName+"."+familyName; } public String getName(String givenName){ return getName(givenName,"Xie&

自定义函数中的参数返回值 “-> (Int -> Int)”的问题

func makeIncrementer() -> (Int -> Int) { func addOne(number: Int) -> Int { return 1 + number } return addOne } var increment = makeIncrementer() println(increment(7)) 这里为什么要写两个 Int->Int 这里是返回值是参数,左边是参数,右边是返回值的意思. 自定义函数中的参数返回值 "-> (Int

Python函数参数默认值的陷阱和原理深究(转)

add by zhj: 在Python文档中清楚的说明了默认参数是怎么工作的,如下 "Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used