JavaScript闭包与箭头函数

闭包

闭包是JavaScript中最强大的特性之一

JavaScript允许函数嵌套

内部函数可以访问定义在外部函数中的所有变量和函数以及外部函数能访问的所有变量和函数

外部函数不能够访问定义在内部函数中的变量和函数

当内部函数生存周期大于外部函数时,由于内部函数可以访问外部函数的作用域,定义在外部函数的变量和函数的生存周期就会大于外部函数本身

当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了

var pet = function(name) {   // The outer function defines a variable called "name"
  var getName = function() {
    return name;             // The inner function has access to the "name" variable of the outer function
  }
  return getName;            // Return the inner function, thereby exposing it to outer scopes
},
myPet = pet("Vivie");
   
myPet();                     // Returns "Vivie"

下面例子,返回了一个包含可以操作外部函数的内部变量方法的对象

var createPet = function(name) {
  var sex;
  
  return {
    setName: function(newName) {
      name = newName;
    },
    
    getName: function() {
      return name;
    },
    
    getSex: function() {
      return sex;
    },
    
    setSex: function(newSex) {
      if(typeof newSex == "string" 
        && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
pet.getName();                  // Vivie

pet.setName("Oliver");
pet.setSex("male");
pet.getSex();                   // male
pet.getName();                  // Oliver

内嵌函数的内嵌变量就像内嵌函数的保险柜。它们会为内嵌函数保留“稳定”——而又安全——的数据参与运行。而这些内嵌函数甚至不会被分配给一个变量,或者不必一定要有名字。

var getCode = (function(){
  var secureCode = "0]Eal(eh&2";    // A code we do not want outsiders to be able to modify...
  
  return function () {
    return secureCode;
  };
})();

getCode();    // Returns the secret code

注意:如果一个闭包的函数用外部函数的变量名定义了同样的变量,那在外部函数域将再也无法指向该变量。

var createPet = function(name) {  // Outer function defines a variable called "name"
  return {
    setName: function(name) {    // Enclosed function also defines a variable called "name"
      name = name;               // ??? How do we access the "name" defined by the outer function ???
    }
  }
}

闭包中的神奇变量this是非常诡异的。 使用它必须十分的小心,因为this指代什么完全取决于函数在何处被调用,而不是在何处被定义。

使用arguments对象

函数的实际参数会被保存在一个类似数组的arguments对象中。在函数内,你可以按如下方式找出传入的引数:

arguments[i]

  • 其中i是引数的序数编号,以0开始
  • 第一个传来的参数会是arguments[0]
  • 参数的数量由arguments.length表示

例如,设想有一个用来连接字符串的函数。唯一事先确定的参数是在连接后的字符串中用来分隔各个连接部分的字符(译注:比如例子里的分号“;”)。该函数定义如下:

function myConcat(separator) {
   var result = "", // initialize list
       i;
   // iterate through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
   }
   return result;
}

你可以给这个函数传递任意数量的参数,它会将各个参数连接成一个字符串“列表”:

// returns "red, orange, blue, "
myConcat(", ", "red", "orange", "blue");

// returns "elephant; giraffe; lion; cheetah; "
myConcat("; ", "elephant", "giraffe", "lion", "cheetah");

// returns "sage. basil. oregano. pepper. parsley. "
myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");

注意

  • arguments 变量只是 “类数组对象”,并不是一个数组
  • 称其为类数组对象是说它有一个索引编号和Length属性
  • 它并不拥有全部的Array对象的操作方法

函数参数

两个新的类型的参数:

  • 默认参数(default parameters)
  • 剩余参数(rest parameters)

默认参数

在JavaScript中,函数参数的默认值是undefined

function multiply(a, b) {
  b = typeof b !== 'undefined' ?  b : 1;

  return a*b;
}

multiply(5); // 5

调用函数时没有实参传递给b,那么它的值就是undefined,于是计算a*b得到、函数返回的是 NaN

剩余参数

剩余参数语法允许将不确定数量的参数表示为数组

function multiply(multiplier, ...theArgs) {
  return theArgs.map(x => multiplier * x);
}

var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]

箭头函数

箭头函数表达式(也称胖箭头函数, fat arrow function)具有较短的语法相比函数表达式和词法绑定此值。箭头函数总是匿名的。

有两个因素会影响介绍箭头函数:

  • 更简洁的函数
  • this
更简洁的函数
var a = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryl­lium"
];
var a2 = a.map(function(s){ return s.length });
var a3 = a.map( s => s.length );

this

在箭头函数出现之前,每一个新函数都重新定义了自己的this值(在严格模式下,一个新的对象在构造函数里是未定义的,通过上下文对象调用的函数被称为“对象方法”等)

function Person() {
  // The Person() constructor defines `this` as itself.
  this.age = 0;

  setInterval(function growUp() {
    // In nonstrict mode, the growUp() function defines `this` 
    // as the global object, which is different from the `this`
    // defined by the Person() constructor.
    this.age++;
  }, 1000);
}
var p = new Person();

在ECMAScript 3/5里,通过把this的值赋值给一个变量可以修复这个问题

function Person() {
  var self = this; // Some choose `that` instead of `self`. 
                   // Choose one and be consistent.
  self.age = 0;

  setInterval(function growUp() {
    // The callback refers to the `self` variable of which
    // the value is the expected object.
    self.age++;
  }, 1000);
}

另外,创建一个约束函数(bound function)可以使得this值被正确传递给growUp()函数

箭头功能捕捉闭包上下文的this值,所以下面的代码工作正常

function Person(){
  this.age = 0;
  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}
var p = new Person();

ok~就这样

Last modification:May 13th, 2018 at 12:21 am

© The copyright belongs to the author

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏磐创AI技术团队的专栏

2018 年最常见的 Python 面试题 & 答案

https://data-flair.training/blogs/python-tutorial/

14510
来自专栏河湾欢儿的专栏

第五节正则

9120
来自专栏从流域到海域

Python yield关键字 和 Generator(生成器)

Generators functions allow you to declare a function that behaves like an itera...

270100
来自专栏java一日一条

MySQL函数大全及用法示例(一)

1、字符串函数 ascii(str) 返回字符串str的第一个字符的ascii值(str是空串时返回0) mysql> select ascii('2...

12720
来自专栏积累沉淀

Python快速学习第四天

第四天: 条件 、循环和其他语句 1、    print 使用逗号输出 - 打印多个表达式也是可行的,但要用逗号隔开 >>> print 'tanggao ',...

197100
来自专栏PHP在线

PHP部分字符串函数汇总

我们大家知道无论哪种语言,字符串操作都是一个重要的基础,往往是简单而重要。PHP给我们提供了大量的字符串操作函数,功能强大,使用也比较简单,这里为大家总结九类字...

35960
来自专栏从流域到海域

Python dict(字典)

Python dict即字典,是一种非常有用的数据结构,相当于其他语言的Map,这种数据结构采用键值对(key-value)形式存储,具有非常快的查询速度...

38790
来自专栏大前端_Web

javascript中的for in 和 in运算符

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

13520
来自专栏前端真相

JavaScript基础(3)

19850
来自专栏塔奇克马敲代码

第2章 变量和基本类型

20940

扫码关注云+社区

领取腾讯云代金券