参数默认值:
// function fn(name,
//     age=100,
//     arr=[],
//     obj={},
//     call=function(){}){
//         //参数1是必须传递
//         //其余参数有默认值,可选传递
//         console.log(name);
//         console.log(age);
//         console.log(arr);
//         console.log(obj);
//         console.log(call('callback'));

//     }
//     fn(name="苏玮一",age=200,arrr=[1,2,3],obj={key:1},call=function(info){
//         return info;
//     });

//函数参数的默认值,可以是另一个函数的返回值
// function pi(){
//     return 3.1415926;
// }
// function fn(r,p=pi()){ //把pi的值传给p
//     console.log(r*r*p);
// }
// fn(r=10);

//如果只想传递第二往后的参数,参数一保持默认值 可用undefined占位
// function fn(name="苏玮一",age){//null ,空 都不行
//     console.log(name);
//     console.log(age);
// }
// fn(undefined,age=21);

//支持参数二使用参数一作为默认值,反之不可以
// function fn(a,b=a){ //(b=a,a) 是错误的 不可以
//     console.log(a);
//     console.log(b);
// }
// fn(a=2);

//解构变量有不定元素,函数的参数也可以有不定参数
// function fn(name,...val){ //不定参数之后不可再有参数
//     console.log(name);
//     console.log(val);
// }
// fn(name="苏玮一",val=21,'女');
name属性:
//ES6提供了一个name属性用于获取函数名,以方便开发者
// function fn(){

// }

// let f2=function(){};

// let obj={
//     fn3:function(){}
// };

// console.log(fn.name);
// console.log(f2.name);
// console.log(obj.fn3.name);
// console.log((new Function()).name); //匿名函数  anonymous
箭头函数:
//ES6新增了一个使用(=>)箭头有符号的语法特性
// let fn=name=>name;
// console.log(fn(name="苏玮一"));
// //翻译为函数代码
// let fn=function(name){
//     return name;
// }

//箭头函数也可以传递两个或两个以上的参数
// let fn=(x,y)=>x+y;
// console.log(fn(10,20));
// //翻译为函数代码
// let fn=function(x,y){
//     return x+y;
// }

//如果定义的函数,并不需要传递参数,可以用()括号方式直接返回
// let fn=()=>"苏玮一";
// console.log(fn());
//  翻译为函数代码
// let fn=function(){
//     return "苏玮一";
// }

//如果函数体需要更复杂的操作,可以将箭头符号右边使用传统函数体
// let fn=(x,y)=>{
//     return x+y;
// };
// console.log(fn(10,10));

//如果箭头符号右边是对象,返回的是对象,需要用圆括号包含
// let fn=name=>({name:name,age:21});
// console.log(fn(name="苏玮一").name);
// //  翻译为函数代码
// let fn=function(name){
//     return{
//         name:name,
//         age:21
//     }
// }

//如果箭头函数左边是对象作为参数,右边是对象的属性运算
// let fn=({name,age})=>name+","+age;
// console.log(fn({name:"苏玮一",age:"21"}));
//  翻译为函数代码
// let fn=function({name,age}){
//     return{
//         name:name,
//         age:21
//     }
// }

//自我立即执行函数,也可以使用箭头符号来创建
// ((name)=>{
//     console.log(name);
// })("苏玮一")
// //  翻译为函数代码
// (function(name){
//     console.log(name);
// })("苏玮一")
绑定this:
//this在全局的时候指向的是我window,在某个对象内部指向当前对象
//在web环境下,它指向了window,而node环境下指向setTimeout
//将this在setTimeout外部进行赋值保存
let obj={
    name:"苏玮一",
    age:21,
    fn:function(){
        // // console.log(this.name);
        // let that=this;
        // setTimeout(function(){
        //     console.log(that);//obj对象包含类似setTimeout函数内部,这时this指向就出现问题
        //     console.log(that.name+","+that.age);
        // },500);
        //箭头函数彻底解决了this在内部指向的问题,直接指向我们需要的
        //因为箭头函数中的this是最外层定义的函数绑定,不受内部影响
        setTimeout(()=>{
            console.log(this);
            console.log(this.name+","+this.age);
        },500);
    }
}
obj.fn();
箭头扩展:
//箭头函数支持一些内置函数的使用
// let arr=[3,1,2,5,4].sort(function(a,b){
//     return a-b;//[ 1, 2, 3, 4, 5 ]
// })
//翻译为函数代码
// let arr=[3,1,2,5,4].sort((a,b)=>a-b);
// console.log(arr);

