当前位置:首页 > 精彩博文 > JavaScript语言编程核心(四)—函数(待完成)
JavaScript语言编程核心(四)—函数(待完成)
时间:2020-08-05 作者: 分类:javascript

JavaScript语言编程核心(四)--- 函数(待完成)

在编程过程中,我们很经常会需要多次使用到一段代码,此时便需要把这段代码定义成函数,从而可以调用任意次。

函数是JavaScript中最出色的设计之一,它们是JS中基础模块单元,可用于代码复用,信息隐藏和组合调用。JS中的函数就是对象,也拥有自己的方法,它连接到Function.prototype上。

本文参考《JavaScript权威指南》;

函数的定义

一般有两种方式可以创建函数:函数声明与函数表达式;

函数声明:

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

这种形式的声明会被提前到作用域的顶部,所以可以在被定义之前调用它,称为 声明提前

函数表达式:

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

表达式的形式并不能在定义之前调用它,虽然var add也会被提前到作用域顶部,但赋值语句并不会被执行,此时add扔为undefined,所以只有在表达式定以后,才能进行函数的调用。

Tips:

1、函数声明可以出现在全局代码中,也可以被嵌套在其它函数内,但根据规定,不能出现在循环,判断,try/catch/finally与with语句中。而函数表达式可以出现在任何地方。

2、定义在其它函数内部的函数,包含一个连接到外部上下文的连接[[scope]],可以自由访问它的父函数中的参数与变量,这便是JS中的 闭包

函数的调用

调用一个已经定义好的函数有4种方式,会传入 实参,this, arguments。

1、函数调用模式

可以直接在函数名称的后面加上(),传入参数完成函数的调用,如add(3,4);此时,根据ES5或者ES5非严格模式,调用上下文( this )被指向全局对象;而在ES5严格模式中,this 则为 undefined

因此可以这样来检测是否为严格模式:

var strict = (function(){return !this;})();

2、方法调用模式

当一个函数被保存成一个对象的属性时,则成为一个方法,此时 this 指向保存该函数的对象。如 object.method()

多数情况下,可以直接用 .符号来直接访问,但少数情况下可能需要使用[ ]来进行属性的访问操作。

方法链 也称为 链式调用级联调用,我们可以在一个方法中返回一个对象,从而可以继续调用它的方法。如JQuery中就是这么实现的;

$(".header").map().get().sort();

这将使代码变得更为简洁和易读,因此当方法不需要返回值时,最好直接返回this。

this

this是函数中的一个关键字 ,它指向函数的调用上下文,并不是变量,也不是属性名,因此不能对其进行赋值。

如果作为方法调用函数,则this指向保存该方法的对象;

如果在函数调用中,this可能指向全局或者undefined,因此,在闭包中,如果想访问父级的this,则通常是将this保存在一个变量里,便可以通过作用域链进行访问,一般可以命名为 self/that/me。

this总结:

1、全局环境中,则指向 全局对象(windows)

2、构造函数里的this,则指向 新创建的对象

3、函数中的this,指向 函数的调用者

4、new Function,指向 全局对象(windows);

5、eval中,指向调用上下文中的this

构造函数调用模式

如果函数或者方法调用之前带有关键字 new,它就构成构造函数式调用。构造函数的处理方式跟普通的调用在实参处理、调用上下文和返回值方面都有着不同。

1、当构造函数没有形参时,可以省略实参列表和圆括号;

2、new操作符的操作步骤可以分成3步:

(1)创建一个新对象;

(2)新对象继承构造函数的prototype属性,this指向该新对象,也就是说,就算即使使用new o.m(),函数中的this值也是指向新对象,而不是o

(3)执行函数语句,为新对象添加属性,方法;

(4)返回该新对象;通常,构造函数中不适用return,但如果有主动return一个对象,则返回该对象;如果没有返回或者返回一个原始值,则返回最初创建的对象;

间接调用

使用call()apply()可以间接地调用函数,它们可以显式地指定this值,也就是说,任何函数都可以作为任何对象的方法来调用。

call(this,p1,p2,p3):以自己的实参列表作为传入函数的实参; apply(this,[p1,p2,p3]):以数组的形式传入实参;

函数的实参与形参

1、实参数量少于形参

调用函数时,当实参的数量少于定义的形参时,则后面的形参的值均为undefined。因此,在设置形参的时候,理想的情况是为参数设置一个合理的默认值,可以使用下面的形式:

a = a || 0;  // 形参设置为 a

但传入的实参和形参只是以顺序的位置对应,并无法主动地为他们指定关系,也就是说,无法省略第一个实参,而直接传入第二个实参,必须填入占位的undefined或者null,因此可选的形参只能放在是参列表的最后。推荐对可选参数进行清晰的注释。

2、实参数量多于形参

调用函数式,当实参的数量大于定义的形参时,可以通过参数对象来获取超过部分的实参。这个对象称为 arguments,是一个类数组,包含着传入的所有实参列表,它可以通过类似于数组的[0],[1]进行索引,访问传入的实参。同时,它还拥有可以length的属性,可以获取到传入函数的实参数量。

该对象有一个重要的用处,既让函数可以处理不定数量的实参,这种函数也成为 不定实参函数(varargs function)。比如,求任意个数字的总和,便可以定义为:

var add = function(){
	var sum = 0,
		i;
		l = arguments.length;
	// 遍历实参对象,累加每一个实参;
	for(i=0;i<l;i++){
		sum += arguments[i];
	}
	// 返回结果;
	return sum;
}

var sum = add(1,2,3,4,5);     // sum为15;

Tips: 1、实参对象arguments其实是实参的一个指针数组,并不是一个真正的数组,也就是说,上面函数中,arguments[0] === 1 的值为 true。在非严格模式下,可以通过实参对象来修改传入函数的实参的值。

2、实参对象还包含两个值,calleecaller。在严格模式下,不能对这两个值进行读写操作,但在非严格模式下,callee指向当前函数本身,caller则指向调用函数的函数。

3、记住定义的形参顺序,是个麻烦的事,因此可以使用直接传入对象,对象中是一个所有参数的键值对集合。

4、合理的实参类型检测,是避免函数执行错误的保证。

自定义函数属性

由于函数的本质也是一个特殊的对象,它也可以拥有自己的属性。当有些函数需要一些静态的值时,其实可以将其保存在函数的自身属性中,从而避免保存到全局环境中。

function integer(){
	return integer.counter++;
}
integer.counter = 0;
// 点击一次,计时器累加1;
$(document).on("click",function(){
	console.log(integer());
})

作为命名空间的函数

一般,我们会避免在全局环境中添加变量,避免污染全局的命名空间,一个很好的解决方法,便是将代码放置于一个函数作用域内。一般使用匿名的立即执行函数:

(function(){
	// 模块代码;
})();
微信公众号: i81for
扫一扫关注 · 佳节领红包
公益性全栈资源网站,鸣谢默默付出的博主、工程师、架构师们。
网站内容来源技术大牛的辛勤结晶。
81For 技术网站 Copyright ©2019 备案号:津ICP备19001147号-2