JavaScript高级程序设计(五)-函数表达式

函数表达式

函数表达式

定义函数

函数声明

function functionName(arg0,arg1){
	// 函数体
}
// Firefox Safari Chrome,Opera 有效 就是IE不行呗
console.log(functionName.name) // functionName

关于函数声明,最重要的特征就是函数声明提升,意思是在执行代码之前会先读取函数声明,这就意味这可以把函数声明放在调用它的语句后面。

// 不要这样做
var m1 = true;
 if(m1){
 	function funs(){
 		console.log("1")
 	}
 }else{
 	function funs(){
 		console.log("2")
 	}
 }
 funs() // Chrome 1

多次声明同一个函数,最后声明的函数有效。不要把函数声明放在条件判断语句的分支里面,这样是无效的,依然会有声明,(Firefox例外,Chrome试了试也例外)不同浏览器做法不一致。。。。
使用函数表达式,是没有这个问题的。

函数表达式

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

void functionName() // 表示忽略返回值

创建一个函数并把它赋值给一个变量。创建的函数叫做匿名函数因为function关键字后面没有函数名。(有时也叫拉姆达函数),它的name属性是空字符串。
函数表达式和其他表达式一样,使用之前必须先赋值。

递归

  递归函数是在一个函数通过名字掉要自身的情况下构成的。
arguments.callee 是一个指向正在执行的函数的指针。编写递归函数的时候,使用arguments.callee比直接使用函数名,更保险。

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

严格模式下,这个arguments不能使用,arguments.callee也就不可以调用了,可以使用命名函数表达式。

var factorial = (function f(num){
	if(num <= 1 ){
		return 1;
	}else{
		return num * f(num-1)
	}
})
// 括号好像没什么作用 在Safari会导致错误,???

闭包

  闭包是指有权访问另一个函数作用域中的变量的函数。 创建闭包的常见方式就是,在一个函数内部创建一个另一个函数。

function createCom(property){
	return function(obj){
		var value1 = obj[property]; // 这里使用了外面函数的变量proerty
		return 1;
	}
}

闭包与变量

  作用链的这种配置引出了一种副作用,即闭包只能取得包含函数中任何变量的最后一个值。

function createFunction(){
	var result = new Array();
	for(var i = 0; i< 10; i++){
		result[i] = function(){
			return i;
		}
	}
	return result;
}
console.log(createFunction()[0]()) // 10

可以通过创建另一个匿名函数强制让闭包的行为符合预期。

function createFunction(){
	var result = new Array();
	for(var i = 0; i< 10; i++){
		result[i] = (function(num){
			return function(){
				return num;
			}
		})(i)
	}
	return result;
}
console.log(createFunction()[0]()) // 10

生成拥有更长的作用域链的闭包,将数据保存到下一级里面。

this

  闭包中使用this可能会导致一些问题。this对象是在运行时基于函数的执行环境绑定的。全局函数中,,this等于window,函数作为某个对象的的方法调用的时候,this等于那个对象。匿名函数的执行环境具有全局性,因此对象通常指向window
   call() apply() bind() 可以改变this指向
  每个函数被调用的时候会自动取得两个特殊变量,this和arguments内部函数在搜索这两个变量的时候,只会搜索到它的活动对象为止。因此无法直接访问到外部函数的这两个变量,可以把外部作用域中的this对象保存在一个闭包能够访问的变量里面。

var name = "The Window";
var obj = {
	name: "My Object",
	getName: function (){
		var that = this;
		return function(){
			return that.name
		}
	}
}
console.log(obj.getName()()) // My Object

内存泄漏

   如果闭包的作用域链中保存着一个HTML元素。那么就意味该元素无法被销毁。

function assignHandler(){
	var element = document.getElementById("some");
	element.onclick = function(){
		console.log(element.id);
	}
}

function assignHandler(){
	var element = document.getElementById("some");
	var id = element.id;
	element.onclick = function(){
		console.log(e);
	}
	element = null;
}

通过吧element.id 保存在变量中,在闭包中引用这个变量,消除循环引用。闭包会引用包含函数的整个活动对象。包括element,即使闭包不直接引用element,包含函数的活动对象也会引用,所以需要手动吧element置为null,解除对DOM对象的引用。

模仿块级作用域

  JavaScript中没有块级作用域,在块级语句中定义的变量,实际在包含函数中。
多次声明同一个变量,是没有效果的,但是会执行后续声明中的变量初始化。匿名函数可以用来魔方块级作用域,
块级作用域(通常被称为私有作用域)

(function(){
	// 这里是块级作用域
})()

以上代码定义并立即调用了一个匿名函数,将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式,紧随其后的圆括号立即调用了这个函数,
常常用在全局作用域中,从而限制向全局作用域中添加过多的变量和函数。也可以减少闭包占用内存的问题。

私有变量

  JavaScript没有私有成员概念。所有对象属性都是公有的,倒是有一个私有变量的概念,,**任何在函数中定义的变量,都可以认为是私有变量,以为不能在函数的外部访问这些变量,**私有变量包括函数的参数,局部变量,和函数内部定义的其他函数。

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

函数内部有三个私有变量,num1、num2和sum,在函数内部可以访问这几个变量,在函数外部则不可以,,如果在函数内部创建一个闭包,那么闭包可以通过自己的作用域 链访问,利用这一点可以创建,用于访问私有变量的公有方法,
  有权访问私有变量和私有函数的公有方法被称为特权方法

function MyObj(){
	// 私有变量
	var privateVar = 10;
	// 私有函数
	function privateFun(){
		return false;
	}
	// 特权方法
	this.publicMet = function(){
		privateVar++;
		return privateFun();
	}
}

特权方法作为闭包有权访问在构造函数中定义的所有变量和函数,利用私有(私有变量,私有函数)和特权成员,可以隐藏那些不应该被直接修改的数据。
但是这样每个MyObj的每个实例中都会重新创建,特权方法,使用静态私有变量可以避免这个问题。

静态私有变量

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

(function (){
	// 私有变量
	var privateVar = 10;
	// 私有函数
	function privateFun(){
		return false;
	}
	// 构造函数   初始化未经声明的变量 
	MyObj = function(){
	}
	// 公有 特权方法
	MyObj.prototype.publicMet = function(){
		privateVar++;
		return privateFun();
	}
})

  初始化未经声明的变量会,创建一个全局变量。在严格模式下给未经声明的变量赋值会导致错误。
这个方法和在构造函数中定义特权方法的主要区别,在于私有变量和函数是由实例共享的。有特权方法是在原型上定义的。因此所有实例都使用的同一个函数。而这个特权方法,作为一个闭包函数,保存着对包含作用域的引用。

多查找作用域链中的一个层次,就会在一定程度上影响查找速度,这正是是用闭包和私有变量的一个明显不足之处。

模块模式

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

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

模块模式是通过为单例添加私有变量和特权方法,使其得到增强。

var singLeton = function (){
	// 私有变量
	var privateVar = 10;
	// 私有函数
	function privateFun(){
		return false;
	}
	return {
		publicFun: true,
		publicMet:function(){
			privateVar++;
			return privateFun();
		}
	}
}

在Web应用程序中,常常需要使用一个单例来管理应用程序级的消息。

vue.js ???

增强的模块模式

  有人改进了模块模式,在返回对象之前加入对其增强的代码,这种增强模式,适合那些单例必须是某种类型的实例。同时还必须添加某些属性,和方法对其增强,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值