//箭头函数不支持arguments绑定,直接用...other模式(rest运算符)
// let fn=(x,y)=>{
//     return arguments[0]+arguments[1];//不支持
// }
//不确定参数 用...other
// let fn=(...val)=>{
//     return val[0]+val[1];
// }
// console.log(fn(10,20));
// //箭头函数和普通函数一样,都可以被typeof和instanceof进行验证
// console.log(typeof fn);
// console.log(fn instanceof Function);
尾调用优化:
什么又是尾调用优化?为何要优化?因为:每次尾调用都会创建栈帧;
 如果尾调次数过多,而内存中的调用栈越来越大,可能就会出现程序问题;
尤其是在递归函数的问题上,尾调用优化适合在这种场景中使用;
 首先要说明,尾调用优化必须是在 ES6 的严格模式下,'use strict';
 严格模式,可以设置为全局作用域,也可以在函数体内有效;
 严格模式对变量、对象和函数做了一些代码规范等等,具体规范可以搜索;
 而对于尾调用,必须严格按照三个规则,才能执行严格模式下的优化,如下:
(1) .尾调用必须 return 返回;  // go(x); 错误
(2) .尾调用 return 返回不得含其它操作 // return go(x) + 1; 错误
(3) .尾调用 return 返回的不是函数,而是函数赋值的变量,不在尾部;
//let result = go(x);
//return result;
//尾调用:在一个函数的最后可执行的一步调用了其他函数
// function go(x){
//     return x+20;
// }
// let fn=function(x){
//     return go(x);
// }
// console.log(fn(10));

//回调函数
// 开启严格模式 'use stirct'
'use stirct'

function fn(x){
    //  console.log(x);
    if(x<=1){
        return 1;
    }
    return fn(x-1);
   
}
fn(10);
新增方法:
//对于一些超过两个字符(四字节)的异体字,ES6 新增了 codePointAt()方法;

//两个字符的异体字,这里用?代替,文档显示不出来,上面土,下面口 
// let text = '?'; 
// console.log(text.length); //2 
// console.log(text.charAt(0)); //? 
// console.log(text.charCodeAt(0)); //55362 
// console.log(text.charCodeAt(1)); //57271 
// console.log(text.codePointAt(0)); //134071,十进制码点

// //一个字符的简体字 
// let text = '吉'; 
// console.log(text.length); //1 
// console.log(text.charAt(0)); //吉 
// console.log(text.charCodeAt(0)); //21513 
// console.log(text.charCodeAt(1)); //NaN 
// console.log(text.codePointAt(0)); //21513

//ES6 提供 normalize()方法用于有音标的符号组合形式进行统一;
// console.log('\u01D1');
// console.log('\u004F');
// console.log('\u030C');
// console.log('\u004F\u030C'.normalize() == '\u01D1'.normalize());

//ES6 提供了三种判断字符串的方法:includes()、startsWith()和 endsWith();
let text = '你好,大美女!';
console.log(text.includes("你"));//true,是否找到'你'
console.log(text.startsWith("你"));//必须从头开始查找
console.log(text.endsWith("!"));//必须从尾部开始查找
console.log(text.includes('你', 8)); //false,超过位置,第二参数寻找的位置

