/**
* 전역 객체를 정의합니다. Version 속성은 출시될 때 현재 버전 번호로 대체됩니다.
*/
var 프로토타입 = {
버전: '@@VERSION@@'
}
/**
* 유형을 생성합니다. 해당 속성인 create는 메소드이고 생성자를 반환합니다.
* 일반적으로 다음과 같이 사용됩니다.
* var X = Class.create(); java의 Class 인스턴스와 유사한 유형을 반환합니다.
* X 타입을 사용하려면 java의 Class.newInstance() 메소드와 마찬가지로 계속해서 new X()를 사용해 인스턴스를 얻어야 합니다.
*
* 반환된 생성자는 Ruby 객체의 생성자 메서드 이름인 초기화라는 메서드를 실행합니다.
* 현재 초기화 메소드는 정의되지 않았습니다. 후속 코드에서 새 유형을 생성하면 동일한 이름의 해당 메소드가 생성됩니다.
*
* 자바부터 이해해야 한다면. java.lang.Class 클래스를 상속받은 클래스를 생성하기 위해서는 Class.create()를 사용하는 것으로 이해하시면 됩니다. 물론 Java는 이를 허용하지 않습니다. 왜냐하면 Class 클래스가 최종 클래스이기 때문입니다
*
*/
var 클래스 = {
생성: 함수() {
반환 함수() {
this.initialize.apply(this, 인수)
}
}
}
/**
* 객체를 생성하려면 변수 이름을 고려하세요. 원래 의도는 추상 클래스를 정의하고 나중에 새 객체를 생성할 때 이를 확장하는 것일 수 있습니다.
* 하지만 후속 코드의 적용을 보면 Abstract는 네임스페이스를 명확하게 유지하는 데 더 가깝습니다.
* 즉, 추상 객체 인스턴스에 새로운 객체 정의를 추가할 수 있습니다.
*
* Java를 이해하면 객체에 대한 내부 클래스를 동적으로 생성한다는 의미입니다.
*/
var Abstract = new Object()
/**
* 다중 상속과 비슷하게 매개변수 개체의 모든 속성과 메서드를 가져옵니다. 그러나 이 상속은 동적으로 획득됩니다.
* 예:
* var a = new ObjectA(), b = new ObjectB();
* var c = a.extend(b)
* 이때 객체 c 또한 a 및 b 개체 속성과 메서드를 소유합니다. 그러나 다중 상속과 달리 ObjectB의 c 인스턴스는 false를 반환합니다.
*/
Object.prototype.extend = function(object) {
for (객체의 속성) {
this[property] = object[property];
}
return this;
}
/**
* 이 메소드는 자바스크립트 함수 객체를 캡슐화하고 새 함수 객체를 반환하지만, 바인딩() 메소드 매개변수는 원래 객체와 동일합니다. 현재 개체의 개체입니다.
* 즉, 새 함수의 this 참조가 매개변수에서 제공하는 객체로 변경됩니다.
* 예:
*
*
* ......... ....
*
* 그러면 aaa.showValue를 호출하면 "aaa"가 반환되고, aaa.showValue2를 호출하면 "bbb"가 반환됩니다.
*
* Apply는 ie5.5 이후에만 등장한 새로운 방법입니다(넷스케이프는 아주 일찍 지원한 것 같습니다).
* 이 방법에 대한 자세한 내용은 MSDN http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp를 참조하세요.
* 호출 방법도 있는데, 적용과 유사합니다. 함께 공부하시면 됩니다.
*/
Function.prototype.bind = function(object) {
var method = this;
return function() {
method.apply(object, 인수)
}
}
/**
* 바인딩과 동일하지만 일반적으로 html 컨트롤 객체의 이벤트 처리에 사용됩니다. 그래서 이벤트 객체를 전달해야 합니다
* 이때는 Function.call을 사용한다는 점에 유의하세요. Function.apply와 차이점은 단지 매개변수 형식의 정의인 것 같습니다. <script> <BR> * var aaa = document.getElementById("aaa"); <BR> * var bbb = document.getElementById("bbb"); <BR> * aaa.showValue = function() {alert(this.value);} <BR> * aaa.showValue2 = aaa.showValue.bind(bbb); <BR> * </script> * Java의 두 가지 오버로드된 메소드와 같습니다.
*/
Function.prototype.bindAsEventListener = function(object) {
var method = this;
return function(event) {
method.call(object, event || window.event);
}
}
/**
* 정수 형식의 RGB 색상 값을 HEX 형식으로 변환
*/
Number.prototype.toColorPart = function() {
var digits = this.toString(16);
(이번 숫자를 반환합니다.
}
/**
* 일반적인 Ruby 스타일 함수로, 매개변수에 있는 메소드를 하나씩 호출하고, 성공적으로 실행된 첫 번째 메소드의 반환값을 반환합니다.
*/
var 시도해 보세요 = {
다음을 시도해 보세요. function() {
var returnValue;
for (var i = 0; i var lambda = arguments[i];
시도해 보세요 {
returnValue = lambda();
휴식;
} catch (e) {}
}
return returnValue;
}
}
/*----------------------------------- -------------------------*/
/* *
* 잘 설계된 예약 실행기
* 먼저 Class.create()로 PeriodicalExecuter 유형을 생성하고,
* 그런 다음 객체 리터럴 구문을 사용하여 프로토타입을 설정합니다.
*
* 특별히 설명이 필요한 것은 rgisterCallback 메소드인데, 위에서 정의한 함수 프로토타입 메소드인 바인드를 호출하고 자신을 매개변수로 전달하는 메소드이다.
* 그 이유는 setTimeout이 기본적으로 항상 창 객체를 현재 객체로 취하기 때문입니다. 즉,registerCallback 메소드가 다음과 같이 정의된 경우입니다.
*registerCallback: function() {
* setTimeout (this.onTimerEvent, this.주파수 * 1000);
* }
* 그러면 this.currentlyExecuting 속성에 접근할 수 없어 this.onTimeoutEvent 메서드가 실행되지 않습니다.
* 바인드를 사용한 후, 이 메소드는 PeriodicalExecuter의 현재 인스턴스인 이를 올바르게 찾을 수 있습니다.
*/
var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
초기화: 함수(콜백, 주파수) {
this.callback = 콜백;
this.주파수 = 빈도;
this.currentlyExecuting = false;
this.registerCallback();
},
registerCallback: function() {
setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
},
onTimerEvent: function() {
if (!this.currentlyExecuting) {
try {
this.currentlyExecuting = true;
this.callback();
} 마지막으로 {
this.currentlyExecuting = false;
}
}
this.registerCallback();
}
}
/*----------------------------------- -------------------------*/
/* *
* 这个函数就 Ruby 了.我觉得它的 作用主要有两个
* 1. 大概是 document.getElementById(id) 적의 最简化调用。
* 比如:$("아아아" ) 将返回上 aaa 对象
* 2. 得到对象数组
* 比如: $("aaa","bbb") 返回一个包括id为"aaa"및"bbb"两个입력은 다음과 같습니다. 。
*/
함수 $() {
var elements = new Array();
for (var i = 0; i var 요소 = arguments[i];
if (요소 유형 == '문자열')
요소 = document.getElementById(element);
if (arguments.length == 1)
return 요소;
elements.push(element);
}
요소를 반환합니다.
}
/**
* Ajax 객체 정의, 정적 메소드 getTransport 메소드는 XMLHttp 객체를 반환합니다.
*/
var Ajax = {
getTransport: function() {
return Try.these(
function() {return new ActiveXObject( 'Msxml2.XMLHTTP')},
function() {return new ActiveXObject('Microsoft.XMLHTTP')},
function() {return new XMLHttpRequest()}
) || 거짓;
},
emptyFunction: function() {}
}
/**
* 이때 Ajax 객체가 네임스페이스 역할을 하는 줄 알았습니다.
* Ajax.Base는 기본 객체형으로 선언됩니다.
* Ajax.Base는 Class.create()를 사용하여 생성되지 않는다는 점에 유의하세요. 작성자가 Ajax.Base를 인스턴스화하는 것을 원하지 않기 때문인 것 같습니다. 도서관 이용자가 변경되었습니다.
* 작성자의 다른 객체 유형 선언은 이를 상속받습니다.
* Java의 개인 추상 클래스와 같습니다
*/
Ajax.Base = function() {};
Ajax.Base.prototype = {
/**
* 확장(见prototype.js中的定义) 적용법真是让人耳目一新
* 옵션 首先设置默认属性,然后再 연장하다 参数对象,那么参数对象中也属性,那么就覆盖默认属性值。 下:
setOptions: function(options) {
이것. options.methed = options.methed? options.methed : '게시';
..........
}
我想很多时候,java 限system了 js 的创意。
*/
setOptions: 函数(选项) {
this.options = {
方法: 'post',
异步: true,
参数: ''
} .extend(选项||{});
}
}
/**
* Ajax.Request 封装 XmlHttp
*/
Ajax.Request = Class.create();
/**
* 定义四种事件(状态), 参考http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp
*/
Ajax.Request.Events =
['未初始化','正在加载','已加载','交互式','已完成'];
/**
*
*/
Ajax.Request.prototype = (new Ajax.Base()).extend({
初始化: 函数(url, 选项) {
this.transport = Ajax.getTransport();
this.setOptions(options);
尝试 {
if (this.options.method == 'get')
url = ' ?' this.options.parameters '&_=';
/**
* 此处好像强制使用了异步方式,而不是依照 this.options.asynchronous 的值
*/
this.transport.open(this.options.method, url, true);
/**
* 这里提供了 XmlHttp 传输过程中每个步骤的回调函数
*/
if (this.options.asynchronous) {
this.transport.onreadystatechange = this.onStateChange.bind(this);
setTimeout((function() { this.respondToReadyState(1)}).bind(this), 10);
}
this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
this .transport.setRequestHeader('X-Prototype-Version', Prototype.Version);
if (this.options.method == 'post') {
this.transport.setRequestHeader('Connection' , '关闭');
this.transport.setRequestHeader('Content-type',
'application/x-www-form-urlencoded');
}
this.transport .send(this.options.method == 'post'?
this.options.parameters '&_=' : null);
} catch (e) {
}
},
onStateChange: function() {
var readyState = this.transport.readyState;
/**
* 如果不是 Loading 状态,就调用回调函数
*/
if (readyState != 1)
this.respondToReadyState(this.transport.readyState);
},
/**
* 回调函数定义在 this.options 属性中,比如:
var option = {
onLoaded : function(req) {...};
......
}
new Ajax.Request(url, option);
*/
respondToReadyState: function(readyState) {
var event = Ajax.Request.Events[readyState];
(this.options['on' 事件] || Ajax.emptyFunction)(this.transport);
}
});
/**
* Ajax.Updater 用于绑定一个 html 元素与 XmlHttp 调用的返回值。类似于 buffalo 的绑定。
* 如果选项包含插入(来自 dom.js) ) 对象的话,插入能够提供更多的插入控制。
*/
Ajax.Updater = Class.create();
Ajax.Updater.prototype = (new Ajax.Base()).extend({
initialize: function(container, url, options) {
this.container = $(container);
this.setOptions(options);
if (this.options.asynchronous) {
this.onComplete = this.options.onComplete;
this.options.onComplete = this.updateContent.bind( this);
}
this.request = new Ajax.Request(url, this.options);
if (!this.options.asynchronous)
this.updateContent ();
},
updateContent: function() {
if (this.options.insertion) {
new this.options.insertion(this.container,
this .request.transport.responseText);
} else {
this.container.innerHTML = this.request.transport.responseText;
}
if (this.onComplete) {
setTimeout((function() {this.onComplete(this.request)}).bind(this), 10);
}
}
});
/**
* 페이지 요소 개체의 도구 클래스에 대한 몇 가지 간단한 정적 메서드를 제공합니다.
*/
var Field = {
/**
* 매개변수 참조 객체의 값 지우기
*/
clear: function() {
for(var i = 0; i $(arguments[i]).value = '';
},
/**
* 매개변수 참조 객체에 포커스를 부여합니다
*/
focus: function(element) {
$(element).focus();
},
/**
* 매개변수 참조 객체 값이 비어 있는지 확인합니다. 비어 있으면 false를 반환하고, 그렇지 않으면 true를 반환합니다.
*/
현재: function() {
for (var i = 0; i if ($(arguments[i]).value == '') false를 반환합니다.
true를 반환합니다.
},
/**
* 선택한 매개변수 참조 객체를 만듭니다
*/
선택: function(element) {
$(element).select();
},
/**
* 매개변수 참조 개체를 편집 가능하게 만듭니다
*/
활성화: function(element) {
$(element).focus();
$(element).select();
}
}
/*----------------------------------- -------------------------*/
/* *
* 양식 도구 클래스
*/
var Form = {
/**
* 양식 요소의 직렬화된 값을 QueryString 형식으로 결합합니다.
*/
직렬화: function(form) {
var elements = Form.getElements($(form));
var queryComponents = new Array();
for (var i = 0; i var queryComponent = Form.Element.serialize(elements[i]);
if (queryComponent)
queryComponents.push(queryComponent);
}
return queryComponents.join('&');
},
/**
*
형식의 모든 요소 객체를 가져옵니다.*/
getElements: function(form) {
form = $(form);
var elements = new Array();
for(Form.Element.Serializers의 tagName) {
var tagElements = form.getElementsByTagName(tagName);
for (var j = 0; j elements.push(tagElements[j]);
}
요소를 반환합니다.
},
/**
* 将指定表单的元素置于不可用状态
*/
禁用: function(form) {
var elements = Form.getElements(form);
for (var i = 0; i var element = elements[i];
element.blur();
element.disable = 'true';
}
},
/**
* 使表单的第一个非 hidden 类型而且处于可用状态的元素获得焦点
*/
focusFirstElement: 函数(表单) {
表单 = $(表单);
var elements = Form.getElements(form);
for (var i = 0; i var element = elements[i];
if (element.type !='隐藏' && !element.disabled) {
Field.activate(element);
休息;
}
}
},
/*
* 重置表单
*/
重置: 函数(表单) {
$(表单) 。重置();
}
}
/**
* 表单元素工具类
*/
Form.Element = {
/**
* 返回表单元素的值先序列化再进行 URL 编码后的值
*/
序列化: 函数(元素) {
元素 = $(元素);
var method = element.tagName.toLowerCase();
var 参数 = Form.Element.Serializers[method](element);
if (参数)
return encodeURIComponent(parameter[0]) '='
encodeURIComponent(parameter[1]);
},
/**
* 返回表单元素序列化后的值
*/
getValue: 函数(元素) {
元素 = $(元素);
var method = element.tagName.toLowerCase();
var 参数 = Form.Element.Serializers[method](element);
if(参数)
返回参数[1];
}
}
/**
* prototype 的所谓序列化其实就是将表单的名字和值组合成一个数组
*/
Form.Element.Serializers = {
输入:函数(元素) {
switch (element.type) .toLowerCase()) {
case '隐藏':
case '密码':
case '文本':
return Form.Element.Serializers.textarea(element);
case ‘checkbox’:
case ‘radio’:
return Form.Element.Serializers.inputSelector(element);
}
返回 false;
},
inputSelector: 函数(元素) {
if (element.checked)
return [element.name, element.value];
},
textarea: 函数(元素) {
return [element.name, element.value];
},
/**
* 看样子,也不支持多选框(select-multiple)
*/
select: 函数(元素) {
var index = element.selectedIndex;
var 值 = element.options[index].value || 元素.选项[索引].文本;
返回[元素.名称,(索引>=0)? 价值 : ''];
}
}
/*------------------------------- -----------------*/
/**
* Form.Element.getValue 는 자주 사용하게 될 것 같아 단축키 참고를 해두었습니다
*/
var $F = Form.Element.getValue;
/*------------------------------- -----------------*/
/**
* Abstract.TimedObserver는 Class.create()를 사용하여 생성되지 않으며 Ajax.Base와 동일한 의도를 가져야 합니다.
* Abstract.TimedObserver는 이름에서 알 수 있듯이 Observer 디자인 패턴을 적용하여 지정된 양식 요소를 추적합니다. ,
* form 요소의 값이 변경되었을 때 콜백 함수가 실행되는 경우
*
* Observer는 onchange 이벤트를 등록하는 것과 비슷한 것 같은데 차이점은 onchange 이벤트가 발생하는 경우는 다음과 같습니다. 요소가 포커스를 잃습니다.
* onpropertychange 이벤트와도 유사하지만 양식 요소 값의 변경에만 초점을 맞추고 시간 초과 제어를 제공합니다.
*
* 그리고 Observer의 장점은 아마도 객체 지향적이라는 점일 것입니다. 게다가 콜백 함수를 동적으로 변경할 수 있어 이벤트를 등록하는 것보다 더 유연합니다.
* 관찰자는 동적 데이터 확인 또는 여러 관련 드롭다운 옵션 목록 연결 등이 가능해야 합니다.
*
*/
Abstract.TimedObserver = function() {}
/**
* 이 디자인은 PeriodicalExecuter와 동일하며, 바인딩 방식이 구현의 핵심입니다
*/
Abstract.TimedObserver.prototype = {
초기화: 함수(요소, 주파수, 콜백) {
this.주파수 = 주파수;
this.element = $(요소);
this.callback = 콜백;
this.lastValue = this.getValue();
this.registerCallback();
},
registerCallback: function() {
setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
},
onTimerEvent: function() {
var value = this.getValue();
if (this.lastValue != value) {
this.callback(this.element, value);
this.lastValue = 값;
}
this.registerCallback();
}
}
/**
* Form.Element.Observer와 Form.Observer는 실제로 동일합니다
* Form.Observer는 전체 폼을 추적하는 데 사용되지 않는다는 점을 참고하세요. 단지 글쓰기를 줄이기 위한 것이라고 생각합니다(이것은 Form.Observer의 디자인 원칙입니다. 루비)
*/
Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({
getValue: function() {
return Form.Element.getValue(this.element);
}
});
Form.Observer = Class.create();
Form.Observer.prototype = (new Abstract.TimedObserver()).extend({
getValue: function() {
return Form.serialize(this.element);
}
});
/**
* 클래스 속성 이름을 기반으로 객체 배열을 가져오고 여러 클래스를 지원합니다.
*
*/
document.getElementsByClassName = function(className) {
var children = document.getElementsByTagName('*') || 문서.모두;
var elements = new Array();
for (var i = 0; i var child = children[i];
var classNames = child.className.split(' ');
for (var j = 0; j if (classNames[j] == className) {
elements.push(child);
휴식;
}
}
}
요소를 반환합니다.
}
/*------------------------- -----------------------*/
/**
* 요소 就象一个 java 적工具类, 主要用来 隐藏/显示/销除 对象, 以及获取对象的简单属性.
*
*/
var 요소 = {
toggle: function() {
for (var i = 0; i var 요소 = $(인수[i]);
element.style.display =
(element.style.display == '없음' ? '' : '없음');
}
},
hide: function() {
for (var i = 0; i var 요소 = $(arguments[ 나]);
element.style.display = '없음'; [ 나]);
element.style.display = '';
}
},
remove: function(element) { element = $(element);
element.parentNode.removeChild(element);
},
getHeight: function(element) {
element = $(element);
return element.offsetHeight;
}
}
/**
* 아마도 호환성 이유로 Element.toggle에 대한 심볼릭 링크를 만들었습니다.
*/
var Toggle = new Object();
Toggle.display = Element.toggle;
/*------------------------------- -----------------*/
/**
* 동적으로 삽입된 콘텐츠 구현을 위해 MS Jscript 구현의 개체에는 insertAdjacentHTML 메서드가 있습니다(http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertadjacenthtml.asp)
* 여기서는 객체 형태의 캡슐화로 간주됩니다.
*/
Abstract.Insertion = function(adjacency) {
this.adjacency = adjacency;
}
Abstract.Insertion.prototype = {
초기화: function(element, content) {
this.element = $(element);
this.content = 콘텐츠;
if (this.adjacency && this.element.insertAdjacentHTML) {
this.element.insertAdjacentHTML(this.adjacency, this.content);
} else {
/**
* gecko는 insertAdjacentHTML 메소드를 지원하지 않지만 대신 다음 코드를 사용할 수 있습니다
*/
this.range = this.element.ownerDocument.createRange();
/**
* 초기화Range 메소드가 정의되어 있으면 실행됩니다. 이는 추상적인 초기화Range 메소드를 정의하는 것과 같습니다.
*/
if (this.initializeRange) this.initializeRange();
this.fragment = this.range.createContextualFragment(this.content);
/**
* insertContent도 추상 메소드이므로 서브클래스에서 이를 구현해야 합니다
*/
this.insertContent();
}
}
}
/**
* 프로토타입 加深了我的体会,就是写js 如何去遵循 Don't Repeat Yourself(DRY) 🎜> * 上文中 Abstract.Insertion 算是一个抽象类, 定义了name为 initializeRange 적의 一个抽象방법
* var Insertion = new Object() 建立一个命名 空间
* Inser tion.Before|Top|Bottom|After 就象是4个java中的4个静态内部类,而它们分别继承于Abstract.Insertion,并实现了initializeRange방법。
*/
var 삽입 = new Object();
Insertion.Before = Class.create();
Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
initializeRange: function() {
this.range.setStartBefore(this.element);
},
/**
* 지정된 노드 앞에, 지정된 노드와 동일한 수준에 콘텐츠를 삽입합니다.
*/
insertContent: function() {
this.element.parentNode.insertBefore(this.fragment, this.element);
}
});
Insertion.Top = Class.create();
Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(true);
},
/**
* 지정된 노드의 첫 번째 하위 노드 앞에 콘텐츠를 삽입하면 해당 콘텐츠가 해당 노드의 첫 번째 하위 노드가 됩니다.
*/
insertContent: function() {
this.element.insertBefore(this.fragment, this.element.firstChild);
}
});
Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(this.element);
},
/**
* 지정된 노드의 끝에 콘텐츠를 삽입하면 콘텐츠가 해당 노드의 마지막 하위 노드가 됩니다.
*/
insertContent: function() {
this.element.appendChild(this. 조각);
}
});
삽입.After = Class.create();
Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
initializeRange: function() {
this.range.setStartAfter(this.element);
},
/**
* 지정된 노드 뒤에, 지정된 노드와 동일한 수준에 콘텐츠를 삽입합니다.
*/
insertContent: function() {
this.element.parentNode.insertBefore(this.fragment,
this.element.nextSibling);
}
});
/* 这是包含错误적의 원본
if (!Function.prototype.apply) {
// http://www.youngpup.net/의 코드 기반
Function.prototype.apply = function(object, parameters) {
var parameterStrings = new Array();
if (!object) 객체 = 창;
if (!parameters) 매개변수 = new Array();
for (var i = 0; i parameterStrings[i] = 'x[' i ']'; //오류 1
object.__apply__ = this;
var result = eval('obj.__apply__(' //오류 2
parameterStrings[i].join(', ') ')');
object.__apply__ = null;
결과 반환;
}
}
*/
if (!Function.prototype.apply) {
Function.prototype.apply = function(object, parameters) {
var parameterStrings = 새 배열();
if (!object) 객체 = 창;
if (!parameters) 매개변수 = new Array();
for (var i = 0; i parameterStrings[i] = 'parameters[' i ']';
object.__apply__ = 이;
var result = eval('object.__apply__(' parameterStrings.join(', ') ')');
object.__apply__ = null;
반환 결과;
}
}
Effect 적의 一个子类
Effect.Blink = Class.create();
Effect.Blink.prototype = {
초기화: function(element, 주파수) {
this.element = $(element);
this.주파수 = 주파수?주파수:1000;
this.element.eff_blink = 이것;
this.blink();
},
blink: function() {
if (this.timer) clearTimeout(this.timer);
시도해 보세요 {
this.element.style.visibility = this.element.style.visibility == '숨김'?'visible':'hidden';
} catch (e) {}
this.timer = setTimeout(this.blink.bind(this), this.주파수);
}
};