JavaScript —— 函数

作用域

执行环境及作用域
每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,而函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。
活动对象在最开始只包含一个变量,即argument对象(这个对象在全局还款中不存在的),作用域链中的下一变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性,有次序的,每个环境都可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。

函数声明与函数表达式

解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);函数表达式,则必须等到解析器执行到它所在的代码才行,才会真正被解释执行。

函数内部属性

函数内部,两个特殊对象:argumentsthis
arguments是一个类数组对象,包含着传入函数中的所有参数
虽然arguments的主要用途是保存函数参数,但是这个对象还有一个名叫callee的属性,这个属性是一个执行,指向拥有这个arguments对象的函数
阶乘例:函数执行的与函数名factrial紧紧耦合在一起,消除耦合使用arguments.callee

function factrial(num){
	if(num <= 1){
		return 1;
	}else{
		return num * factrial(num-1);
	}
}
function factrial(num){
	if(num <= 1){
		return 1;
	}else{
		return num * arguments.callee(num-1);
	}
}
var trueFactorial = factorial;
factorial = function(){
	return 0;
}
alert(trueFactorial(5));//120
alert(factorial(5));//0

this对象

this引用的是函数据以执行的环境对象,或者可以说是(当在网页的全局作用域中调用函数时,this对象引用的就是window)

window.color = "red";
var o = {color:"blue"};
function saycolor(){
	alert(this.color);
}
saycolor();//red
o.saycolor() = saycolor;
o.saycolor();//blue

注意!函数的名字仅仅是一个包含指针的变量而已。即使是在不同的环境中执行,全局的saycolor()函数与o.saycolor()指向的仍然是同一个函数

caller是函数对象的一个属性,该属性保存着调用当前函数的函数
这个属性中保存着调用当前函数的引用,如果是在全局作用域中调用当前函数,返回null

function outer(){
	inner();
}
function inner(){
	alert(inner.caller);
}
outer();

弹出显示outer()函数的源代码,outer()调用inner(),所以inner.caller就指向outer()为了实现更松散的耦合,通过arguments.caller

function outer(){
	inner();
}
function inner(){
	alert(arguments.callee.caller);
}
outer();

严格模式下,访问arguments.callee会导致错误
ECMAScript还定义了arguments.caller属性,严格模式下也会错误,非严格始终是undefined,这属性是为了分清arguments.caller和函数caller属性。
以上变化都是为了加强这门语言的安全性,这样第三方代码就不能在相同的环境窥视其让代码了。严格模式下:不能为函数的caller属性赋值,会报错

函数属性和方法
函数是对象,所以函数也有属性和方法
两个属性:length和prototype
lenght属性表示函数希望接收的命名参数的个数

prototype

对于ECMAScript中的引用类型而言,prototpye是保存它们所有实例方法的真正所在。诸如:toString()和valueOf()等方法,实际上都保存在prototype名下,只不过是通过各自对象的实例访问罢了。
prototype属性是不可枚举的,使用for-in无法发现。
每个函数都是包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数的作用域,另一个是参数数组

function sum(num1,num2){
	return num1 + num2;
}
function callSum(num1,num2){
	return sum.apply(this,arguments);//sum.apply(this,a[num1,num2]);
}
alert(callSum(10,10));

callSum()在执行Sum()函数时传入this作为this值(因为是在全局作用域中调用的,所以传入的就是window对象)和arguments对象。在严格模式下,未指定环境对象而调用函数,则this值不会转型为window只会是undefined。

call()方法与apply()作用相同,第一个参数还是this值,其余参数都直接传递给函数。传递函数的参数必须逐个举例出来。

function callSum(num1,num2){
	return sum.call(this,num1,num2);
}
alert(callSum(10,10));//20

apply,call()真正用武之地是能扩充函数赖以运行的作用域。

window.color = "red";
var o = {color:"blue"};
function saycolor(){
	alert(this.color);
}
saycolor();//red

这样的好处是对象不需要与方法有任何耦合关系

saycolor.call(this);//red
saycolor.call(window);//red
saycolor.call(o);//blue

bind()方法 创建一个函数的实例,其this值会被绑定到传给bind()函数的值。

window.color = "red";
var o = {color:"blue"};
function saycolor(){
	alert(this.color);
}
var objectsayColor = sayclor.bind(0);
objectsayColor(); //blue

saycolor()调用bind()并传入对象o,创建了objectsayColor()函数。objectsayColor()函数的this值o,因此即使在全局作用域中调用这个函数,也会看到"blue"。

函数表达式

定义函数的方式:一种是函数声明。二种是函数表达式
函数声明特征:函数声明提升,在执行代码之前先读取函数声明
函数表达式:创建一个函数并将它函数给变量functionName,这种情况下创建爱你的函数叫做匿名函数(拉姆达函数),使用前必须先赋值
//①不要这样做

if(condition){
	function sayHi(){
		alert("Hi");
	}
}else{
	function sayHi(){
		alert('"Yo!');
	}
}

//②可以这样做

var sayHi;
if(condition){
	sayHi = function(){
		alert("Hi!");
	}
}else{
	sayHi = function(){
		alert("Yo!");
	}
}

①是属于无效语法,JS引擎会尝试修正错误,将其转换为合理状态。但浏览器尝试修复正错误做法并不一致

递归

递归函数是在一个函数通过名字调用自身的情况下构成的
arguments.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用

function factorial(num){
	if(num<=1){
		return 1;
	}else{
		return num * arguments.callee(num-1);//arguments.callee代替函数名,可以确保无论怎样调用函数都不会出问题。
	}
}

严格模式下,不能通过脚本访问arguments.callee

var factorial = (function f(num){//使用命名函数表达式
	if(num<=1){
		return 1;
	}else{
		return num * f(num-1);
	}
})
发布了17 篇原创文章 · 获赞 0 · 访问量 764

猜你喜欢

转载自blog.csdn.net/CandiceYu/article/details/89889497