オブジェクトを勉強しなおす
雪を降らせるスクリプトを過去のHDDから拾ってきた。
こういうスクリプトを見たとき感動したことを思い出す。
じっくりと眺めている。
基本というかこのテーマが「オブジェクトを移譲しまくる!」なのだが、
未だにこんな書き方の発想を1から作ることができない。
というか忘れてしまっている。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <title>Snow</title> <style type="text/css"> body { background-color:black; overflow: hidden; } </style> <body> <script type="text/javascript"> if ('undefined' != typeof addEventListener || 'undefined' != typeof attachEvent && 'undefined' != typeof setInterval && 'undefined' != typeof Function.prototype && 'undefined' != typeof Function.prototype.call) /*@cc_on @if (1) attachEvent('on' + @else@*/ addEventListener(/*@end@*/ 'load', function () { //______________________________________________________________________ var Math2 = new function () { var PI = Math.PI; var sin = Math.sin; var floor = Math.floor; var random = Math.random; var sintab = [ ]; var i; for (i = 0; i < 360; i++) sintab[i] = sin(i * PI/180); this.sinDeg = function (deg) { return sintab[deg]; }; this.randomInt = function (n) { return floor(random() * n); }; }; //______________________________________________________________________ function Starter (callbackfn) { this.timerID = (function (o) { return setInterval(function () { return callbackfn.call(o); }, o.interval); })(this); } function Stopper () { clearInterval(this.timerID); } function Timer () { this.timerID = null; this.interval = Math2.randomInt(30) + 16; } // Timer.prototype.__proto__ = null; Timer.prototype.start = function (listener) { return Starter.call(this, listener); }; Timer.prototype.stop = function () { return Stopper.call(this); }; //______________________________________________________________________ function Decorator (alpha, size) { //@ this.filter = 'Alpha(opacity=' + alpha + ')'; this.opacity = alpha / 100 + ''; this.fontSize = size + 'px'; } function Locator (x, y) { this.left = x + 'px'; this.top = y + 'px'; } function Mover (element) { Timer.call(this); this.element = element; } // Mover.prototype.__proto__ = Timer.prototype; Mover.prototype = new Timer; Mover.prototype.constructor = Mover; Mover.prototype.move = function (x, y) { return Locator.apply(this.element.style, arguments); }; Mover.prototype.view = (function () { var C = document /*@if (1) [document.compatMode == 'CSS1Compat' ? 'documentElement' : 'body'] /*@else@*/ .defaultView /*@end@*/; return function () { return { innerWidth : /*@if (1) C.clientWidth @else@*/ C.innerWidth /*@end@*/, innerHeight: /*@if (1) C.clientHeight @else@*/ C.innerHeight /*@end@*/ }; }; })(); //______________________________________________________________________ function Snow (element) { Mover.apply(this, arguments); this.p = 0; this.x = 0; this.y = 0; this.z = 0; this.init(1); } // Snow.prototype.__proto__ = Mover.prototype; Snow.prototype = new Mover; Snow.prototype.constructor = Snow; Snow.prototype.init = (function (randomInt) { return function (n) { var v = this.view(); this.x = randomInt(v.innerWidth); this.y = randomInt(v.innerHeight) * Boolean(n); this.z = randomInt(5) + 1; Decorator.call(this.element.style, randomInt(80) + 21, this.z * 7); }; })(Math2.randomInt); Snow.prototype.fall = (function (floor, sinDeg) { var PI = Math.PI; return function () { var v = this.view(); var x; var y; this.y += this.z / 2 + 2; this.p += 2; if (this.y > v.innerHeight) this.init(); x = this.x + floor(sinDeg(this.p * 2 % 360) * 6 * this.z); y = this.y + floor(sinDeg(this.p % 360) * 6 * this.z); this.move(x, y); }; })(Math.floor, Math2.sinDeg); Snow['#instances'] = [ ]; Snow.create = function () { var d = document; var e = d.createElement('p'); var s = e.style; var o; e.appendChild(d.createTextNode('*')); s.color = '#fff'; s.position = 'absolute'; o = new this(d.body.appendChild(e)); Snow['#instances'].push(e, o); o.start(o.fall); return o; }; document./*@if (1) attachEvent('on' + @else@*/ addEventListener(/*@end@*/ 'click', function (evt) { var x = Snow['#instances']; var snow; var i = 0; var e = evt.target || evt.srcElement; while (snow = x[i++]) { if (snow == e) { x[i].stop(); break; } } }, false); //______________________________________________________________________ Snow.demo = function (n) { for (var i = 0; i < n; i++) this.create(); }; Snow.demo (200); //______________________________________________________________________ }, false); </script>
ちょっと変更
もうIEは捨てて、まずは従来通りに書き直してみる。
クリックして落下を止める機能に再開機能を付加する。
まだ思慮の最中。
細かいことだが悩み出すとキリがない。
<!DOCTYPE html> <meta charset="utf-8"> <title>Snow</title> <style> body { background-color:black; overflow: hidden; } </style> <body> <script> if ('undefined' !== typeof addEventListener && 'undefined' !== typeof setInterval && 'undefined' !== typeof Function.prototype && 'undefined' !== typeof Function.prototype.call && 'undefined' !== typeof Function.prototype.apply ) /* window. */ addEventListener('load', function () { //__ function floor (n) { return Math.floor (n); } function randomInt (n) { return floor (Math.random () * n); } var sinDeg = new function () { var sintab = [ ]; var sin = Math.sin; var rad = Math.PI / 180; var val = 0; for (var i = 0; i < 360; i++) { sintab[i] = sin (val); val += rad; } return function sinDeg (deg) { return sintab[deg % 360]; }; }; //__ function Starter (callbackfn) { this.timerID = setInterval (callbackfn.bind (this), this.interval); } function Stopper () { clearInterval (this.timerID); this.timerID = null; } function Timer () { this.timerID = null; this.interval = randomInt (30) + 16; } function start () { return Starter.call (this, this.motion); } function stop () { return Stopper.call (this); } Timer.prototype.start = start; Timer.prototype.stop = stop; //__ function Decorator (alpha, size) { this.opacity = alpha / 100 + ''; this.fontSize = size + 'px'; } function Locator (x, y) { this.left = x + 'px'; this.top = y + 'px'; } function Mover (element) { Timer.call (this); this.element = element; } function move (x, y) { return Locator.apply (this.element.style, arguments); } function view () { var C = this.element.ownerDocument.defaultView; return { innerWidth : C.innerWidth, innerHeight: C.innerHeight }; } Mover.prototype = new Timer; Mover.prototype.constructor = Mover; Mover.prototype.move = move; Mover.prototype.view = view; //__ function Snow (element) { Mover.apply (this, arguments); this.p = 0; this.x = 0; this.y = 0; this.z = 0; } function init (n) { var v = this.view (); this.x = randomInt (v.innerWidth); this.y = randomInt (v.innerHeight) * Boolean (n); this.z = randomInt (5) + 1; this.p = randomInt (360); Decorator.call (this.element.style, randomInt (80) + 21, this.z * 7); } //実験的な例としてクリックしたら落下を止める document.addEventListener('click', clickStopper, false); function clickStopper (event) { var x = Snow['#instances']; var snow; var i = 0; var e = event.target; while (snow = x[i++]) { if (snow.element === e) { snow[snow.timerID ? 'stop': 'start'](); break; } } } //__ function fall () { var h = this.view ()['innerHeight']; var x; var y; this.y += this.z / 2 + 2; this.p += 1; if (this.y > h) this.init (); x = this.x + floor(sinDeg(this.p * 2) * 6 * this.z); y = this.y + floor(sinDeg(this.p ) * 6 * this.z); this.move(x, y); } //__ function create () { var d = document; var e = d.createElement ('p'); var s = e.style; var obj; e.appendChild (d.createTextNode ('*')); s.color = '#fff'; s.position = 'absolute'; obj = new this (d.body.appendChild (e)); obj.init (true); obj.start (); Snow['#instances'].push (obj); return obj; }; function demo (n) { if (0 < n) while (n--) this.create (); } //__ Snow.prototype = new Mover; Snow.prototype.constructor = Snow; Snow.prototype.fall = fall; Snow.prototype.init = init; Snow.prototype.motion = fall; //__ Snow['#instances'] = [ ]; Snow.create = create; Snow.demo = demo; //__ Snow.demo (100); }, false); </script>
Object.create で書き直す(思案中)
今ひとつ統一感がないな。
最初が Timer ではなく、new Object だな〜
<!DOCTYPE html> <meta charset="utf-8"> <title>Snow</title> <style> body { background-color:black; overflow: hidden; } </style> <body> <script> if ('undefined' !== typeof addEventListener && 'undefined' !== typeof setInterval && 'undefined' !== typeof Function.prototype && 'undefined' !== typeof Function.prototype.call && 'undefined' !== typeof Function.prototype.apply && 'undefined' !== typeof Function.prototype.bind ) /* window. */ addEventListener('load', function () { //__ // 整数化 function floor (n) { return Math.floor (n); } // 乱数を整数(0からn未満)を返す function randomInt (n) { return floor (Math.random () * n); } // Sin関数は前もって計算しておく var sinDeg = new function () { var sintab = [ ]; var sin = Math.sin; var rad = Math.PI / 180; var val = 0; for (var i = 0; i < 360; i++) { sintab[i] = sin (val); val += rad; } return function sinDeg (deg) { return sintab[deg % 360]; }; }; //__ function Timer (interval) { this.interval = interval; } function Starter (cbFunc) { this.timerID = setInterval (cbFunc.bind (this), this.interval); } function Stopper () { clearInterval (this.timerID); this.timerID = null; } Object.defineProperty (Timer.prototype, 'timerID', { value : null, writable : true, enumerable : false, configurable: false }); Object.defineProperty (Timer.prototype, 'interval', { value : null, writable : true, enumerable : true, configurable: false }); Object.defineProperty (Timer.prototype, 'start', { value : Starter, writable : false, enumerable : true, configurable: false }); Object.defineProperty (Timer.prototype, 'stop', { value : Stopper, writable : false, enumerable : true, configurable: false }); //var p =[];for(var o in Timer.prototype) p.push(o); alert(p.join("\n")); //__ function Decorator (alpha, size) { this.opacity = alpha / 100 + ''; this.fontSize = size + 'px'; } function Locator (x, y) { this.left = x + 'px'; this.top = y + 'px'; } function Mover (element) { Timer.call (this); this.element = element; } function move (x, y) { return Locator.apply (this.element.style, arguments); } function view () { var C = this.element.ownerDocument.defaultView; return { innerWidth : C.innerWidth, innerHeight: C.innerHeight }; } Mover.prototype = Object.create ( Timer.prototype, { constructor: { value: Mover }, view: { value : view, writable : false, enumerable : false, configurable: false }, move: { value : move, writable : false, enumerable : true, configurable: false } }); //__ function Snow (element) { Mover.apply (this, arguments); this.p = 0; this.x = 0; this.y = 0; this.z = 0; } function init (n) { var v = this.view (); this.x = randomInt (v.innerWidth); this.y = randomInt (v.innerHeight) * Boolean (n); this.z = randomInt (5) + 1; this.p = randomInt (360); this.interval = randomInt (30) + 16; Decorator.call (this.element.style, randomInt (80) + 21, this.z * 10); } //実験的な例としてクリックしたら落下を止める document.addEventListener('click', clickStopper, false); function clickStopper (event) { var x = Snow['#instances']; var snow; var i = 0; var e = event.target; while (snow = x[i++]) { if (snow.element === e) { snow.timerID ? snow.stop (): snow.start (fall); break; } } } //__ function fall () { var h = this.view ()['innerHeight']; var x; var y; this.y += this.z / 2 + 2; this.p += 1; if (this.y > h) this.init (); x = this.x + floor(sinDeg(this.p * 2) * 6 * this.z); y = this.y + floor(sinDeg(this.p ) * 6 * this.z); this.move(x, y); } //__ function create () { var d = document; var e = d.createElement ('p'); var s = e.style; var obj; e.appendChild (d.createTextNode ('*')); s.color = '#fff'; s.position = 'absolute'; obj = new this (d.body.appendChild (e)); obj.init (true); obj.start (fall); Snow['#instances'].push (obj); return obj; }; function demo (n) { if (0 < n) while (n--) this.create (); } //__ Snow.prototype = new Mover; Snow.prototype.constructor = Snow; Snow.prototype.fall = fall; Snow.prototype.init = init; Snow.prototype.motion = fall; //__ Snow['#instances'] = [ ]; Snow.create = create; Snow.demo = demo; //__ Snow.demo (100); }, false); </script>
new Object じゃなくて new Function だったか…
<!DOCTYPE html> <meta charset="utf-8"> <title>Snow</title> <style> body { background-color:black; overflow: hidden; } </style> <body> <script> if ('undefined' !== typeof addEventListener && 'undefined' !== typeof setInterval && 'undefined' !== typeof Function.prototype && 'undefined' !== typeof Function.prototype.call && 'undefined' !== typeof Function.prototype.apply && 'undefined' !== typeof Function.prototype.bind ) /* window. */ addEventListener('load', function () { //__ // 整数化 function floor (n) { return Math.floor (n); } // 乱数を整数(bからe未満)を返す function randomInt (b, e) { switch (arguments.length) { case 2 : return floor (Math.random () * (e - b)) + b; case 1 : return floor (Math.random () * b); default : throw new Error; } } // Sin関数は前もって計算しておく var sinDeg = new function () { var sintab = [ ]; var sin = Math.sin; var rad = Math.PI / 180; var val = 0; for (var i = 0; i < 360; i++) { sintab[i] = sin (val); val += rad; } return function sinDeg (deg) { return sintab[deg % 360]; }; }; //__ var obj = new Function; function Timer (interval) { this.interval = interval; } function Starter (cbFunc) { this.timerID = setInterval (cbFunc.bind (this), this.interval); } function Stopper () { clearInterval (this.timerID); this.timerID = null; } Timer.prototype = Object.create ( obj.prototype, { constructor: { value: Timer }, timerID: { value : null, writable : true, enumerable : false, configurable: false }, interval: { value : null, writable : true, enumerable : true, configurable: false }, start: { value : Starter, writable : false, enumerable : true, configurable: false }, stop: { value : Stopper, writable : false, enumerable : true, configurable: false } }); //var p =[];for(var o in Timer.prototype) p.push(o); alert(p.join("\n")); //__ function Decorator (alpha, size) { this.opacity = alpha / 100 + ''; this.fontSize = size + 'px'; } function Locator (x, y) { this.left = x + 'px'; this.top = y + 'px'; } function Mover (element) { Timer.call (this); this.element = element; } function move (x, y) { return Locator.apply (this.element.style, arguments); } function view () { var C = this.element.ownerDocument.defaultView; return { innerWidth : C.innerWidth, innerHeight: C.innerHeight }; } Mover.prototype = Object.create ( Timer.prototype, { constructor: { value: Mover }, view: { value : view, writable : false, enumerable : false, configurable: false }, move: { value : move, writable : false, enumerable : true, configurable: false } }); //__ function Snow (element) { Mover.apply (this, arguments); this.p = 0; this.x = 0; this.y = 0; this.z = 0; } function init (n) { var v = this.view (); this.x = randomInt (v.innerWidth); this.y = randomInt (v.innerHeight) * Boolean (n); this.z = randomInt (1, 6); this.p = randomInt (360); this.interval = randomInt (40, 80); Decorator.call (this.element.style, randomInt (21, 80), this.z * 7); } //__ Snow.prototype = Object.create ( Mover.prototype, { constructor: { value: Snow }, init: { value : init, writable : false, enumerable : true, configurable: false } });; //実験的な例としてクリックしたら落下を止める document.addEventListener('click', clickStopper, false); function clickStopper (event) { var x = Snow['#instances']; var snow; var i = 0; var e = event.target; while (snow = x[i++]) { if (snow.element === e) { snow.timerID ? snow.stop (): snow.start (fall); break; } } } //__ function fall () { var h = this.view ()['innerHeight']; var x; var y; this.y += this.z / 2 + 2; this.p += 1; if (this.y > h) this.init (); x = this.x + floor(sinDeg(this.p * 2) * 6 * this.z); y = this.y + floor(sinDeg(this.p ) * 6 * this.z); this.move(x, y); } //__ function create () { var d = document; var e = d.createElement ('p'); var s = e.style; var obj; e.appendChild (d.createTextNode ('*')); s.color = '#fff'; s.position = 'absolute'; obj = new this (d.body.appendChild (e)); obj.init (true); obj.start (fall); Snow['#instances'].push (obj); return obj; }; function demo (n) { if (0 < n) while (n--) this.create (); } //__ Snow['#instances'] = [ ]; Snow.create = create; Snow.demo = demo; //__ Snow.demo (100); }, false); </script>