Java教程

JavaScript语言精粹学习笔记之函数

本文主要是介绍JavaScript语言精粹学习笔记之函数,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

函数的特性:可以封装一些功能(代码),在需要时可以执行这些功能(代码)。封装到函数中的代码不会立即执行,会在函数调用的时候执行

4.1函数对象

函数对象也有原型,函数对象连接的是Function.prototype(该原型对象本身连接到object.prototype)。
想了解原型的话可以看看我之前的文章-对象

  1. 函数可以被调用
  2. 函数可以作为参数传递给其他函数
  3. 函数也可以返回函数

4.2函数字面量

函数对象可以通过函数字面量来创建:

var add = function(a,b){
	return a+b;
}

函数字面量包括四个部分:

  1. 保留字function (es6中有箭头函数,可以没有function)
  2. 函数名(可以被省略),有名字可以更好的识别和调用。
  3. 括号里的参数,每个参数有逗号隔开。这些名称将会被定义为函数的变量,在函数被调用时传入实参初始化这些变量(形参)为其提供实际的值,可以在函数内部正常的使用。
  4. 包围在花括号中的语句。这些语句是函数的主体。它们在函数被调用的时候执行。

函数字面量可以出现在任何允许表达式出现的地方。函数嵌套的情况下会出现闭包,关于闭包可以看我的文章作用域和闭包

4.3调用

调用一个函数将暂停当前函数的执行,传递控制权和参数给新参数。除了声明是定义的形参外,每个函数都会接收两个附加的参数:this和arguments。参数this指的是当前的上下文环境,他的值取决函数的调用模式。
js中有四种调用模式:方法调用、函数调用、构造器调用和apply调用。
关于形参和实参:
实参就是通过函数调用是传递过来赋值给形参的。当实参的个数大于形参的时候,多余的实参会被忽略,少于的话,缺少的实参将会替换为undefined传入。任何类型的值都可以被传递给参数(因为js是一门弱类型语言)

方法调用

当一个函数被保存为对象的一个属性,我们称它为一个方法。当一个方法被调用时,this会绑定到该对象。
如果调用表达式包含一个属性存取表达式(obj.或obj[],(obj为对象名),那么它被当作一个方法来调用。

var name = "xiaolang"
function fun(){
				console.log(this.name);
			}
var obj = {
				name:"小浪",
				sayName:fun
			};
	obj.sayName();//小浪
	fun();//xiaolang

方法可以是this去访问对象,能从对象中取值或修改该对象等等操作。this绑定的是调用方法的对象。

函数调用

当一个函数作为一个函数来调用的是时候,this会被绑定到全局对象。

var name = 'xiaolang'
var obj = {
	name:"小浪",
	sayName: function (){
		var func = function (){
			console.log(this.name)
		}
		func();
	}
}
obj.sayName();//xiaolang

构造器调用模式

JavaScript是一门基于原型继承的语言。这意味着对象可以直接从其他对象继承属性。
如果在函数前面带上new来调用,那么将创建一个隐藏连接到改函数的prototype成员的新对象,同时this将会绑定到那个新对象上,这就是构造器调用。new的前缀也会改变return语句的行为

Apply调用

apply方法让我们构建一个参数数组并用它去调用函数。它允许我们选择this的值。
apply方法接收两个参数。第一个将绑定给this的值,可以为对象。第二个就是一个参数数组。

function fun(){
	console.log(this);
}
obj = {
	name:"小浪",
	sayName: fun
}	
fun();//window
fun.apply(obj);//object

4.4参数

当函数被调用时,解析器会自动添加一个arguments数组作为参数,通过它可以访问所有被调用时传递的参数列表,包括多余的参数。但实际上arguments并不是一个数组,他只是一个对象,没有数组所有的方法,但其中有一个属性length

4.5 返回

函数从执行开始到遇到}函数体结束。
我们可以通过return语句使函数提前结束。当return语句执行时,余下的代码并不会执行
一个函数总是会返回一个值,如果没有那就是返回undefined
如果函数以new前缀来调用时,返回的不是一个值,而是一个该新对象(this对象)

4.6 异常

异常是干扰程序正常流程的非正常的事故。
可以通过throw{}来主动抛出一个异常。
可以通过try{}catch(e){}来捕获异常,所有的e异常将会被捕获。

4.7给类型添加方法

JavaScript允许给语言的基本类型添加方法。
可以通过原型prototype添加。这样可以让所有的类型都可以访问一些特殊的方法。但使用时需要小心使用。
还有一个注意点,for in 语句在原型上表现很糟糕,但我们可以使用hasOwnProperty方法来筛选继承来的属性。

4.8 递归

递归函数会直接或间接的调用本身的一种函数。
递归函数可以高效的操作树形结构,比如浏览器的文档对象模型(DOM)。每次递归调用处理给定树的一小段。

//定义 walk_the_DOM 函数,它从来个给定的节点开始,按HTML源巫中的顺序
//访问该树的每个节点。
//它会调用一个函数、并依次传递每个节点给它。walk_the_DOM 调用自身去处理11每一个子节点。
var walk_the_DOM = function walk(){
	func(node)
	node = node.firstChild
	while(node){
		walk(node,func)
		node = node.nextSibling
	}
}
//定义getElementsByAttribute函数。它取得一个属性名称字符串//和一个可选的匹配值。
//它调用 walk_the_DOM,传递一个用来查找节点属性名的函数。1/匹配的节点会累积到一个结果数组中。
var getElementsByAttribute = function (att,value){
	var results =[];
	walk_the_DOM (document.body, function (node){
		var actual = node.nodeType === 1 && node.getAttribute(att) ;
		if (typeof actual === 'string'&&( actual ===value || typeof value !== 'string')){
			results. push (node);
		}
	})
return results;	
);

