递归

function factorial(num){
if(num<=1){
return 1;
}else {
return num * arguments.callee(num-1);
}
} console.log(factorial(4));

但是如果代码是在严格模式下开发:

"use strict";
function factorial(num){
if(num<=1){
return 1;
}else {
return num * arguments.callee(num-1);
}
} console.log(factorial(4));

结果:Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them

在严格模式下不能通过脚本访问arguments.callee,访问这个属性会报错,那么可以使用命名函数表达式来达到相同的结果:

"use strict";
var factorial = (function f(num){
if(num<=1){
return 1;
}else {
return num * f(num-1);
}
}) console.log(factorial(4)); //

以上代码创建了一个名为f()的命名函数表达式,然后将它赋值给变量factorial,即是把函数赋值给另外一个变量,函数的名字仍然有效。

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。

闭包与变量

作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。

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等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window。

var name = "The window";

var object = {
name: "My Object",
getNameFunc: function(){
return function(){
return this.name;
};
}
}; console.log(object.getNameFunc()()); // The window

不过,把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了。

var name = "The window";

var object = {
name: "My Object",
getNameFunc: function(){
var that = this;
return function(){
return that.name;
};
}
}; console.log(object.getNameFunc()()); // My Object

看下面代码:

var name = "The window";
var object = {
name: "My Object",
getName: function(){
console.log(this.name);
}
} object.getName(); // My Object
(object.getName)(); // My Object
(object.getName = object.getName)(); // The window

来分析下调用的结果:

第一行代码跟平常一样调用了object.getName()返回了My Object ,因为this.name就是object.name。

第二行代码在调用这个方法之前给它加了一个括号。虽然加了一个括号后,就好像只是在引用一个函数,但是this的值得到了维持,因为object.getName(object.getName)的定义是相同的。

第三行代码先执行了一条赋值语句,然后再调用赋值后的结果。因为这个赋值表达式的值是函数本身,所以this的值不能得到维持,结果就返回了The window

当然你不大可能像第二行和第三行代码一样调用这个方法。这个例子只是说明了一个细微的语法变化,都有可能意外的改变this的值。

内存泄露

function assignHandler(){
var element=document.getElementById('someElement');
element.onclick=function(){
alert(element.id);
}
}

上述代码它所占用的内存不会永远消失。修改一下代码如下解决:

function assignHandler(){
var element = document.getElementById('someElement');
var id = element.id;
element.onclick = function(){
alert(id);
}
element = null;
}

模仿块级作用域

用块级作用域(通常称为私用作用域)的匿名函数的语法如下所示:

(function(){
})();

私有变量

function add(num1,num2){
var sum=num1+num2;
return sum;
}

在这个函数内部,有三个私有变量:sum,num1,num2。在函数内部可以访问这几个变量。但是在函数外部则不能访问它们。如果在这个函数内部创建一个闭包,那么闭包可以通过自己的作用域链也可以访问这些变量。而利用这一点,就可以创建用于访问私有变量的公有方法。

我们把有权访问私有变量和私有函数的公有方法称为特权方法。有两种在对象上创建特权方法的方式。第一种是在构造函数中定义特权方法。基本模式如下:

function myObejct(){
//私有变量和私有函数
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("Nicholas");
alert(person.getName());//Nicholas
person.setName("Greg");
alert(person.getName());//Greg

静态私有变量

通过在私有作用域中定义私有变量或函数,同样也可以创建特权方法。其基本模式如下:

(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");
console.log(person1.getName()); //Nicholas
person1.setName('Grey');
console.log(person1.getName()); //Grey var person2 = new Person("Michael");
console.log(person1.getName()); //Michael
console.log(person2.getName()); //Michael

在一个实例上调用setName()会影响所有的实例。

模块模式

模块模式是为单例创建私有变量和特权方法。所谓单例,指的就是只有一个实例的对象。按照惯例,js是以对象字面量的方式来创建单例对象的。

var singleton={
name:value,
method:function(){
//这里是方法的代码
}
};

模块模式通过为单例添加私有变量和特权方法能够使其得到增强。其语法形式如下:

var singleton=function(){
//私有变量和私有函数
var privateVariable=10; function privateFunction(){
return false;
}
//特权/公有属性和方法
return {
publicProperty:true,
publicMethod:function(){
privateVariable++;
return privateFunction();
}
}
}();

增强的模块模式

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高级程序设计》笔记:函数表达式(七)的更多相关文章

  1. 读javascript高级程序设计03-函数表达式、闭包、私有变量

    一.函数声明和函数表达式 定义函数有两种方式:函数声明和函数表达式.它们之间一个重要的区别是函数提升. 1.函数声明会进行函数提升,所以函数调用在函数声明之前也不会报错: test(); functi ...

  2. 《JAVASCRIPT高级程序设计》创建对象的七种模式

    细看javascript创建对象模式的诞生,具体的脉络为:不使用任何模式——工厂模式——构造函数模式——原型模式——组合使用构造函数模式——动态原型模式——寄生构造函数模式——稳妥构造函数模式.每一种 ...

  3. JavaScript高级程序设计笔记(一)

    ---恢复内容开始--- 前三章为基础知识,为了方便以后查看,所以比较啰嗦.这里对函数的基本操作没有记录. 1.JavaScript的实现 虽然 JavaScript 和 ECMAScript 通常都 ...

  4. JavaScript高级程序设计笔记之面向对象

    说起面向对象,大部分程序员首先会想到 类 .通过类可以创建许多具有共同属性以及方法的实例或者说对象.但是JavaScript并没有类的概念,而且在JavaScript中几乎一切皆对象,问题来了,Jav ...

  5. javascript高级程序设计--笔记01

    概述 JavaScript的实现包含三个部分: 1  核心(ECMAScript)   提供核心语言功能 2  文档对象模型(DOM)  一套提供了访问以及操作网页内容的API 3  浏览器对象模型( ...

  6. javascript事件小结(事件处理程序方式)--javascript高级程序设计笔记

    1.事件流:描述的是从页面中接收事件的顺序. 2.事件冒泡:IE的事件流叫做事件冒泡,即事件开始从具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到不具体的节点(文档). 3.事件捕获 ...

  7. Javascript高级程序设计笔记(很重要尤其是对象的设计模式与继承)

    var obj = {'a':'a'}; var fun = function (){} console.log(typeof obj);//object console.log(typeof fun ...

  8. JavaScript高级程序设计笔记 事件冒泡和事件捕获

    1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...

  9. JavaScript高级程序设计之函数性能

    setTimeout 比 setInterval 性能更好 // 取代setInterval setTimeout(function self () { // code goes here setTi ...

  10. JavaScript高级程序设计之函数

    函数实际上是对象,每个函数都是Function类型的实例. 函数是引用类型. 函数名实际上是一个指向函数对象的指针,不会与某个函数绑定. // 这种写法更能表达函数的本质 var sum = func ...

随机推荐

  1. 『Möbius函数与Möbius反演』

    Möbius函数 定义 设正整数\(n\)算数基本定理分解后为\(n=\prod_{i=1}^{k}p_i^{a_i}\),定义函数 \[ \mu(n)= \begin{cases} 0\ \ (\e ...

  2. [译] PEP 255--简单的生成器

    我正打算写写 Python 的生成器,然而查资料时发现,引入生成器的 PEP 没人翻译过,因此就花了点时间翻译出来.如果在阅读时,你有读不懂的地方,不用怀疑,极有可能是我译得不到位.若出现这种情况,我 ...

  3. Unity C#笔记 委托&事件

    C#的委托与事件搭配,即是观察者模式的一种实现. 因为观察者模式的原理很易懂,不作多讲,本文纯粹用于记录语法. delegate(委托) //声明没有参数,没有返回值的委托类型XXXX public ...

  4. DSAPI显示PNG异形窗体

    使用DSAPI实现PNG异形窗体,注意,该窗体为层样式窗体,以PNG或32位带透明通道的图像合成到屏幕,此方法不会触发窗体的重绘,故原窗体(包括其子控件)均不会显示,如果需要更新画面,需要重新用代码等 ...

  5. bat脚本自定义魔兽warIII运行分辨率,去黑边

    我们一般平时安装完WarIII后运行时的分辨率默认是800*600,导致有黑边的存在.所以我写了一个bat脚本来自定义WarIII的运行分辨率.需要以管理员身份运行. 下载链接: 链接:https:/ ...

  6. Vue应用框架整合与实战--Vue技术生态圈篇

    实用框架以及工具 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 UI组件 Element-UI ★13489 - 饿了么出品的Vue2的web UI工具套件 Vux ★8133 ...

  7. Sitecore® 8.2 Professional Developer考试心得

    因工作原因入了Sitecore的坑.. 不了解Sitecore认证考试的同学请移步: http://www.cnblogs.com/edisonchou/archive/2018/08/17/9488 ...

  8. PTA 深入虎穴 (正解)和树的同构

    在上一篇博客中分享了尝试用单链表修改程序,虽然在Dev上运行没有错误,但是PTA设置的测试点有几个没有通过,具体不清楚问题出现在哪里,所以现在把之前正确的程序放在这里. 7-2 深入虎穴 (30 分) ...

  9. Sublime Text2支持Vue语法高亮显示

    1.下载vue语法高亮插件vue-syntax-highlight 下载地址:https://github.com/vuejs/vue-syntax-highlight 2.将vue-syntax-h ...

  10. Appium在Android7.0及以上系统运行时报错的解决方案

    背景:在使用Samsung S系列手机进行自动化测试时,发现同样脚本的情况下华为荣耀系列可以正常运行,最终发现差异在于Android7.0及以上系统和appium版本不匹配,需要升级appium.但需 ...