• 箭头函数


    引言

    在 ES6 中,箭头函数是其中最有趣也最受欢迎的新增特性。顾名思义,箭头函数是一种使用 (=>) 定义函数的新语法,它与传统的 ES5 函数有些许不同。

    这是一个用 ES5 语法编写的函数:

    1. function addTennum){

    2. return num +10;

    3. }

    4. timesTwo5);// 15

    有了 ES6 的箭头函数后,我们可以用箭头函数这样表示:

    1. var addTen = num => num +10

    2.  

    3. addTen(5);// 15

    箭头函数的写法短的多!由于隐式返回,我们可以省略花括号和 return 语句。

    与常规 ES5 函数相比,了解箭头函数的行为方式非常重要。

    箭头函数的特点

    更短的语法

    基础语法如下:

    1. (参数)=>{ statements }

    接下来,拆解一下箭头函数的各种书写形式:

    当没有参数时,使用一个圆括号代表参数部分

    1. let f =()=>5;

    2.  

    3. f();// 5

    当只有一个参数时,可以省略圆括号。

    1. let f = num => num +5;

    2.  

    3. f(10);// 15

    当有多个参数时,在圆括号内定义多个参数用逗号分隔。

    1. let f =(a,b)=> a + b;

    2.  

    3. f(1,2);// 3

    当箭头函数的代码块部分多余一条语句,就需要使用大括号括起来,并且使用 return 语句。

    1. // 没有大括号,默认返回表达式结果

    2. let f1 =(a,b)=> a + b

    3. f1(1,2)// 3

    4.  

    5. // 有大括号,无return语句,没有返回值

    6. let f2 =(a,b)=>{a + b}

    7. f2(1,2)// undefined

    8.  

    9. // 有大括号,有return语句,返回结果

    10. let f3 =(a,b)=>{return a + b}

    11. f3(1,2)// 3

    由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。

    1. //报错

    2. let f1 = num =>{num:num}

    3.  

    4. //不报错

    5. let f2 = num =>({num:num})

    不能通过 new 关键字调用

    箭头函数没有[[Construct]]方法,所以不能被用作构造函数。

    1. let F =()=>{};

    2.  

    3. // 报错 TypeError: F is not a constructor

    4. let f =new F();

    没有原型

    由于不可以通过 new 关键字调用,因而没有构建原型的需求,所以箭头函数不存在 prototype 这个属性。

    1. let F =()=>{};

    2. console.log(F.prototype)// undefined

    没有 this 绑定

    在 ES5 函数表达式中,this关键字根据调用它的上下文绑定到不同的值。但是,对于箭头函数,它this是词法绑定的。

    箭头函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。

    1. window.name ='window_name'

    2. let obj ={

    3. name:'obj_name',

    4. f1:function(){

    5. returnthis.name

    6. },

    7. f2:()=>{

    8. returnthis.name

    9. }

    10. }

    11. obj.f1();// obj_name

    12. obj.f2();// window_name

    上面代码中,obj.f1 是一个普通函数,obj.f2 是一个箭头函数。

    当调用 obj.f1() 时,obj.f1 中 this 的指向的是 f1 函数的调用者,也就是 obj,所以返回 'obj_name'。

    当调用 obj.f2() 时,由于 obj.f2 是箭头函数,所以 obj.f2 中this 指向的是定义 obj.f2 时的 this 指向,也就是 window,所以返回 'window_name'。

    对箭头函数使用 call、apply、bind 时,不会改变 this 指向,只会传入参数

    1. window.name ='window_name';

    2.  

    3. let f1 =function(){returnthis.name}

    4. let f2 =()=>this.name

    5.  

    6. let obj ={name:'obj_name'}

    7.  

    8. f1.call(obj)// obj_name

    9. f2.call(obj)// window_name

    10.  

    11. f1.apply(obj)// obj_name

    12. f2.apply(obj)// window_name

    13.  

    14. f1.bind(obj)()// obj_name

    15. f2.bind(obj)()// window_name

    上面代码中,声明了普通函数 f1,箭头函数 f2。

    普通函数的 this 指向是动态可变的,所以在对 f1 使用 call、apply、bind 时,f1 内部的 this 指向会发生改变。

    箭头函数的 this 指向在其定义时就已确定,永远不会发生改变,所以在对 f2 使用 call、apply、bind 时,会忽略传入的上下文参数。

    this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this

    没有 arguments、super、new.target

    箭头函数中是没有 arguments、super、new.target 的绑定,这些值由外围最近一层非箭头函数决定。

    以 arguments 为例,看如下代码:

    1. let f =()=>console.log(arguments);

    2.  

    3. //报错

    4. f();// arguments is not defined

    由于在全局环境下,定义箭头函数 f,对于 f 来说,无法获取到外围非箭头函数的 arguments 值,所以此处报错。

    再看一个例子:

    1. function fn(){

    2. let f =()=> console.log(arguments)

    3. f();

    4. }

    5. fn(1,2,3)// [1,2,3]

    上面的代码,箭头函数 f 内部的 arguments,其实是函数 fn 的 arguments 变量。

    若想在箭头函数中获取不定长度的参数列表,可以使用 ES6 中的 rest 参数解决:

    1. let f =(...args)=>console.log(args)

    2.  

    3. f(1,2,3,4,5)// [1,2,3,4,5]

    不能用作 Generator 函数

    在箭头函数中,不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

    自执行函数

    在 ES6 的箭头函数出现之前,自执行函数一般会写成这样:

    1. (function(){

    2. console.log(1)

    3. })()

    或者写成这样:

    1. (function(){

    2. console.log(1)

    3. }())

    箭头函数当然也可以被用作自执行函数,可以这样写:

    1. (()=>{

    2. console.log(1)

    3. })()

    但是,令大多数人想不到的是,下面这种写法会报错:

    1. (()=>{

    2. console.log(1)

    3. }())

    那么,为什么会报错呢?

    原因是,箭头函数属于 AssignmentExpression 的一种,当 CallExpression 时,要求左边的表达式是 MemberExpression 或其他 CallExpression。

    原理就是这样了,具体可参见ECMAScript® 2015 规范

    关于箭头函数的题目

    在面试中关于箭头函数的考察,主要集中在 arguments 关键字的指向和箭头函数的this指向上,下面几道题目,供大家参考一下。

    先上题目,由浅入深,答案后面给出。

    题目1

    1. function foo(n){

    2. var f =()=> arguments[0]+ n;

    3. return f();

    4. }

    5.  

    6. let res = foo(2);

    7.  

    8. console.log(res);// 4

    题目2

    1. function A(){

    2. this.foo =1

    3. }

    4.  

    5. A.prototype.bar =()=> console.log(this.foo)

    6.  

    7. let a =new A()

    8. a.bar()

    题目3

    1. let res =(function(){

    2. return[

    3. (()=>this.x).bind({ x:'inner'})()

    4. ];

    5. }).call({ x:'outer'});

    6.  

    7. console.log(res)

    题目4

    1. window.name ='window_name';

    2.  

    3. let obj1 ={

    4. name:'obj1_name',

    5. print1:function(){

    6. console.log(this.name)

    7. },

    8. print2:()=>console.log(this.name),

    9. print3:function(){

    10. returnfunction(){

    11. console.log(this.name)

    12. }

    13. },

    14. print4:function(){

    15. return()=>console.log(this.name)

    16. }

    17. }

    18.  

    19. let obj2 ={name:'obj2_name'}

    20.  

    21. obj1.print1()

    22. obj1.print1.call(obj2)

    23. obj1.print2()

    24. obj1.print2.call(obj2)

    25. obj1.print3()()

    26. obj1.print3().call(obj2)

    27. obj1.print3.call(obj2)()

    28. obj1.print4()()

    29. obj1.print4().call(obj2)

    30. obj1.print4.call(obj2)()

    答案如下:

    1. // 题目1:4

    2. // 题目2:undefined

    3. // 题目3:["outer"]

    4. /**

    5. * 题目4:

    6. * obj1.print1() --obj1_name

    7. * obj1.print1.call(obj2) --obj2_name

    8. * obj1.print2() --window_name

    9. * obj1.print2.call(obj2) --window_name

    10. * obj1.print3()() --window_name

    11. * obj1.print3().call(obj2) --obj2_name

    12. * obj1.print3.call(obj2)() --window_name

    13. * obj1.print4()() --obj1_name

    14. * obj1.print4().call(obj2) --obj1_name

    15. * obj1.print4.call(obj2)() --obj2_name

    16. */

    箭头函数

     冰山工作室沙翼 冰山工作室 今天

    在 ES6 中,箭头函数是其中最有趣也最受欢迎的新增特性。顾名思义,箭头函数是一种使用 (=>) 定义函数的新语法,它与传统的 ES5 函数有些许不同。

    引言

    在 ES6 中,箭头函数是其中最有趣也最受欢迎的新增特性。顾名思义,箭头函数是一种使用 (=>) 定义函数的新语法,它与传统的 ES5 函数有些许不同。

    这是一个用 ES5 语法编写的函数:

    1. function addTennum){

    2. return num +10;

    3. }

    4. timesTwo5);// 15

    有了 ES6 的箭头函数后,我们可以用箭头函数这样表示:

    1. var addTen = num => num +10

    2.  

    3. addTen(5);// 15

    箭头函数的写法短的多!由于隐式返回,我们可以省略花括号和 return 语句。

    与常规 ES5 函数相比,了解箭头函数的行为方式非常重要。

    箭头函数的特点

    更短的语法

    基础语法如下:

    1. (参数)=>{ statements }

    接下来,拆解一下箭头函数的各种书写形式:

    当没有参数时,使用一个圆括号代表参数部分

    1. let f =()=>5;

    2.  

    3. f();// 5

    当只有一个参数时,可以省略圆括号。

    1. let f = num => num +5;

    2.  

    3. f(10);// 15

    当有多个参数时,在圆括号内定义多个参数用逗号分隔。

    1. let f =(a,b)=> a + b;

    2.  

    3. f(1,2);// 3

    当箭头函数的代码块部分多余一条语句,就需要使用大括号括起来,并且使用 return 语句。

    1. // 没有大括号,默认返回表达式结果

    2. let f1 =(a,b)=> a + b

    3. f1(1,2)// 3

    4.  

    5. // 有大括号,无return语句,没有返回值

    6. let f2 =(a,b)=>{a + b}

    7. f2(1,2)// undefined

    8.  

    9. // 有大括号,有return语句,返回结果

    10. let f3 =(a,b)=>{return a + b}

    11. f3(1,2)// 3

    由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。

    1. //报错

    2. let f1 = num =>{num:num}

    3.  

    4. //不报错

    5. let f2 = num =>({num:num})

    不能通过 new 关键字调用

    箭头函数没有[[Construct]]方法,所以不能被用作构造函数。

    1. let F =()=>{};

    2.  

    3. // 报错 TypeError: F is not a constructor

    4. let f =new F();

    没有原型

    由于不可以通过 new 关键字调用,因而没有构建原型的需求,所以箭头函数不存在 prototype 这个属性。

    1. let F =()=>{};

    2. console.log(F.prototype)// undefined

    没有 this 绑定

    在 ES5 函数表达式中,this关键字根据调用它的上下文绑定到不同的值。但是,对于箭头函数,它this是词法绑定的。

    箭头函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。

    1. window.name ='window_name'

    2. let obj ={

    3. name:'obj_name',

    4. f1:function(){

    5. returnthis.name

    6. },

    7. f2:()=>{

    8. returnthis.name

    9. }

    10. }

    11. obj.f1();// obj_name

    12. obj.f2();// window_name

    上面代码中,obj.f1 是一个普通函数,obj.f2 是一个箭头函数。

    当调用 obj.f1() 时,obj.f1 中 this 的指向的是 f1 函数的调用者,也就是 obj,所以返回 'obj_name'。

    当调用 obj.f2() 时,由于 obj.f2 是箭头函数,所以 obj.f2 中this 指向的是定义 obj.f2 时的 this 指向,也就是 window,所以返回 'window_name'。

    对箭头函数使用 call、apply、bind 时,不会改变 this 指向,只会传入参数

    1. window.name ='window_name';

    2.  

    3. let f1 =function(){returnthis.name}

    4. let f2 =()=>this.name

    5.  

    6. let obj ={name:'obj_name'}

    7.  

    8. f1.call(obj)// obj_name

    9. f2.call(obj)// window_name

    10.  

    11. f1.apply(obj)// obj_name

    12. f2.apply(obj)// window_name

    13.  

    14. f1.bind(obj)()// obj_name

    15. f2.bind(obj)()// window_name

    上面代码中,声明了普通函数 f1,箭头函数 f2。

    普通函数的 this 指向是动态可变的,所以在对 f1 使用 call、apply、bind 时,f1 内部的 this 指向会发生改变。

    箭头函数的 this 指向在其定义时就已确定,永远不会发生改变,所以在对 f2 使用 call、apply、bind 时,会忽略传入的上下文参数。

    this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this

    没有 arguments、super、new.target

    箭头函数中是没有 arguments、super、new.target 的绑定,这些值由外围最近一层非箭头函数决定。

    以 arguments 为例,看如下代码:

    1. let f =()=>console.log(arguments);

    2.  

    3. //报错

    4. f();// arguments is not defined

    由于在全局环境下,定义箭头函数 f,对于 f 来说,无法获取到外围非箭头函数的 arguments 值,所以此处报错。

    再看一个例子:

    1. function fn(){

    2. let f =()=> console.log(arguments)

    3. f();

    4. }

    5. fn(1,2,3)// [1,2,3]

    上面的代码,箭头函数 f 内部的 arguments,其实是函数 fn 的 arguments 变量。

    若想在箭头函数中获取不定长度的参数列表,可以使用 ES6 中的 rest 参数解决:

    1. let f =(...args)=>console.log(args)

    2.  

    3. f(1,2,3,4,5)// [1,2,3,4,5]

    不能用作 Generator 函数

    在箭头函数中,不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

    自执行函数

    在 ES6 的箭头函数出现之前,自执行函数一般会写成这样:

    1. (function(){

    2. console.log(1)

    3. })()

    或者写成这样:

    1. (function(){

    2. console.log(1)

    3. }())

    箭头函数当然也可以被用作自执行函数,可以这样写:

    1. (()=>{

    2. console.log(1)

    3. })()

    但是,令大多数人想不到的是,下面这种写法会报错:

    1. (()=>{

    2. console.log(1)

    3. }())

    那么,为什么会报错呢?

    原因是,箭头函数属于 AssignmentExpression 的一种,当 CallExpression 时,要求左边的表达式是 MemberExpression 或其他 CallExpression。

    原理就是这样了,具体可参见ECMAScript® 2015 规范

    关于箭头函数的题目

    在面试中关于箭头函数的考察,主要集中在 arguments 关键字的指向和箭头函数的this指向上,下面几道题目,供大家参考一下。

    先上题目,由浅入深,答案后面给出。

    题目1

    1. function foo(n){

    2. var f =()=> arguments[0]+ n;

    3. return f();

    4. }

    5.  

    6. let res = foo(2);

    7.  

    8. console.log(res);// 4

    题目2

    1. function A(){

    2. this.foo =1

    3. }

    4.  

    5. A.prototype.bar =()=> console.log(this.foo)

    6.  

    7. let a =new A()

    8. a.bar()

    题目3

    1. let res =(function(){

    2. return[

    3. (()=>this.x).bind({ x:'inner'})()

    4. ];

    5. }).call({ x:'outer'});

    6.  

    7. console.log(res)

    题目4

    1. window.name ='window_name';

    2.  

    3. let obj1 ={

    4. name:'obj1_name',

    5. print1:function(){

    6. console.log(this.name)

    7. },

    8. print2:()=>console.log(this.name),

    9. print3:function(){

    10. returnfunction(){

    11. console.log(this.name)

    12. }

    13. },

    14. print4:function(){

    15. return()=>console.log(this.name)

    16. }

    17. }

    18.  

    19. let obj2 ={name:'obj2_name'}

    20.  

    21. obj1.print1()

    22. obj1.print1.call(obj2)

    23. obj1.print2()

    24. obj1.print2.call(obj2)

    25. obj1.print3()()

    26. obj1.print3().call(obj2)

    27. obj1.print3.call(obj2)()

    28. obj1.print4()()

    29. obj1.print4().call(obj2)

    30. obj1.print4.call(obj2)()

    答案如下:

    1. // 题目1:4

    2. // 题目2:undefined

    3. // 题目3:["outer"]

    4. /**

    5. * 题目4:

    6. * obj1.print1() --obj1_name

    7. * obj1.print1.call(obj2) --obj2_name

    8. * obj1.print2() --window_name

    9. * obj1.print2.call(obj2) --window_name

    10. * obj1.print3()() --window_name

    11. * obj1.print3().call(obj2) --obj2_name

    12. * obj1.print3.call(obj2)() --window_name

    13. * obj1.print4()() --obj1_name

    14. * obj1.print4().call(obj2) --obj1_name

    15. * obj1.print4.call(obj2)() --obj2_name

    16. */

     

    阅读原文
    阅读 62
     

    写留言

  • 相关阅读:
    LINQ语法详解
    win7下安装IIS7
    jquery ajax跨域请求webservice webconfig配置
    ServiceStack.Hello——跨平台.net REST api服务搭建
    使用ServiceStack构建Web服务
    VS2010插件之NuGet
    jQuery调用WCF
    它在 ServiceHost 指令中提供为 Service 特性值,或在配置元素 system.serviceModel/serviceHostingEnvironment/serviceActivations 中提供
    WCF Service Configuration Editor的使用
    jQuery验证控件jquery.validate.js使用说明+中文API
  • 原文地址:https://www.cnblogs.com/xianxiaoan/p/11084892.html
Copyright © 2020-2023  润新知