js学习笔记4(函数)

1.箭头函数

ES6新增属性。箭头函数特别适合嵌入函数的场景。

    //只有一个参数,括号可以省略
    let double = x => {return 2 * x};
    let tripble = (x) => {return 2 * x};

    //没有参数需要括号
    let getRandom = () => {return Math.random();};

    //有多个参数需要括号
    let sum = (a, b) => {return a + b}
    /**
     * 箭头函数也可以不使用大括号,但这会改变函数的行为。如果不使用大括号
     * 那么箭头后面就只能有一行代码(赋值操作或者表达式),而且省略大括号
     * 会隐式返回这行代码的值。
     */
    let fun1 = (x) => {return 2 * x;}
    let fun2 = (x) => 2 * x; //等于上面的写法
    let fun3 =  (x) => return  2 * x ; //无效写法

箭头函数虽然语法简介,但是很多场合不适用。箭头函数不能使用arguments、super、new.target,也不能用作构造函数。箭头函数也没有protptype属性。

2.函数名

因为函数名就是指向函数的指针,所以它们跟其他包含对象指针的变量具有相同的行为。
在ES6中,所有的函数对象都会暴露一个只读的name属性,其中包含关于函数的信息。

    function sum(num1, num2) { return num1 + num2; }
    console.log(sum(1,2)); //3
    let anotherSum = sum;
    sum = null;
    console.log(anotherSum(1,2)); //3
    console.log(anotherSum.name) //sum 返回的是方法名
    anotherSum.name = '小马哥';
    console.log(anotherSum.name) //sum  name属性只读,不能修改
3.理解参数

ECMAScript函数即不关心传入的参数个数,也不关心这些参数的数据类型。定义函数时要接收2个参数,并不意味着调用的时候就要传入2个参数,可以传1个,3个甚至一个都不传。事实上,在使用function关键字定义(非箭头)函数时,可以在函数的内部访问arguments对象,从中获取传进来的每个参数值。arguments是一个类数组对象(不是Array的实例)

    function sayHi(name, message) {
        console.log(arguments.length);  //2
        return '小马哥对' + name + '说' + message;
    }

    function sayHello() {
        console.log(arguments.length);  //2
        return '小马哥对' + arguments[0] + '说' + arguments[1];
    }

    let sayHello2 = () => {
        return '小马哥对' + arguments[0] + '说' + arguments[1];
    }
    
    console.log(sayHi('韩梅梅', '今天加班'))       //小马哥对韩梅梅说今天加班
    console.log(sayHello('韩梅梅', '今天加班'))    //小马哥对韩梅梅说今天加班
    console.log(sayHello2('韩梅梅', '今天加班'))   //报错

箭头函数中的参数:如果函数是使用箭头函数语法定义的,那么传给函数的参数不能使用arguments关键字访问,而只能通过定义的命名参数访问。

    function foo(){
        let sayHello = () => {
            console.log( '小马哥对' + arguments[0] + '说' + arguments[1]);   //小马哥对韩梅梅说今天加班
        }
        sayHello();
    }
    foo('李雷','你也加班');
4.没有重载

ECMAScript函数如果定义了同名函数,则后面定义的会覆盖先定义的。

5.默认参数值

在ECMAScript5.1及以前,实现默认参数的一种常用方式就是检测某个参数是否等于undefined。在ES6开始可以支持显示定义默认参数。

   function sayName(name = '小马哥') {
        console.log('myName==' + name);
    }
    sayName('孙红雷');  //myName==孙红雷
    sayName();  //myName==小马哥
6.参数扩展与收集

ES6新增了扩展操作符,使用它可以非常简洁地操作和组合数据。扩展操作符最有用的场景就是函数定义中的参数列表。

  • 6.1扩展参数:对于可迭代对象应用扩展操作符,并将其作为一个参数传入,可以将可迭代对象拆分,并将返回的每个值单独传入。
    let values = [1, 2, 3, 4]
    function getSum() {
        let sum = 0;
        for (let i = 0; i < arguments.length; i++) {
            sum += arguments[i];
        }
        return sum;
    }
    console.log(getSum.apply(null, values)); //10---es5写法
    console.log(getSum(-1,...values,5)); //14
    console.log(getSum(...values,5,6,7,8,9,10));//55
    console.log(getSum(...values,...[5,6,7,8,9,10]));//55
    console.log(getSum(5,...values,...[5,6,7,8,9,10]));//60
  • 6.2收集参数: 在构思函数定义时,可以使用扩展操作符把不同长度的独立参数组合为一个数组。类似于arguments对象的构造机制,只不过收集参数的结果会得到一个Array实例。
    let ignorFirst = (firstValue, ...values) => {
        console.log(values);
    }
    ignorFirst()   // []
    ignorFirst(1,2,3,4,5)   //[2, 3, 4, 5]
