>  기사  >  웹 프론트엔드  >  Javascript 클로저 및 코드 구현 방법에 대한 심층 분석에 대한 자세한 소개

Javascript 클로저 및 코드 구현 방법에 대한 심층 분석에 대한 자세한 소개

黄舟
黄舟원래의
2017-03-16 15:07:551144검색

1. 클로저 란 무엇이며 클로저를 작성하고 사용하는 여러 가지 방법 패키지

클로저에 대한 공식 설명은 표현식에는 많은

변수

와 이러한 변수에 바인딩된 환경(일반적으로 함수 )이 있으므로 이러한 변수도 표현식의 일부입니다. 클로저의 특징: 1. 함수 변수의 참조로, 함수가 반환되면 활성화된 상태
입니다. 2. 클로저는 함수가 반환될 때 리소스를 해제하지 않는 스택 영역입니다. 간단히 말하면 자바스크립트
내부 함수
의 사용을 허용합니다. 즉, 함수 정의와 함수 표현식이 다른 함수의 함수 본문 내에 위치합니다. 또한 이러한 내부 함수는 모든 지역 변수, 매개변수 및 해당 함수가 존재하는 외부 함수에 선언된 기타 내부 함수에 액세스할 수 있습니다. 이러한 내부 함수 중 하나가 이를 포함하는 외부 함수 외부에서 호출되면 클로저가 형성됩니다. 2. 클로저를 작성하고 사용하는 여러 가지 방법

우선 JS의 모든 것이

객체라는 점을 이해해야 합니다.

, 함수는 객체의 일종입니다. 먼저 클로저를 작성하는 5가지 방법을 살펴보고 클로저가 무엇인지 간략하게 이해해 보겠습니다. 이에 대해서는 나중에 자세히 설명하겠습니다.

//第1种写法  
function Circle(r) {  
      this.r = r;  
}  
Circle.PI = 3.14159;  
Circle.prototype.area = function() {  
  return Circle.PI * this.r * this.r;  
}  

var c = new Circle(1.0);     
alert(c.area());
이러한 작성 방식에는 특별한 것이 없습니다. 단지 함수에 몇 가지 속성을 추가했을 뿐입니다.

//第2种写法  
var Circle = function() {  
   var obj = new Object();  
   obj.PI = 3.14159;  

   obj.area = function( r ) {  
       return this.PI * r * r;  
   }  
   return obj;  
}  

var c = new Circle();  
alert( c.area( 1.0 ) );

이러한 작성 방법은 변수를 선언하고 변수에 함수를 값으로 할당하는 것입니다.

//第3种写法  
var Circle = new Object();  
Circle.PI = 3.14159;  
Circle.Area = function( r ) {  
       return this.PI * r * r;  
}  

alert( Circle.Area( 1.0 ) );
이 방법은 새 개체를 만든 다음 해당 개체에

속성과 메서드

를 추가하는 것으로 가장 잘 이해됩니다.

//第4种写法  
var Circle={  
   "PI":3.14159,  
 "area":function(r){  
          return this.PI * r * r;  
        }  
};  
alert( Circle.area(1.0) );

이 방법은 일반적으로 사용되며 가장 편리합니다. var obj = {}는 빈 객체를 선언합니다.

//第5种写法  
var Circle = new Function("this.PI = 3.14159;this.area = function( r ) {return r*r*this.PI;}");  

alert( (new Circle()).area(1.0) );
솔직히 저는 이런 글쓰기 방법을 사용해본 적이 없으니 참고하시면 됩니다.

일반적으로 위의 방법들 중 2번과 4번이 더 많이 나오며, 습관에 따라 선택하시면 됩니다.

위 코드에는 JS에서 흔히 사용하는 프로토타입이 나오는데 프로토타입의 용도는 무엇인가요? 아래를 살펴보겠습니다.

var dom = function(){

    };

    dom.Show = function(){
        alert("Show Message");
    };

    dom.prototype.Display = function(){
        alert("Property Message");
    };

    dom.Display(); //error
    dom.Show();  
    var d = new dom();
    d.Display();
    d.Show(); //error

먼저 변수를 선언하고 변수에 함수를 할당합니다. 왜냐하면 Javascript에서는 각 함수에 Portotype 속성이 있지만 객체에는 없기 때문입니다. 메소드 2개를 추가하고 직접 추가하고 프로토타입을 깨뜨려 호출 상황을 살펴봅니다. 분석 결과는 다음과 같습니다.

1. 프로토타입 속성을 사용하여 정의되지 않은 객체 메서드는

정적

메서드이며 클래스 이름을 통해서만 직접 호출할 수 있습니다! 또한 이 정적 메서드에서는 이 변수를 사용하여 개체의 다른 속성을 호출할 수 없습니다!

2. 프로토타입 속성을 사용하여 정의된 객체 메서드는 비정적 메서드이며 인스턴스화 후에만 사용할 수 있습니다! 메소드 내에서 이는 객체 자체의 다른 속성을 참조하는 데 사용될 수 있습니다!
코드를 살펴보겠습니다:

var dom = function(){
        var Name = "Default";
        this.Sex = "Boy";
        this.success = function(){
            alert("Success");
        };
    };

    alert(dom.Name);
    alert(dom.Sex);
먼저 살펴보겠습니다. 무엇이 표시될까요? 대답은 둘 다 정의되지 않음을 표시한다는 것입니다. 이유는 무엇입니까? 왜냐하면 자바스크립트의 각 함수는 스코프(scope)를 형성하고, 이러한 변수들은 함수 내에서 선언되기 때문에 이 함수의 스코프에 포함되어 외부에서 접근이 불가능하기 때문입니다. 변수에 액세스하려면 새 인스턴스를 만들어야 합니다.

var html = {
        Name:'Object',
        Success:function(){
            this.Say = function(){
                    alert("Hello,world");
            };
            alert("Obj Success");
        }
    };

이러한 작성 방식을 살펴보겠습니다. 실제로 이는 Javascript의 "구문 설탕"입니다. 이 작성 방식은 다음과 동일합니다.

var html = new Object();
    html.Name = 'Object';
    html.Success = function(){
            this.Say = function(){
                    alert("Hello,world");
            };
            alert("Obj Success");

변수 html은 함수가 아닌 객체이므로 프로토타입 속성이 없으며 해당 메소드도 공개 메소드이므로 html을 인스턴스화할 수 없습니다. 그렇지 않으면 다음 오류가 발생합니다.

하지만

다른 변수에 값으로 할당할 수 있습니다(예: var o = html; 다음과 같이 사용하세요:

    alert(html.Name);
    html.Success();

말하자면, 끝났나요? 신중한 사람들은 Success 메소드에서 Say 메소드에 어떻게 접근할 수 있는지 물을 것입니다. html.Success.Say()인가요? 물론 위에서 언급한 것처럼 범위 제한으로 인해 접근이 불가능합니다. 따라서 다음 방법을 사용하여 액세스하십시오.

var s = new html.Success();
s.Say();

//还可以写到外面
html.Success.prototype.Show = function(){
    alert("HaHa");
};
var s = new html.Success();
s.Show();

Javascript 범위 문제는 한두 문장으로 명확하게 설명할 수 없습니다. 관심이 있는 경우 온라인에서 몇 가지 정보를 찾을 수 있습니다.

二、Javascript闭包的用途                                                                  

事实上,通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;更优雅,更简洁的表达出代码;在某些方面提升代码的执行效率。

1、匿名自执行函数

我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,
比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。
除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,
比如UI的初始化,那么我们可以使用闭包:

var data= {    
    table : [],    
    tree : {}    
};    

(function(dm){    
    for(var i = 0; i < dm.table.rows; i++){    
       var row = dm.table.rows[i];    
       for(var j = 0; j < row.cells; i++){    
           drawCell(i, j);    
       }    
    }    

})(data);

我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在函数执行完后会立刻释放资源,关键是不污染全局对象。

2、结果缓存

我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,

那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。

var CachedSearchBox = (function(){    
    var cache = {},    
       count = [];    
    return {    
       attachSearchBox : function(dsid){    
           if(dsid in cache){//如果结果在缓存中    
              return cache[dsid];//直接返回缓存中的对象    
           }    
           var fsb = new uikit.webctrl.SearchBox(dsid);//新建    
           cache[dsid] = fsb;//更新缓存    
           if(count.length > 100){//保正缓存的大小<=100    
              delete cache[count.shift()];    
           }    
           return fsb;          
       },    

       clearSearchBox : function(dsid){    
           if(dsid in cache){    
              cache[dsid].clearSelection();      
           }    
       }    
    };    
})();    

CachedSearchBox.attachSearchBox("input");

这样我们在第二次调用的时候,就会从缓存中读取到该对象。

3、封装

var person = function(){    
    //变量作用域为函数内部,外部无法访问    
    var name = "default";       

    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();    

print(person.name);//直接访问,结果为undefined    
print(person.getName());    
person.setName("abruzzi");    
print(person.getName());    

得到结果如下:  

undefined  
default  
abruzzi

4、实现类和继承

function Person(){    
    var name = "default";       

    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
    };   

    var p = new Person();
    p.setName("Tom");
    alert(p.getName());
    var Jack = function(){};
    //继承自Person
    Jack.prototype = new Person();
    //添加私有方法
    Jack.prototype.Say = function(){
        alert("Hello,my name is Jack");
    };
    var j = new Jack();
    j.setName("Jack");
    j.Say();
    alert(j.getName());

我们定义了Person,它就像一个类,我们new一个Person对象,访问它的方法。

下面我们定义了Jack,继承Person,并添加自己的方法。

위 내용은 Javascript 클로저 및 코드 구현 방법에 대한 심층 분석에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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