JavaScript笔记:函数表达式
来源:互联网 发布:windows 包管理工具 编辑:程序博客网 时间:2024/05/22 11:51
函数表达式是JavaScript中一个很强大又容易令人困惑的特性。
创建函数有两种方式:
// 方式1function sayHi(){ alert("Hi!");}// 方式2var sayHi = function(){ alert("Hi!");};
函数有个很重要的特性就是函数声明提升:意思就是说,在执行代码之前会先读取函数的声明。
闭包
闭包指的是有权访问另一个函数作用域的变量的函数。创建闭包的另一个方式,就是在一个函数中创建另一个函数。
function createComparisonFunction(propertyName) { return function(object1, object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if (value1 < value2){ return -1; } else if (value1 > value2){ return 1; } else { return 0; } };}// 请注意下面这两行代码://var value1 = object1[propertyName];//var value2 = object2[propertyName];
这段代码中,需要注意的两行代码如上所示,这两行代码访问了外部的函数属性propertyName。即使这个内部的函数被返回了,并且在其他地方被调用了,它仍然可以访问变量propertyName。
1、闭包与变量
注意,闭包只能取得包含函数变量中任何变量的最后一个值。也就是说,闭包保存的是整个变量对象,而不是某个特殊的变量。
下面这段代码很能说明问题:
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(){return i; };} return result;}
createFunctions函数返回后,result中的所有返回值都是10;如果我们想要返回值是期望的0-10,应该如下这样写:
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(num){ return function(){ return num; }; }(i); return result;}
上面这段代码通过创建匿名函数达到了目的。
2、关于this对象
我们知道,this对象是在运行的时候根据函数的执行环境绑定的。在全局函数中,this等于window。当函数被某个对象调用时,this则等于那个对象。但是,匿名函数的执行环境具有全局性,因此其this对象通常指向window。
例如:
var name = "The Window";var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; };} };alert(object.getNameFunc()()); //"The Window"
如果在getNameFunc想返回object的name,该如何做呢?只需要在闭包中,将this变量保存下来即可:
var name = "The Window";var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; }};alert(object.getNameFunc()()); //"My Object"
3、内存泄漏
由于IE9之前的版本对JS对象和DOM对象使用不同的垃圾收集例程,因此闭包在这些IE浏览器下就会有一些特殊的问题。具体来说就是,如果闭包的作用域链中保存了HTML元素,那么就意味着,该元素不会被销毁。
看下面的例子:
function assignHandler(){ var element = document.getElementById("someElement"); element.onclick = function(){ alert(element.id); };}
上述代码创建了一个作为element元素事件处理的闭包。由于匿名函数保存了一个对assignHandler活动对象的引用,因此就会导致无法减少element元素的引用数,那么它所占用的内存就永远不会被回收。因此,这段代码应该修改为:
function assignHandler(){ var element = document.getElementById("someElement"); var id = element.id; element.onclick = function(){ alert(id); }; element = null;}
模仿块级作用域
JavaScript没有块级作用域的概念,这意味着,在块语句中定义的变量,实际上是包含在函数中,而非语句中的。例如:
function outputNumbers(count){ for (var i=0; i < count; i++){ alert(i); } alert(i); }
这个函数中定义了一个for循环,在java语言中,一旦for循环结束,变量i也会被销毁。但是在js语言中,i变量会在函数中一直存在,不会被销毁。
匿名函数可以模仿块级作用域来避免这个问题。
(function(){ // 这里是块级作用域})();
以上代码创建了一个匿名函数并立即调用了这个函数。
利用匿名函数,上面的一段代码可以修改为:
function outputNumbers(count){ (function () { for (var i=0; i < count; i++){ alert(i); } })(); alert(i); // 错误}
这种技术经常用来限制向全局作用域中添加过多的变量和函数。一般来说,我们应该少向全局作用域中添加变量和函数,因为在多人参加的大型项目中,这样很容易导致命名冲突的错误。通过创建私有域,大家不必担心搞乱全局作用域,又可以愉快地使用自己的变量。
私有变量
任何在函数内部定义的变量,可以成为私有变量,因为在函数外部不能访问这些变量。
另外,我们把有权访问函数内部私有变量和私有方法的方法称为特权方法。
function myObject(){ // 私有变量和函数 var privateVariable = 10; function privateFunction(){ return false; } // 特权方法 this.publicMethod = function (){ privateVariable++; return privateFunction(); };}
利用私有和特权成员,可以隐藏那些不可以被直接修改的数据。
1、静态私有变量。
通过在私有作用域中定义私有变量和函数,同样可以创建特权方法:
(function(){ // 私有变量和函数 var privateVariable = 10; function privateFunction(){ return false; } // 构造函数 MyObject = function(){ }; // 公有/特权方法 MyObject.prototype.publicMethod = function(){ privateVariable++; return privateFunction(); };})();
需要注意的是,在定义构造函数的时候,我们没有使用函数声明,而是使用了函数表达式。函数声明只能创建局部函数,但那并不是我们想要的。
上面这种方式定义和在构造函数中定义特权方法的区别在于,私有变量和函数是所有对象共享的:
(function(){ var name = ""; Person = function(value){ name = value; }; Person.prototype.getName = function(){ return name; }; Person.prototype.setName = function (value){ name = value; };})();var person1 = new Person("Nicholas"); alert(person1.getName()); //"Nicholas" person1.setName("Greg"); alert(person1.getName()); //"Greg"var person2 = new Person("Michael");alert(person1.getName()); //"Michael"alert(person2.getName()); //"Michael"
我们可以发现了:当对象2修改了name变量,对象1也跟着受到影响。
2、模块模式
为单例创建私有变量和方法:(所谓单例,就是只有一个实例的对象)
var singleton = function(){ // 私有变量和私有函数 var privateVariable = 10; function privateFunction(){ return false; } //特权/公有 return { publicProperty: true, publicMethod : function(){ privateVariable++; return privateFunction(); } }; }();
从本质上讲,这个对象字面量定义的是单例的公共接口。
3、增强的模块模式
单例必须是某种类型,并且还需要添加某些方法和属性的情况。
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;}();
- JavaScript笔记:函数表达式
- JavaScript笔记五:函数表达式
- JavaScript学习笔记---函数和正则表达式
- JavaScript高级程序设计笔记-函数表达式
- JavaScript学习笔记(十) 函数声明VS函数表达式
- JavaScript学习笔记之函数表达式与闭包
- JavaScript笔记整理 —— 函数声明与表达式
- JavaScript高程学习笔记之函数表达式(7)
- javascript函数表达式
- Javascript之函数表达式
- javascript函数表达式
- JavaScript函数表达式
- JavaScript函数表达式
- Javascript 函数表达式
- JavaScript的函数表达式
- JavaScript函数表达式
- JavaScript函数表达式
- 5 javascript 函数表达式
- 想通过自学成为一个有良好计算机专业素养的Java程序员要读哪些书?
- Unique Paths和Unique Paths II 路径
- java23种设计模式十(连载)
- 第一期w1:知识提取
- Newtonsoft.Json的序列化和反序列化
- JavaScript笔记:函数表达式
- Android sharedUserId研究记录
- LINQ to Entities 不识别方法“System.DateTime AddDays(Double)”,因此该方法无法转换为存储表达式。
- RedisMessageListenerService
- jvm学习记录 -- Java内存区域与内存溢出异常
- 从源码分析ArrayList和LinkList的区别
- linux配置java环境变量(详细)
- 数据结构实验之排序七:选课名单
- 剑指offer面试题 java解答51-55