ES6学习之路-ES6函数扩展(一)

ES6函数的扩展

1.函数参数的默认值

es6之前,不能给函数的参数指定默认值,只能在函数体内使用变通的方法来实现;

function log(x,y){
 y = y || '你是大傻子';
console.log(x,y);    
}
log(1);    //1,你是大傻子
log(1,'');  // 1,你是大傻子

检查参数y是否赋值,没有则指定默认值

es6的写法:

function log (x, y = '哈哈哈'){
console.log(x,y);
}

log(1);   //1,哈哈哈
log(1,''); // 1

由于es6内部使用 “===” 来判断是否有值,  '' === undefined  返回false,

if(y === "undefined"){
   y = '哈哈哈'; 
}

而在y= y || '你是大傻子';中 ;

y = '' || '你是 大傻子';
y = 0 || '你是大傻子';
y = null || '你是大傻子';
y = undefined || '你是大傻子';

返回值均为 :'你是大傻子'
所以 es6 之前的写法  log(1,'');  返回 1你是大傻子,

所以 es6 的写法中:log(1,''); 这里的y值不取默认值,而是取传进去的 ` '' `  值,结果返回 1''; 即为 1;


eg2:

function Point(x = 0, y = 0){    //构造函数(首字母大写)
this.x = x;
this.y = y;
}
const p = new Point();
p // x = 0; y = 0;

这样写的优点:

    1.简洁(不用在函数内部做判断等操作)

    2.易读(读代码时,可以清楚看懂哪些参数可省略)

    3.利于优化(因为有默认值的存在,即使后期不再使用该参数,也不会导致无法运行)


注意:

    在给函数传参时,参数变量x 是默认声明的,根据es6变量、函数不能被重复声明的规定,在函数体内,变量x不能

    使用let 或const 再次声明,否则会报错;

    function log(x,y){
    let x = 1; //error
    const y = 0; // error
    }
  • 使用参数默认值时,函数不能有同名参数(不知道为啥)
function(x,x,y){
...  //可以
}

function(x,x,y=1){
...//报错 不可以
}
  • 参数默认值不是传值的,而是每次重新计算默认表达式的值。(惰性求值)
let x = 99;
funtion foo(p = x + 1){
console.log(p);
}
foo(); //p =  99+1 = 100

x = 200;
foo(); // p = 200 +1 = 201   //这里没用使用上次计算

        这里参数p的默认值 是 x+1. 每次调用foo时,都是重新计算 x+1,而不是取上次的p = 100;

  • 与解构赋值默认值结合使用  
     
function foo({x,y = 5}){
console.log(x,y);
}
foo({});//传入x;undefined,y:undefined;y取默认值5,结果 :undefinde 5;
foo({x:1,y:2}); // 1 2
foo({x:1});// 1 5    
foo();//此时传入的对象为undefined , foo函数中没有给 {x,y = 5}取默认值,所以在函数体内找不到x,y的值,返回:Uncaught TypeError: Cannot destructure(解构) property `x` of 'undefined' or 'null'.

    该方法只使用了对象的结构赋值默认值,没有使用函数参数的默认值。只用参数是一个对象时,变量x和y才会通过解构赋值生成。通过提供函数参数的默认值,可以避免这种情况。如下:

function foo({x,y = 1} = {}){
console.log(x,y);
}
foo();//没有参数时,取{},传入值x:undefinde,y:undefinde; 返回结果:undefined 1;

    如果没有提供参数,foo的参数默认是一个空对象,传入空对象时,y的默认值为1生效,所以输出 undefined 1;

  • 解构赋值eg2(eg1的扩展)

  

function fetch(url,{body = '',method = 'GET',headers = {}}){
console.log(method);
}
fetch('//ossweb-imng.qq.com',{});// 返回method的默认值 GET
fetch('//ossweb-img.qq.com');// 参数匹配url,后面的对象对应的参数为空,fetch函数又没有指定默认参数,所以这里解构报错,错误同上;

   如果函数fetch的第二个参数是对象,就可以为其三个属性设置默认值。这种写法不能省略第二个参数。如果和函数参数的默认值相结合,就可以省略第二个参数({});实现如下:

function fetch(url,{body = '', method = 'GET', headers = {}} = {}){
console.log(method);
}
fetch('//ossweb-img.qq.com',{});//GET
fetch('//ossweb-img.qq.com');//GET

    此时,函数fetch没有第二个参数时,函数参数的默认值生效,然后解构赋值的默认值生效,变量method取到默认值GET。

?练习:写法的差别

//1
function m1({x = 0, y = 1} = {}){
return [x,y];
}

//2
function m2 ({x,y} = {x:1,y:2}){
return[x,y];
}

    写法1中,给m1函数指定了参数默认值{};同时又设置了对象解构赋值的默认值{x = 0, y = 1};

    写法2中,给m2函数只指定了参数默认值是一个具有属性的对象{x = 1, y = 2}而没有设置对象结构赋值的默认值

//没有参数时
m1(); //取默认参数{},然后解构赋值默认值 x:0,y:0;
m2(); //取默认参数{x:0,y:0},返回 0 0

//参数齐全时
m1({x:3,y:8});  // 有参数,直接解构赋值给参数 x:3,y:8 
m2({x:3,y:8}); //有参数, 直接解构赋值 
x:3,y:8

//参数不齐时
m1({x:1}); //有参数,解构赋值时 y为undefined,此时y取默认值0 ,返回 1 0 

m2({x:1}); // 有参数, 解构赋值时,y为undefined ,但此时y未设置默认值 
返回 1 undefined

//都无值时