JavaScript没有尾递归优化。如果是深入递归的函数可能会因为返回栈溢出而导致运行失败。

//构建一个尾递归的函数,因为他会返回自身调用的结果
var factorial = function factorial(i, a){
	a = a||1;
	if(i<2){
		return a
	}
	return factorial(i-1, a*i)
}

尾递归是一种在函数的最后执行递归调用语句的特殊形式的递归。

我们知道arguments.callee() 是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用。
但严格模式下会出错,不过,可以使用命名函数表达式来达成相同的结果

4.9作用域

作用域控制着变量与参数的可见性及生命周期。
作用域的好处是使内部函数可以访问定义他们外部的函数的参数和变量。
函数的存在就创建了一个函数作用域,在函数执行的时候就会将其传入作用域链中执行。

4.10 闭包

作用域和闭包

4.11回调

函数可以让不连续事件的处理变的更容易。
可以设置为某事件发生就直接执行另一事件,让事件连续起来。

4.12模块

我们可以通过函数和闭包来构建模块。模块是一个提供接口却隐藏状态和实现的函数或对象。减少对全局变量的污染,使模块内的变量、函数、对象等隐藏起来,不与外部的变量、函数、对象起冲突,外部也不能随便修改模块的内容,只有通过模块进行修改,提高了安全性。
模块模式的一般形式是:一个定义了私有变量和函数的函数;利用闭包创建可以访问私有变量和函数的特权函数;最后返回这个特权函数,或者把它们保存到一个可访问到的地方。

4.13级联

有一些方法没有返回值。
如果我们让这些方法返回this而不是undefined,就可以启用级联。在一个级联中,我们可以在单独一条的语句中依次调用同一个对象的很多方法。一个启用级联的Ajax类库可能允许我们以这样的形式去编码:
getElement (‘myBoxDiv’).
move (350,150).
width (100).
height (100).colori’red’).
border ( ’ 10px outset’).padding(’ 4px’).
appendText( “Please stand by”) .on ( ‘mousedown’, function (m){
this.startDrag(m,this.getNinth (m))).
on(‘mousemove’, ‘drag’).on( ’ mouseup’, ‘stopDrag’).later (2000, function o{
this.color(‘yellow’).setHTML( “What hath God wraught?”).slide (400,40,200,200);.tip("This box is resizeable’) ;

级联可以产生出具备很强表现力的接口。它也能帮助控制那种构造试图一次做太多事情的接口的趋势。

4.14套用

函数也是值,套用允许我们将函数与传递给他的参数相结合去产生出一个新的函数。
JavaScript并没有curry方法,但我们可以通过给Function.prototype添加功能来实现:

Function.method ('curry',function (){
		var args = arguments, that=this;
		return function(){return that.apply (null, args.concat (arguments));}
});//有些事不太对头.

curry方法通过创建一个保存着原始函数和被套用的参数的闭包来工作。它返回另一个函数,该函数被调用时,会返回调用原始函数的结果,并传递调用curry 时的参数加上当前调用的参数的所有参数。它使用Array的concat方法去连接两个参数数组。
但因为arguments并不是一个真正的数组,没有concat方法。
解决方案:

Function. method ('curry', function (){
	var slice = Array.prototype.slice,
	args = slice.apply(arguments) ,
	that =this;
	return function (){return that.apply(null,args.concat (slice.apply(arguments));};
});

4.15记忆

函数可以用对象去记住先前操作的结果,从而避免无谓的运算,这种优化叫作记忆。

var fibonacci =function (n){return n<2 ? n : fibonacci(n - 1) + fibonacci(n - 2);};
for (var i=0;i<=10;i++){'//' +i+':'+ fibonacci(i));

fibonacci函数被调用了453次,很多次都是无谓的调用,我们可以创建一个数组来存储结果,储存结果可以隐藏在闭包中,当我们的函数被调用时,先判断函数是否知道运行结果,如果知道就直接返回这个结果。

var fibonacci =function(){
	var memo = [0, 1];
	var fib =function (n){
		var result = memo [n];
		if (typeof result !== ' number'){
				result = fib (n - 1)+fib(n - 2);
				memo[n] = result;
			}
		return result;
	};
	return fib
)();

我们可以把这种形式一般化,编写一个函数来帮助我们构造带记忆功能的函数。memoizer函数将取得一个初始的memo数组和fundamental 函数。它返回一个管理meno存储和在需要时调用fundamental函数的shell函数。我们传递这个shell函数和该函数的参数给fundamental函数:

var memoizer = function (memo,fundamental){
	var shell = function (n){
		var result =memo [n] ;
		if (typeof result !== 'number '){
			result= fundamental (shell, n);
			memo[n] =result;
		}
		return result;
	}
	return shell
);

现在,我们可以使用memoizer来定义fibonacci函数,提供其初始的memo 数组和fundamental函数:

var fibonacci = memoizer([0,1], function (shell,n){
	return shel1(n - 1)+she1l(n - 2);
});

通过设计能产生出其他函数的函数,可以极大减少我们必须要做的工作。例如:要产生一个可记忆的阶乘函数,我们只须提供基本的阶乘公式即可:

var factorial = memoizer([1,1],function (shell,n){return n * shell(n - 1)}) ;
这篇关于JavaScript语言精粹学习笔记之函数的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!