7.函数内部(arguments,this,new.target)
  • arguments对象:这个对象只有以function关键字定义函数时候才会有,主要用于包含函数参数。arguments还有一个callee属性,是指向arguments对象所在函数的指针。
    function factorial(num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * arguments.callee(num - 1);  //指向当前对象所在的函数
        }
    }

    let trueFactorial = factorial;
    factorial = function () {
        return 0;
    }
    console.log(trueFactorial(5))   //120
    console.log(factorial(5))   //0
  • this对象:在标注函数(指向调用该函数的上下文)和箭头函数中(指向定义该函数的上下文)有不同的行为。
    在标准函数中:this引用的是把函数当成方法调用的上下文对象,通常这个时候,称其为this值(在网页的全局上下文中调用函数时,this指向windows)。
 window.color = 'red';
    let o = {
        color: 'blue',
    }
    function sayColor() {
        console.log(this.color);
    }
    sayColor()  //red
    o.sayColor = sayColor;
    //调用的时候,函数调用者变更为o,this指向o
    o.sayColor();   //blue

在箭头函数中:this引用的是定义箭头函数的上下文,在事件回调或者定时回调中调用某个函数,this指向的并非想要的对象。此时将回调函数写成箭头函数就可以解决这个问题。因为箭头函数中的this会保留定义该函数时的上下文。

    window.color = 'red';
    let o = {
        color: 'blue',
    }
    let sayColor = () => console.log(this.color);
    sayColor()  //red
    o.sayColor = sayColor;
    o.sayColor();   //red
  • caller属性:这个属性引用的是调用当前函数的函数,或者如果的在全局作用域中调用的则为null。
  function outer(){
       let  arr =[];
       for (let i=0;i<20;i++){
           arr[i] = i;
       }
       inner();
   }
   function inner(){
       let  arr =[];
       for (let i=0;i<20;i++){
           arr[i] = i;
       }
       console.log(inner.caller)  //outer的源代码
       console.log(arguments.callee.caller) //等价于上面
   }
   outer();
  • new.target属性(ES6新增): 检测函数是否使用new关键字调用的new.target属性。如果函数是正常调用的则new.target的值是undefined,反之将引用被调用的构造函数。
8.函数属性与方法(length,prototype,apply(),call())
  • length:表示该函数方法的入参个数。
  • prototype:保存引用类型所有实例方法的地方,就意味着toString()、valueOf()等方法都保存在prototype上,进而由所有实例共享。在ES5中,prototype属性是不可枚举的,因此使用for-in循环不会返回这个属性。
  • apply():这个方法都会以指定的this值来调用函数,即会设置调用函数时函数体内的this对象的值。apply()接收两个参数:函数体内this的值和一个参数数组。第二个参数可以是Array的实例,但也可以是arguments对象。
  • call():方法作用和apply()一样,只是传参的形式不同,第一个参数是this,后面的参数必须一个一个列出来。
   function sum(num1,num2){
        return num1 + num2;
    }
    function sum2(num1,num2){
        return sum.apply(this,arguments)
    }
    function sum3(num1,num2){
        return sum.call(this,num1,num2);
    }
    console.log(sum2(20,30)); //50
    console.log(sum3(20,30)); //50

apply()和call(),更重要的作用是控制函数调用上下文,即函数体内this值的能力。

window.color = 'red';
    let o = {
        color: 'blue'
    };
    function sayColor() {
        console.log(this.color);
    }
    sayColor();    //red
    sayColor.call(this);    //red
    sayColor.apply(window);    //red    
    sayColor.apply(o);    //blue
    sayColor.call(o);    //blue
9.闭包

匿名函数经常被人误以为是闭包。闭包指的是那些引用了另一个函数作用域变量的函数,通常是在嵌套函数中实现的。

    function compare(propertyName) {
        return function (object1, object2) {
            //内部函数(匿名函数)引用了外部函数的变量propertyName
            let value1 = object1[propertyName];
            let value2 = object2[propertyName];
            return value1 === value2 ? 0 : value1 > value2 ? 1 : -1;
        }
    }

在这个内部函数被返回并在其他地方被使用后,它仍然引用着哪个变量。因为这是因为内部函数的作用域链包含compare()函数的作用域。

10.this 对象

在闭包中使用this会让代码变复杂。如果内部函数没有使用箭头函数定义,则this对象会在运行时绑定到执行函数的上下文。如果在全局函数中调用,非严格模式下,this等于window。

  window.identity = 'The Window';
    let object = {
        identity: 'My Object',
        getIdentityFunc() {
            return function () {
                return this.identity;
            }
        }
    }
    console.log(object.getIdentityFunc()())     //The Window

object.getIdentityFunc()返回函数,所以object.getIdentityFunc()()立即调用返回的函数,从而得到一个字符串。每个函数在被调用的时候都会创建两个特殊的变量:this和arguments。内部函数用于不可能直接(可以间接,箭头函数或者使用变量)访问外部函数的这两个变量。

11.立即调用的函数表达式

立即调用的函数表达式又称为立即嗲用的函数表达式(IIFE)。类似于函数声明,但是由于被包含在括号中,所以会被解释为函数表达式。紧跟在第一组括号后面的第二组括号会立即调用前面的函数表达式。在ES5.1及以前,为了防止变量定义外泄,IIFE是个非常有效的方式。也不会导致闭包相关的内存问题,因为不存在对这个函数的引用,为此,只要函数执行完毕,其作作用域链就可以被销毁。

    (function () {
        //块级作用域
    })();
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容