m1({}); //返回解构赋值后的默认值 0 0
m1({}); //有参,但参数未设置对象解构赋值的默认值, 此时 对象为{},x y 均为 undefined , 返回 undefined undefined 

  • 参数默认值的位置

       定义了默认值的参数,应是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数如果非尾参数设置默认值,实际上这个参数是无法省略的。

//eg1
functon f(x = 1, y){
return [x,y];
}
f(); // [1,undefined]
f(2); // [1,undefined]
f(,1) // 报错
f(undefined,1);//[1,1]
//eg2
function f(x,y = 5, z){
return [x,y,z];
}
f();//[undefined,5,undefined]
f(1);//[1,5,undefined]
f(1,,2);//undefined
f(1,undefined,2);//[1,5,2]

    上面代码中,有默认值的参数都不是尾参数。此时,无法省略该参数,而不省略它后面的参数,除非显式的输入 undefined;

      如果传入 undefined ,出发该参数等于默认值,非undefined 则不行(如 null,‘’,0);

funtion foo (x = 5, y = 7 ){
return [x,y];
}

foo(null,undefined); // null 7

==================

分割线 0410 23:30   未完待续

函数的 length 属性

0411 21:46分 ,续上:

  • 函数的length属性返回函数的参数个数,但给参数指定了默认值后,只返回没有指定默认值的参数个数。

(指定了默认值后,函数的length属性会失真,返回不准确)

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

    length属性的返回值,等于函数的参数个数,减去 指定了默认值的参数个数。

length 含义:函数预期传入的参数个数。   某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。 rest参数也不会计入length属性(还没看到)。

(function(...args){}).length;//0

    如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。(length属性计算第一个设置默认值的参数之前的 参数个数)

(function(a,b = 1,c){}).length;//1
(function(a = 1,b,c){}).length;//0
(function(a,b,c = 1,d){}).length;//2
  • 作用域

    在设置参数默认值的情况下,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等初始化结束,作用域消失。  函数体内不能再声明参数中的变量。

在未设置参数默认值时,不会出现该作用域。

var x = 1;
function foo(x , y = x){  //参数y的默认值 等于 变量x 

foo(2);// 2   

    调用函数f时,参数形成一个单独的作用域。在这个作用域里,默认值变量x 指向第一个参数x, 而不是全局变量 x //1;所以在调用 foo函数时, 参数x = 2; 所以 y = 2,输出为2;

eg2:

let x = 1;
function foo( y = x){
 let x = 2;
 console.log(y);
}

foo(); // 1

  函数f被调用时, 设置了参数默认值  的  y = x 形成一个单独的作用域。 这个作用域里,变量x 未定义, 所以指向外层的全局变量x。 函数调用时,函数体内部的局部变量x 影响不到 默认值变量x ; 所以输出 1;

   如果此时全局变量x不存在的话,就会报错。

function foo(y = x){
 let x = 2;
 console.log(y);
}
foo(); // x is not defined
let x = 1;
function foo(x = x){  //参数 x = x 形成一个单独作用域。 实际执行的是 let x = x, 由于暂时性死区的原因 ,会报 x 未定义错误。
....
}
foo();//  x is not defined   

   参数的默认值 是 一个函数是, 函数的作用域也遵守这个规则。

let foo = 'outer';
function bar(func = () => foo){
 let foo = 'inner';
 console.log(func());
}
bar(); // outer

    函数bar 的参数 func的默认值是一个匿名函数 ,返回值为全局变量foo,(函数参数形成的单独作用域里没有定义foo,所以foo指向外层的全局变量),所以输出 outer

    同理,如果没有在外层定义全局变量foo,会报错:

function bar(func = () => foo){   //匿名函数内的foo变量指向外层,但函数外层没有声明foo,所以报错
let foo = 'inner';
console.log(func());
}
bar(); // foo is not defined

eg3:

var x = 1;
function foo(x, y = function(){x = 2}){
 var x  = 3;   //此处使用var 声明函数体内部变量x, 使用let 会报错
y();
 console.log(x);
}

foo(); // 3
x // 1

    函数foo的参数形成一个单独作用域,作用域里,声明了变量x,y,y的默认值是一个匿名函数,匿名函数内部的变量取的是当前作用域的第一个参数x。foo函数内部又声明了一个内部变量x,该内部变量x 与 参数x 不是同一个作用域,所以不是同一个变量,执行 y 的默认值(匿名函数)后, 外部的全局变量x 未改变, foo函数内部的变量x也未变。 

    

var x = 1;
functino foo(x, y = funciton(){x = 2}){
x = 3;   
y();
console.log(x);
}
foo(); // 2
x //1


如果将 foo函数内部的  var x = 3;的var去除,函数foo的内部变量x 就指向第一个参数x,与匿名函数内部的x一致,最后输出

值为 2 ;foo内部  x =3 时, 参数x的值被设置为 3, 执行 y() 后,又被重新赋值为2 ,最后输出2;

  • 作用域的应用

 

funtion throwIfMissing(){
throw new Error("Missing parameter");
}
function foo(mustBeProvided = throwIfMissing()){
return mustBeProvided;
}
foo();     // Error:Missing parameter;

foo函数调用时如果没有参数,就会调用默认值 throwIfMissing函数的运行结果(函数名throwIfMissing 之后有()),表明

参数的默认值不是在定义时执行,而是在运行时执行。(这里参数的默认值如果在定义时执行,那么缺少参数时,若想顺利抛出错误,需要执行该参数的默认值(throwIfMissing函数),有参数时则只需要返回参数值,这样就需要判断返回值是函数还是常量 。 所以在运行时执行 这样的写法更简洁)如果参数已赋值,默认值中的函数就不会运行。

另外,可将参数默认值设置为 undefined , 表明该参数可省略。

function foo(optional = undefined){
...
}

0411 23:13 抄完—— 函数扩展第一小节








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值