1. 首页
  2. web前端

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

定义函数的方式:

第一种为 函数声明; 第二种为 函数表达式。

语法:

function functionName(arg0, arg1, arg2) {  // 函数体 }

在Firefox,Safari,Chrome和Opera有效:

就是通过这个属性可以访问到这个函数指定的名字。

console.log(functionName.name); // 'functionName'

函数声明:

它的一个重要特点就是:函数声明提升,就是在执行代码前先读取函数声明,可以把函数声明放在调用它的语句后。

// 调用函数 dada(); // 函数声明 function dada() {  console.log('dada'); }

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

使用函数表达式,函数表达式有多种不同的形式

var functionName = function(arg0, arg1, arg2){  // 函数体 }

上面语句,用话语表示,创建一个函数,把它赋值给一个变量,这个函数,我们叫做匿名函数,因为没有函数名称,在关键字function后面是没有标识符的,匿名函数的name值,获取的结果为空字符串。

注意,函数表达式和其他表达式是一样的,需要在使用前必须赋值,否则:

// 调用 da(); var da = function() {  console.log('dada'); }

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

函数声明和函数表达式区别,关键就是在函数提升

// 函数表达式 var dada; if(name) {  dada = function() {   console.log('da1');  }; }else{  dada = function() {   console.log('da2');  }; }

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

递归函数

什么是递归函数,就是一个函数通过名字调用自身。

function da(num) {  if(num < 5) {   return 'da';  }else {   return num * da(num-2);  } }

闭包

闭包就是可以访问 另一个函数中的变量的 函数,创建闭包即是在一个函数内创建另一个函数。

JavaScript 闭包

JavaScript 变量可以是局部变量或全局变量。私有变量可以用到闭包。

闭包就是能够读取其他函数内部变量的函数。

例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。

在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

闭包 (closure)是个精确但又很难解释的电脑名词。

在 Perl 里面,闭包是以 匿名函数的形式来实现,具有持续参照位于该函数范围之外的文字式变数值的能力。这些外部的文字变数会神奇地保留它们在闭包函数最初定义时的值 (深连结)。

在Javascript中闭包的创建过程

function a(){  var i=0;   function b(){   alert(++i);   }  return b; } var c=a(); c();

1、函数b嵌套在函数a内部;
2、函数a返回函数b。

面试官问我:什么是闭包,我该如何回答?

简单讲,就是指有权访问另一个函数作用域中的变量的函数。

它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。

内存泄漏

闭包会引用包含函数的整个变量对象,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素无法被销毁。我们有必要在对这个元素操作完之后主动销毁。

function da() {  var element = document.getElementById('nameDa');  var id = element.id;  element.onclick = function() {   console.log(id);  };  element = null; }

函数内部的定时器

当函数内部的定时器引用了外部函数的变量对象时,该变量对象不会被销毁。

(function() {   var da = 0;  setInterval(function() {   console.log(da++);  },1000); })();

运用闭包的过程

闭包引用外部函数变量对象中的值,在外部函数的外部调用闭包。

求和的函数是这样定义的:

function sum(arr) {     return arr.reduce(function (x, y) {         return x + y;     }); }  sum([1, 2, 3, 4, 5]); // 15

函数表示:

function lazy_sum(arr) {     var sum = function () {         return arr.reduce(function (x, y) {             return x + y;         });     }     return sum; }  var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()  f(); // 15

闭包特点:

让外部访问函数内部变量成为可能;
局部变量会常驻在内存中;
可以避免使用全局变量,
防止全局变量污染;
会造成内存泄漏
(有一块内存空间被长期占用,而不被释放)

每个执行环境都有一个表示变量的对象,变量对象,一般作用域链中包含两个变量对象,本地活动对象和全局变量对象,作用域链的本质就是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

在函数中访问一个变量时,会从作用域链搜索具有相同的名字的变量,一般地,当函数执行完成后,局部活动对象就会被销毁,内存中保存全局作用域。

一个内部函数会将它的外部函数的活动对象添加到它的作用域链中。闭包会带着它的函数的作用域,会占用更多的内存,多度使用闭包会导致内存占用过多。

函数表达式可以不用命名,就可以实现动态编程,函数表达式不需要名称,函数声明要求要有名字,没有名字的函数表达式叫做匿名函数,递归函数使用arguments.callee来递归地调用自身。

闭包的作用域链包含着自己的作用域,包含函数的作用域和全局作用域,一般,函数的执行后会被销毁,但是,函数返回一个闭包,这个函数的作用域将会一直在内存中保存到闭包不存在为止。

模块模式是为单例创建私有变量和特权方法。单例就是只有一个实例的对象,是以对象字面量的方法创建单例对象。

var da = {  name: 'dada',  eat: function() {   // 代码  } };

私有建立和私有函数

var singleton = function(){   //私有变量和私有函数  var privateVariable = 10;   function privateFunction(){   return false;   }  //特权/公有方法和属性  return {   publicProperty: true,   publicMethod : function(){   privateVariable++;   return privateFunction();   }   };  }();
var application = function(){   //私有变量和函数  var components = new Array();   //初始化  components.push(new BaseComponent());   //公共  return {   getComponentCount : function(){   return components.length;   },   registerComponent : function(component){   if (typeof component == "object"){   components.push(component);   }   }   };  }(); 
var singleton = function(){   //私有变量和私有函数  var privateVariable = 10;   function privateFunction(){   return false;   }   //创建对象  var object = new CustomType();   //添加特权/公有属性和方法  object.publicProperty = true;   object.publicMethod = function(){   privateVariable++;   return privateFunction();   };   //返回这个对象  return object;  }(); 
 var application = function(){   //私有变量和函数  var components = new Array();   //初始化  components.push(new BaseComponent());   //创建 application 的一个局部副本  var app = new BaseComponent();   //公共接口  app.getComponentCount = function(){   return components.length;   };   app.registerComponent = function(component){   if (typeof component == "object"){   components.push(component);   }   };   return app;  }();

模仿块级作用域

function outputNumbers(count){   for (var i=0; i < count; i++){   alert(i);   }   alert(i); //计数 }
function outputNumbers(count){   for (var i=0; i < count; i++){   alert(i);   }   var i; //重新声明变量  alert(i); //计数 }

闭包包含的是整个变量对象

function createFunctions(){   var result = new Array();   for (var i=0; i < 10; i++){   result[i] = function(){   return i;   };   }   return result;  }
function createFunctions(){   var result = new Array();   for (var i=0; i < 10; i++){   result[i] = function(num){   return function(){   return num;   };   }(i);  }   return result;  }

this

this,在全局函数中,this等价于window,当函数被作为某个对象的方法调用时,this等价于那个对象。

var name = "The Window";  var object = {   name : "My Object",   getNameFunc : function(){   return function(){   return this.name;   };   }  };  alert(object.getNameFunc()());  //"The Window"(在非严格模式下)

任何在函数中定义的变量,都可以认为是私有变量,因不能在函数的外部访问这些变量。

私有变量包含函数的参数,局部变量和函数内部定义的其他函数。

function add(num1, num2){   var sum = num1 + num2;   return sum;  }
function MyObject(){   //私有变量和私有函数  var privateVariable = 10;   function privateFunction(){   return false;   }   //特权方法  this.publicMethod = function (){   privateVariable++;   return privateFunction();   };  }
function Person(name){   this.getName = function(){   return name;   };   this.setName = function (value) {   name = value;   };  }  var person = new Person("dada");  alert(person.getName()); //"dada"  person.setName("da");  alert(person.getName()); //"da"

静态私有变量

(function(){   //私有变量和私有函数  var privateVariable = 10;   function privateFunction(){   return false;   }   //构造函数  MyObject = function(){   };   //公有/特权方法  MyObject.prototype.publicMethod = function(){   privateVariable++;   return privateFunction();   };  })();

JavaScript this 关键字

面向对象语言中 this 表示当前对象的一个引用。

但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。

在方法中,this 表示该方法所属的对象。
如果单独使用,this 表示全局对象。
在函数中,this 表示全局对象。
在函数中,在严格模式下,this 是未定义的(undefined)。
在事件中,this 表示接收事件的元素。
类似 call() 和 apply() 方法可以将 this 引用到任何对象。

this 总是返回一个对象,简单说,就是返回属性或方法“当前”所在的对象。

this.property上面代码中, this 就代表 property 属性当前所在的对象。

var obj = {   foo: function () {} };  var foo = obj.foo;  // 写法一 obj.foo()  // 写法二 foo()

虽然obj.foo和foo指向同一个函数,但是执行结果可能不一样

var obj = {   foo: function () {    console.log(this.bar)    },   bar: 1 };  var foo = obj.foo; var bar = 2;  obj.foo() // 1 foo() // 2

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

var obj = { foo:  5 };

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

变量obj是一个地址(reference)。后面如果要读取obj.foo,引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的foo属性。

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域

http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

原创文章,作者:怪小克

本文来自投稿,不代表 怪小克 立场,如若转载,请注明出处:https://wangchaoke.cn/?p=2123

本站发布的内容若侵犯到您的权益,请邮件联系 860095347@qq.com 删除,我们将及时处理!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

860-095-347

在线咨询:点击这里给我发消息

邮件:860095347@@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code