//repeat()重复字符串,padStart()补全字符串头部,padEnd()补全字符串尾部;
console.log('x'.repeat(5)); 
console.log('xyz'.repeat(3)); 
console.log('Mr.Lee'.repeat(0)); //
console.log('x'.padStart(5, 'Mr')); //MrMrx 
console.log('x'.padEnd(5, 'Mr')); //xMrMr

//---------------模板字符串------------------
//在 ES6 之前,字符串内夹杂变量,我们总是通过分离和+号连接解决;
// let name="苏玮一",age=21;
// text="我是"+name+",今年"+age+"岁";
// console.log(text);


//可以直接使用(`)反引号配合${var}模版语法格式,直接实现变量解析功能
//支持多行操作
// text=`我是${name},今年${age}岁`;
// console.log(text);


// 如果我们想在字符串中插入表达式,也可以使用${a + b}模版语法; 
// text = `一加一等于:${1+1}`; 

//${${}}这种模版嵌套的方式,也是支持的;
// text = `结果:${flag ? 'true' : 'false'}`;
//  text = `结果:${flag ? `true${1+1}` : 'false'}`;

//可以使用 String.raw 来得到原生字符串; 
// text = String.raw `我\n 是`;
正则的扩展改进:
// u 修饰符,对占两个字符特殊字进行正则识别;
// let text = '𠮷';
// let result=/吉{2}/.test("吉吉");
// let result=/𠮷{2}/.test("𠮷𠮷");
// console.log(result);

// y 修饰符,它的作用是当匹配过一次后继续往下匹配
// let text = 'xxx_xx_x_', patt = /x+_/y; 
// console.log(patt.exec(text)); //xxx_ 
// console.log(patt.exec(text)); //xx_ 
// console.log(patt.exec(text)); //x_

//对于 y 修饰符,ES6 提供了 stikcy 属性,用来检测是否存在 y 修饰符
// console.log(patt.sticky);
//ES6 提供了 flags 属性,用于返回正则使用的修饰符名称
// console.log(patt.flags);

// . 表示匹配所有,除了终止符,比如回车\n 换行\n 等等,使用 s 修饰符匹配;
// let text="x\nyz",patt = /x.+yz/s; 
// console.log(patt.test(text));;

//ES6 支持修饰符替换,之前会报错 
let regex = new RegExp(/xyz/iu, 'g');
console.log(regex.flags); //g
数值的扩展改进:
// 二进制、八进制和十六进制分别用 0b、0o、0x 作为前缀;
 console.log(Number('0b11')); 
 console.log(Number('0o11')); 
 console.log(Number('0x11'));

 //Number.isFinitel()、Number.isNaN()判断无穷大和 NaN;
 //非数值为 false,数值为 true 
 console.log(Number.isFinite(100)); 
 //NaN 为 true,其余为 false 
 console.log(Number.isNaN(100));

 //Number.parseInt()、Number.parseFloat()转换整型和浮点型;
 console.log(Number.parseInt('55.55a')); 
 console.log(Number.parseFloat('55.555b'));

 //Number.isInteger(),来判断参数是否是一个整型;
 console.log(Number.isInteger(10));

//一个常量,值特别小,用于判断是否得到正确结果
// console.log((0.1 + 0.22 - 0.3).toFixed(20));
console.log(Number.EPSILON); 
console.log(Number.EPSILON.toFixed(30)); // 直观的看
console.log((0.1 + 0.2 - 0.3) < Number.EPSILON);

//ES6+新增了一个指数运算符 **,并且可以进行赋值运算; 
console.log(2 ** 4); //16,4 个 2 相乘 
let num = 2; 
num **= 5; 
console.log(num); //32,5 个 2 相乘

//----------------Math扩展-----------
//ES6 对 Math 对象新增了一些方法.trunc()、.sign()、cbrt()、clz32()  .imul()  .fround()  .hypot()、expm1()、.log1p()、log10()、log2();
console.log(Math.trunc(5.55)); //去掉小数部分