**学习目标
了解函数的基本概念
函数的定义方式
函数的参数
this
call、apply
执行环境、作用域链
垃圾收集、块级作用域
closure**
4.1初识函数
Function类型,即函数的类型。 一个典型的JavaScript函数定义如下: function 函数名称(参数表) {
函数执行部分: } 注意:参数列表直接写形参名即可,不用写var! return语句:return返回函数的返回值并结束函数运行
函数也可以看做数据来进行传递
4.2 定义函数
三种定义函数的方式: function语句形式 函数直接量形式 通过Function构造函数形式定义函数 比较三种方式定义的区别:
4.3 函数的参数
函数的参数:arguments对象 arguments是表示函数的实际参数(与形参无关) callee函数(回调函数属性)
arguments对象的秘密属性 callee属性:
这个属性比较奇怪,他能返回arguments对象所属的函数的引用,这相当于在自己的内部调用自己。 用法:例如检测函数传递的参数正确与否
4.4 this
this对象是在运行时基于函数的执行环境绑定的。在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。
也就是说this关键字总是指代调用者。
4.5 call、apply
每一个函数都包含两个非继承而来的方法:call、apply。这俩个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
call、apply的用途之一就是传递参数,但事实上,它们真正强大的地方式能够扩充函数赖以运行的作用域。
使用call()、aplly()来扩充作用域的最大好处就是对象不需要与方法有任何耦合关系。 call方法简单的实现。
4.6 执行环境、作用域链
执行环境(execution
context)是javascript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们的代码无法访问这个对象,但是解析器在处理数据时会在后台执行它。
全局执行环境是最外围的一个执行环境。根据ECMScript实现所在的宿主环境不同,表示执行环境的对象也不一样。
每一个函数都有自己的执行环境。当执行流进一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返还给之前的执行环境。当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope
chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
4.7 垃圾收集、块级作用域
javascript是一门具有自动垃圾收集机制的编程语言。开发人员不必关心内存分配和回收问题。
离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。标记清除是目前主流的垃圾收集算法。这种算法的思想是给当前不使用的值加上标记,然后回收其内存。
javascript里面没有块级作用域的概念,和C、JAVA等高级语言不同。所以在使用if、for时候要格外的小心。
javascript模拟块级作用域
4.8 Closure(闭包)
概念: 闭包与函数有着紧密的关系,它是函数的代码在运行过程中的一个动态环境,是一个运行期的、动态的概念。
所谓闭包,是指词法表示包括不必计算的变量的函数。也就是说,该函数能够使用函数外定义的变量.。
在程序语言中,所谓闭包,是指语法域位于某个特定的区域,具有持续参照(读写)位于该区域内自身范围之外的执行域上的非持久型变量值能力的段落。这些外部执行域的非持久型变量神奇地保留他们在闭包最初定义(或创建)时的值。
<!-- 函数示例程序:-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" charset="UTF-8">
//简单的一个函数:function关键字+函数的名字 没有返回值类型
//参数列表相当于函数的入口,return 相当于函数的出口
// function test(a,b){
// return a + b;
// }
//
// var c = test(10,20);
// alert(c);
//函数也是一种数据类型
// alert(typeof test);//function类型
function test1(aa){
aa();
}
function test2(){
alert("test2");
}
// test1(test2);
test1(function(){
alert("匿名的函数");
});
//在js中函数是可以嵌套定义的 (尽量不要这样去定义)
function test3(){
function test4(){
alert("test4");
}
test4();//test3调用test4
}
test3();
</script>
</head>
<body>
</body>
</html>
<!-- -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" charset="UTF-8">
//3种方式定义函数
/*
//1 function语句式
function test1(){
alert("我是test1");
}
//2函数的直接量 ECMAScript
var test2 = function(){
alert("我是test2");
}
//3 function构造函数式
var test3 = new Function("a","b","return a+b;");
alert(test3(10,20));
*/
/*
var d1 = new Date();
var t1 = d1.getTime();
for(var i = 0;i < 10000000; i++)
{
// function test1(){;} //19
// var test2 = new Function();//5630
}
var d2 = new Date();
var t2 = d2.getTime();
alert(t2-t1);
*/
/**
* 解析顺序问题 对于function语句式的函数,javascript解析器会优先的解释
*
*/
/*
//test1();//在这个位置可以调用
function test1(){
alert('1111');
}
test1();
//test2();//在这个位置不可以调用
var test2 = function(){
alert("2222");
}
test2();
*/
//函数作用域
var k = 1;
function t1(){
var k = 2;
// function test(){return k;} //k = 2
// var test = function(){return k;} //k=2
var test = new Function('return k;'); //k=1
alert(test());
}
t1();
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" charset="UTF-8">
//function参数
//形参列表
//js中函数的参数:形参 实参
function test(a,b,c,d)
{
// alert(test.length); //4 形参个数
//函数的实际参数 内部就是用一个数组去接受函数的实际参数
//arguments对象 可以访问函数的实际参数
//arguments对象只能在函数的内部访问和使用
// alert(arguments.length); //实际参数个数
// alert(arguments[0]); //第1个实参的值
// alert(arguments[1]); //第2个实参的值
/*if(test.length == arguments.length)
return a + b;
else {
return "参数不正确";
}*/
//arguments对象 用的最多的还是做递归操作
//arguments.callee
if(arguments.callee.length == arguments.length){
return a + b;
} else{
return "参数不正确";
}
}
// alert(test(10,20)); //30 //"参数不正确";
// test(10,20);
//arguments.callee 指函数本身
function fact(num){
if(num <= 1) return 1;
else
{
// return num * fact(num - 1);
return num * arguments.callee(num - 1);
}
}
var F = fact;
// fact = null;
alert(F(5));
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" charset="UTF-8">
//this:this对象是指在运行时期基于执行环境所绑定的
//this总是指向调用者,也就是说 谁调用了我 我指向谁
/*var k = 10;
function test(){
this.k = 20;
}
test();
// alert(test.k);//undefined
alert(window.k);//20
*/
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" charset="UTF-8">
//call apply简单的用法:绑定一些函数 用于传递参数 调用
/*function sum(x,y)
{
return x + y;
}
function call1(num1,num2)
{
return sum.call(this,num1,num2);
}
function apply1()
{
return sum.apply(this,[num1,num2]);
}
alert(call1(10,20));
alert(apply1(20,40));
*/
//扩充作用域
/*window.clolor = 'red';//全局变量
var obj = {color:'blue'};
function showColor(){
alert(this.color);
}
showColor.call(this);//red
showColor.call(obj);//blue //环境不同 结果不同
*/
//call 方法的简单模拟与实现
//function 方法
function test1(a,b){
return a + b;
}
function Obj(x,y){
this.x = x;
this.y = y;
return x * y;
}
var o = new Obj(10,20);
alert(test1.call(o,o.x,o.y));
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" charset="UTF-8">
//1.执行环境window对象(最上层的执行环境)
var color1 = "blue";
function changeColor(){
var color2 = "red";
function swapColor(){ //这个函数 又产生了一个执行环境
var color3 = color2;
color2 = color1;
color1 = color3;
//这里可以访问:color1、2、3
}
//这里可以访问color1、color2、但不能访问color3
swapColor();
}
//这里只能访问color1
changeColor(); //作用域window第一个作用环境
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" charset="UTF-8">
//增圾收集 方法1标记方法
/*function test(){
var a = 10; //被使用
var b = 20;
}
test();//执行完毕 之后a,b又被标记了一次:没有被使用
*/
//块级作用域的概念
//高级程序语言 java for if 块级作用域的概念
//js没有块级作用域的概念
/*function test(){
for(var i = 1;i <= 5; i++)
alert(i);//1-5
alert(i);//6
}
test();
*/
function test(){
(function(){
for(var i = 1;i <= 5; i++){
alert(i);
}
})();//i消失
alert(i);
}
test();
</script>
</head>
<body>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" charset="UTF-8">
/*
var name = "xiao A";
var obj = {
name : "xiao B",
getName:function(){
return function(){
return this.name;
}
}
};
// alert(obj.getName()()); //xiao A
var k = obj.getName();
// alert(typeof k);//function
*/
/*
var name = "xiao A";
var obj = {
name : "xiao B",
getName:function(){
//this总是指向调用者
var o = this;
return function(){
return o.name;
// return this.name;
}
}
};
// alert(obj.getName()());
// alert(obj.name);
var k = obj.getName(); //xiao B
*/
//闭包:一个函数 可以访问另外一个函数作用域中的变量
//封闭性:private起到一个保护变量的作用
function f(x){
var temp = x;
return function(x){
temp += x;
alert(temp);
}
}
var a = f(50);
a(5); //55
a(10);//65
a(20);//85
</script>
</head>
<body>
</body>
</html>