>웹 프론트엔드 >JS 튜토리얼 >JavaScript 기능 사용법_기본지식

JavaScript 기능 사용법_기본지식

WBOY
WBOY원래의
2016-05-16 18:30:181043검색

什么是函数(Function)
function sum(a,b){ 
     return a+b; 

其实通俗的说就是一个有名称的代码段,方便重用。
要注意的是:
1.Javascript 的函数语法,因为Javascript本身就是区分大小写的,所以function不能写作Function或FUNCTION.
2.sum是函数的名称,这个并不是必须的,等以后我们会说到。
3.return是返回,如果不写的话,函数的返回是undefined.如果要返回多个值,可以返回个数组或者对象(以后再说)
函数的调用

下面我们讲函数的基本调用。

var result = sum(1,2) 
函数的参数

不好意思的说,这个才是本篇文章的重点。
实例一,参数少于 实际定义参数的数目
var result = sum(1); 
结果result 为NaN,这就说明了,参数b的值为undefined,但并不会报错,这就无形中制造了bug.
实例二,参数多于 实际定义参数的数目
sum(1,2,3,4,5) 
结果为3.发现多于的参数被忽略了。
实例三,没有参数的函数
function args(){return arguments;} 
每个函数里都有一个默认的数组那就是arguments .它就是每个函数默认的参数为[] 。如果我们调用函数如下
args(1,2,3,4,5,6); 
会发现arguments的值为[1,2,3,4,5,6]。这下容易了,我们可以改造下上面的sum方法

function sum(){ 
    var res= 0; 
    for(i=0;i        res+=arguments[i]; 
    } 
    return res; 

sum(1,2,3,4); 
结果为10,这个sum函数灵活多了吧。^_^

Functions are data

这一篇是函数里比较重要的概念,那就是函数是一个数据。看个例子
function f(){return 1;} 
var f=function(){return 1;} 
这两个函数定义都是相同的。
typeof f; 
f的值为"function",所以说Javascript 的 函数是个数据类型。它有比较两个重要的特点
1.它包含了代码
2.能被执行
看个例子
var sum = function(a,b){return a+b;} 
var add = sum; 
sum=undefined; 
typeof sum; 
typeof add; 
add(1,2); 
我们把函数sum做为一个值赋给了add,发现删除了sum不影响add的调用。所以函数也就是个正常的赋值。
匿名函数(Anonymous Functions)
Javascript中,可以不用写赋值的代码,如
"abcd" 1 [1,2,3] 
这样都不会报错,这些数据叫做匿名的。同样的函数做为数据也可以是匿名的
function(a){return a} 
匿名函数的作用有两个
1.可以把匿名函数做为一个参数传入到另一个函数中。
2.你可以理解运行这个匿名函数
下面就会详细讨论这两个功能的作用了。

回调函数(Callback Functions)

因为函数和其他数据一样可以被赋值,删除,拷贝等,所以也可以把函数作为参数传入到另一个函数中。
实例一
function invoke_and_add(a,b){ 
  return a()+b(); 

function one(){ 
  return 1; 

function two(){ 
  return 2; 

invoke_and_add(one ,two); 
结果为3;
再来看看匿名函数的用法。
实例二
invoke_and_add(function(){return 1;},function(){return 2;}),直接一个函数体传进去,没有函数名。
我们称,invoke_and_add为回调函数 
我们用匿名函数替代了 one,two两个函数。
通过上面两个实例,回调函数的定义为:传递一个函数A到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。 说白了,就是被人直接调用的函数,在一个函数执行另一个函数!
如果没有名称,就叫做匿名回调函数

回调函数的作用

主要有三个
1.当函数作为参数传递的时候,不用为这个函数定义一个名称,这样的好处是减少了全局变量。
2.节省了大量的代码。
3.提高了程序的性能。

自调用函数(Self-invoking Functions)

自调用函数也是匿名函数的一种表现形式,这个函数在定义之后,直接调用。如下

function(){ 
   alert('haha'); 

)() 

看起来还挺怪异,不过确实很简单。
自调用函数很方便使用,可以不用定义更多的全局变量。还有个好处,就是这个函数不能被执行两遍。真是非常适合做初始化的工作。
许多著名的javascript库特别多的源码中使用了这个功能,例如本人喜欢的Jquery.

内部函数(Inner Functions)

把函数作为一个值来思考一下,既然一个值可以定义在函数中,把函数做为数据放在函数中也未尝不可。如下:
function a(param){ 
function b(theinput){        
   return theinput *2; 

return 'The result is '+b(param); 

也可以这么写
var a = function(param){ 
     var b = function(theinput){ 
        return theinput*2; 
     }; 
     return 'The result is '+b(param); 
}; 
b函数是在a函数之中的 ,也就是意味着,在a函数的外部是无法访问b函数的。所以也称之为私有函数(private function)
a(2); 
a(8); 
b(2); 
发现b(2)是没有定义的。也就确定了它确实是私有函数。
内部函数的是使用还是有很多好处的。
1.可以有更少的全局变量。过多的使用全局变量就有可能由于命名冲突而产生过多的bugs
2.私有性,可以设计更好的接口函数供外部访问。

返回值为函数的函数(Functions that Return Functions)

在前几篇文章已经介绍了函数要有返回值,即使没有写return,函数也会返回一个undefine。
接下来看看返回值为函数的情况
function a(){ 
alert('a'); 
return function(){ 
  alert('b'); 
}; 

在这个例子中,a函数执行了alert('a'),以及它返回了另一个函数b。关于返回b的调用我们可以这样来用。
var newFunc = a(); 
newFunc(); 
执行结果为 alert a和alert b
如果不想赋值调用这个函数也可以简写如下
a()(); 
函数的自身重写

因为函数可以返回一个函数,那就意味着可以用一个新的函数替代一个旧的函数,根据前一个例子来改进一下
a=a(); 
第一次运行函数a,就alert a,再次运行函数a,就alert b,这个功能对初始化非常有用。这个函数a重写了自己,避免在以后调用初始化的功能(上个例子为alert a)。
当然我们还有更简单的方法来重写a函数那就是在a函数的内部重写它,来看看代码
function a(){ 
alert("a") 
a=function(){ 
   alert("b"); 


只有在初次调用a函数才会执行 alert a 在以后的调用中,都会执行alert b
下面结合前几节看个综合的例子
var c = function(){ 
   function a(){ 
    alert('a') 
   } 
   function b(){ 
    alert('b') 
   } 
   a(); 
   return b; 
}();//alert('a'); 
c();//alert('b'); 
这个例子有以下几点需要注意
1. a函数,b函数是内部函数。
2. return b 返回的是个函数的引用。
3. 子调用函数重写了函数c。

如果能明白这个例子,关于内部函数,子调用函数和返回值为函数的函数就可以都理解了。

闭包(Closures)闭包属于比较难的一部分,在学习闭包之前,先来学习以下Javascript的作用域(Scope)

作用域链(Scope Chain)

函数内部定义的变量,在函数外不能访问,或者变量定义在代码段中(如if,for中),在代码段之外也不可访问。
var a =1; 
function f(){ 
var b=1; 
return a; 

f();//a=1 
b;//b 没有定义 
a 是全局变量,而b定义在函数f之中。所以:
在f函数中,a和b都可以访问。
在f函数之外,a可以访问,而b不可以

再次看个例子
var a = 1; 
function f(){ 
var b = 1; 
function n(){ 
  var c =3; 


如果定义一个函数n在函数f中,函数n不但可以访问自己作用域的c,而且还能访问所谓的父作用域的b和a
这就是作用域链(Scope Chain)
词法作用域(Lexical Scope)

Javascript에는 어휘 범위(Lexical Scope)도 있습니다. 이는 함수가 호출될 때가 아니라 정의될 때 범위를 생성한다는 의미입니다.
function f1(){var a=1;f2();}
function f2(){return a;}
f1();//a가 정의되지 않았습니다
f1 함수를 살펴보세요 먼저 함수 f2가 호출됩니다. 함수 로컬 변수 a가 f1에도 있기 때문에 함수 f2도 a에 액세스할 것으로 예상할 수 있지만 그렇지 않습니다.
이번에 f2 함수가 정의되었지만 해당 범위에서 a가 발견되지 않았기 때문입니다. 함수 f1이든 함수 f2이든 자신의 지역 변수나 전역 변수에만 액세스할 수 있습니다.

폐쇄로 사슬 끊기

예를 들어 클로저를 설명해 보겠습니다.
예시 1

function f(){
var b="b";
return function(){
return b;
}
}
함수 f에는 변수 b가 포함되어 있습니다. 전역 범위에서는 b에 액세스할 수 없으며 결과는 정의되지 않습니다.
이 함수의 반환값을 함수로 살펴보세요. 이 새로운 함수는 f의 범위에 있는 변수 b에 액세스할 수 있습니다. 다음 코드를 보세요
var n = f();
n();//Access b
f 자체는 전역 함수이고, 반환되는 함수는 새로운 전역 함수이므로 함수 f의 범위에 액세스할 수 있습니다.

예제 2
이 예의 결과는 이전 예와 동일하지만 한 가지 차이점이 있습니다. 함수 f는 함수를 반환하지 않지만 새로운 전역 변수 n을 생성합니다.
var n
function f(){
var b = "b";
n=function(){
return b; >
그렇군요 n()을 함수 f의 변수 b에 액세스하도록 지시합니다

위의 두 예를 통해 함수가 상위 범위를 가리키고 해당 함수가 지역 변수를 가리키는 경우 이를 클로저라고 부를 수 있다고 말할 수 있습니다.

클로저는 실제로 내부 변수에 대한 외부 액세스 방법인 변명을 제공합니다.

매개변수를 전달하는 함수 f를 만들 때 이 매개변수는 함수 f 로컬 변수가 됩니다. 이 매개변수를 반환하는 f의 내부 함수를 만들 수 있습니다.
function f(arg){
var n =function(){
return args;
arg; n;
}
var m= f(123)
m();//124

루프에 클로저 적용

표면은 정상이지만 재활용 과정에서 일부 벌레가 발생하기 쉽습니다.
다음 코드를 보세요
function f(){

var a = []

var i

for(i=0;i<3;i ){

a [i] = function(){
              경고(i)
a[0]();//3
a[1]();//3
a[2] ();//3
새 루프를 만듭니다. 우리의 목적은 루프를 돌 때마다 새로운 함수가 생성되고, 이 함수는 루프의 시퀀스 값인 i를 반환합니다. 위 코드
의 실행 결과를 살펴보면 모두 3입니다. 그리고 우리가 기대하는 결과는 1, 2, 3입니다.
정확히 왜요? 우리는 모두 변수 i를 가리키는 세 개의 새로운 클로저를 만들었습니다. 클로저는 변수 i의 값을 기억하지 않으며 단지 변수 i에 대한 참조일 뿐입니다. 루프가 끝나면 i의 값은 3이므로 결과는 모두 3입니다.

올바른 작성 방법을 살펴보겠습니다
function f() {
var a = []
var i
for(i = 0; i < 3; i ) {
a[i] = (함수(x){
반환 함수(){
경고(x);
반환 x;
}
})(i);

}

return a;
}
var a = f()
a[0]();//0
a[1]();//1
a[2]();//2
변수 i를 로컬 변수 x로 변환하기 위해 다시 클로저를 사용했습니다. x 변수는 매번 다른 값을 갖습니다. 자기 호출 함수를 완전히 이해하지 못했다면 다음과 같이 작성하면 이해할 수 있습니다.
function f() {
function makeClosure(x) {
return function(){
return x;
}
}
var a = [];
var i
for(i = 0; i < 3; i ) {
a[i] = makeClosure(i); //makeClosure, i의 값을 기억하는 데 사용됩니다.
}
반환
}

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.