函数(全是重点)
1.函数就是一个具有某些功能的代码块(可以看作是个工具),这个代码块只能被事件激活,或者在函数被调用时才会执行。你可以在页面中的任何位置调用.
2.函数的创建方法:
(1)第一种定义方式:函数声明
function fun(){
console.log(3);
//return this;
//为什么函数会输出函数体中的内容,因为在函数体的最后,
//
默认会有一个 return this ! 不过可以修改成其它的返回值!,
//这里的this指的是全局对象window
}
fun(); //函数调用,函数必须调用,不调用函数是不会执行代码块
(2)第二种定义方式: 函数表达式(存储在变量中)
var fun1=function()
{
console.log(5);
}
fun1();//
这里的函数调用必须放在函数声明(即函数所存变量)的前面
如果放在前面的话,代码会报错:
错误举例:
(3)函数的第三种定义方式:构造函数
var fun2= new Function(console.log(8)); //8
//函数调用,函数必须调用,不调用函数是不会执行代码块
函数可以自调
3.函数的调用方式
javaScript 函数有 4 种调用方式:
每种方式的不同在于 this 的初始化。
(1)作为一个函数去调用: 函数名();
函数作为全局对象调用,会使this的值成为全局对象,使用window对象作为一个变量,容易造成程序崩溃!
例1:
function myFunction(a, b)
{
return a * b;
}
myFunction(10, 2) // myFunction(10, 2) 返回 20
例2:
function myFunction(a, b)
{
return a * b;
}
window.myFunction(10, 2); // window.myFunction(10, 2) 返回 20
这是调用 JavaScript 函数常用的方法, 但不是良好的编程习惯
全局变量,方法或函数容易造成命名冲突的bug。
当函数没有被自身的对象调用时
this 的值就会变成全局对象。
在 web 浏览器中全局对象是浏览器窗口(window 对象)。
function myFunction()
{
return this;
}
myFunction(); // 返回 window 对象
(2)
函数作为方法调用;(函数作为对象的方法调用,会使this的值成为对象的本身)
var myObject = {
firstName:"John"
,
lastName: "Doe"
,
fullName: function ()
{
return this.firstName + " " + this.lastName;
}
}
myObject.fullName()
(3)使用构造函数调用调用函数(谁调用它,this就指向谁)
(4)
作为函数方法调用函数:
在js中函数是对象,是对象就有属性和方法,而call()和apply()是预定义的函数方法! 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身。
====递归函数
1.通过函数自身名字调用
这种通过函数名字调用自身的方式存在一个问题:函数的名字是一个指向函数对象的指针,如果我们把函数的名字与函数对象本身的指向关系断开,这种方式运行时将出现错误。
2.通过arguments.callee调用函数自身
例子:
function sum(num){
if(num<=1){return 1;}
return num+arguments.callee(num-1);
}
console.log(sum(5));//15
function sum(num){
if(num<=1){
return 1;
}else{
return num+arguments.callee(num-1);
}
}
console.log(sum(5));//15
var sumAnother=sum;
console.log(sumAnother(5));//15
sum=null;
console.log(sumAnother(5));//15
这种方式很好的解决了函数名指向变更时导致递归调用时找不到自身的问题。但是这种方式也不是很完美,因为在严格模式下是禁止使用arguments.callee的。
警告:在严格模式下,第5版 ECMAScript (ES5) 禁止使用 arguments.callee()。当一个函数必须调用自身的时候, 避免使用 arguments.callee(), 通过要么给函数表达式一个名字,要么使用一个函数声明.参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments/callee
===类数组对象:arguments:
- 当我们在js中在调用一个函数的时候,我们经常会给这个函数传递一些参数,js把传入到这个函数的全部参数存储在一个叫做arguments的东西里面
- 它是一个特殊的对象,它的属性名是按照传入参数的序列来的,第一个参数位于位置 0,第二个参数位于位置 1,依此类推,并且它还有length属性,存储的是当前传入函数参数的个数。
- arguments对象不能显式的创建,它只有在函数开始时才可用。
- 它可以像访问数组那样去访问每一个子元素:
arguments[0],arguments[1],。。。。。。。。arguments[n];
- Javascript的每个函数都会有一个rguments对象实例arguments,它引用着函数的实参,它也有类似于数组的length属性;
(1)、arguments.length 为函数实参个数。
(2)、arguments.callee 引用函数自身
callee 属性是 arguments 对象的一个成员,仅当相关函数正在执行时才可用。
callee 属性的初始值就是正被执行的 Function 对象,这允许匿名的递归函数。
var sum=function(n){
if(1==n) {
return 1;
} else {
return n + arguments.callee(n-1);
}
}
alert(sum(6));
arguments此对象大多用来针对同个方法多处调用并且传递参数个数不一样时进行使用。
根据
arguments的索引来判断执行的方法。
每次函数体运行时,传入的数据会生成一个新的空间,空间名叫arguments或者叫形参名
===实参和形参:
形参就是取的名字,必须保证传入数据时按照定义好的形参个数和位置,这个名字在函数体里使用,实参是调用函数的时候外面传入的实际的数据。
每次函数体运行时,传入的数据会生成一个新的空间,空间名叫arguments或者叫形参名
运行结果:300
如果调用函数时,实参传入
多了:
1.按照传入的位置先后给形参赋值,没有使用,对其没有任何影响;
2.按照传入的位置先后给形参赋值,如果想要使用传入多的实参,只有通过arguments来取;
如果调用函数时,实参传入
少了:
1.函数体内,没有传入的数据的形参,没有任何影响;
2.函数体内,有这个传入数据的形参,依次赋值
函数也是一种数据:如下例:
对于
fn12来说:name1,name2,name3是它的形参
fg,100,200是它的实参;
对于
nmae1 来说: name2,name3是它的形参
对于
fg来说: num1,num2是它的形参
====闭包:
闭包是一个拥有许多变量和绑定了这些变量的环境表达式(通常是一个函数)
闭包 内部的函数,传出来(或者传不出来),被使用,这个函数就叫做 闭包
外部合法使用局部变量,通过把内部函数传入外部,这个过程就叫做闭包
当函数被当做数据,传入另一个函数,在另外一个函数种被使用时,传入的函数就叫做回调;
()的含义:
1.表示指向(一个空间):
2.函数的调用(开关符号):
分析:
()()
前面一个小括号指向一个函数
后面一个小括号调用函数
立即执行函数:
分析空间问题:
所遇问题:
每次点击按钮都显示的时第三个按钮的背景颜色;这造成所想要实现的功能不能实现(点击谁,背景颜色就改变谁)
这种现象的原因:函数里面所用到的 i 值不是即时值,而是for循环后所达到的临界值2;
如何解决这种问题呢?
我们可以采用闭包的形式来解决;
如下解决方法:
作用1:私有作用域;
作用2:避免污染全局作用域
闭包的优缺点:
优点:有利于封装,可以访问局部变量
缺点:内存占用浪费i,造成内存泄漏