We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
虽然现在已经是ES6的时代,但是,还是有必要了解下ES5是怎么写一个类的。 本文详述JavaScript面向对象编程中的类写法,并分步骤讲述如何写出优雅的类。
例子为一个轻提示组件Toast。 需要实现的功能:
Toast
on
off
init
function Toast(option){ this.prompt = ''; this.elem = null; this.init(option); } Toast.prototype = { // 构造器 constructor: Toast, // 初始化方法 init: function(option){ this.prompt = option.prompt || ''; this.render(); this.bindEvent(); }, // 显示 show: function(){ this.changeStyle(this.elem, 'display', 'block'); }, // 隐藏 hide: function(){ this.changeStyle(this.elem, 'display', 'none'); }, // 画出dom render: function(){ var html = ''; this.elem = document.createElement('div'); this.changeStyle(this.elem, 'display', 'none'); html += '<a class="J-close" href="javascript:;">x</a>' html += '<p>'+ this.prompt +'</p>'; this.elem.innerHTML = html; return document.body.appendChild(this.elem); }, // 绑定事件 bindEvent: function(){ var self = this; this.addEvent(this.elem, 'click', function(e){ if(e.target.className.indexOf('J-close') != -1){ console.log('close Toast!'); self.hide(); } }); }, // 添加事件方法 addEvent: function(node, name, fn){ var self = this; node.addEventListener(name, function(){ fn.apply(self, Array.prototype.slice.call(arguments)); }, false); }, // 改变样式 changeStyle: function(node, key, value){ node.style[key] = value; } }; var T = new Toast({prompt:'I\'m Toast!'}); T.show();
JavaScript的类,是用函数对象来实现。 类的实例化形式如下:
函数对象
var T = new Toast();
其中的重点,就是Function的编写。
Function
类分为两部分:constructor+prototype。也即构造器+原型。
constructor
prototype
构造器
原型
构造器从直观上来理解,就是写在函数内部的代码。 从Toast例子上看,构造器就是以下部分:
function Toast(option){ this.prompt = ''; this.elem = null; this.init(option); }
这里的this,指向的是实例化的类。 每次通过new Toast()的方式进行实例化,构造器都会执行一遍。
this
new Toast()
原型上的方法和变量的声明,都是通过Toast.prototype.*的方式。 那么在原型上普通的写法如下:
Toast.prototype.*
Toast.prototype.hide = function(){/*code*/} Toast.prototype.myValue = 1;
但是,该写法不好的地方:就是每次都要写前半部分Toast.prorotype,略显累赘。 在代码压缩优化方面也不友好,无法做到最佳的压缩。 改进的方式如下:
Toast.prorotype
Toast.prorotype = { constructor: Toast, hide: function(){/*code*/}, myValue: 1 }
这里的优化,是把原型指向一个新的空对象{}。 带来的好处,就是可以用{key:value}的方式写原型上的方法和变量。 但是,这种方式会改变原型上构造器prototype.constructor的指向。 如果不重新显式声明constructor的指向,Toast.constructor.prototype.constructor的会隐式被指向Object。而正确的指向,应该是Toast。 虽然通过new实例化没有出现异常,但是在类继承方面,constructor的指向异常,会产生不正确的继承判断结果。这是我们不希望看到的。 所以,需要修正constructor。
{}
{key:value}
prototype.constructor
Toast.constructor.prototype.constructor
Object
new
原型上的方法和变量,是该类所有实例化对象共享的。也就是说,只有一份。 而构造器内的代码块,则是每个实例化对象单独占有。不管是否用this.**方式,还是私有变量的方式,都是独占的。 所以,在写一个类的时候,需要考虑该新增属性是共享的,还是独占的。以此,决定在构造器还是原型上进行声明。
this.**
类的实例化,一个强制要求的行为,就是需要使用new操作符。如果不使用new操作符,那么构造器内的this指向,将不是当前的实例化对象。 优化的方式,就是使用instanceof做一层防护。
instanceof
function Toast(option){ if(!(this instanceof Toast)){ return new Toast(option); } this.prompt = ''; this.elem = null; this.init(option); }
从上述代码可以看出,使用这个技巧,可以防止团队一些大头虾出现使用错误实例化方式,导致代码污染的问题。 这种忍者技巧很酷,但从另一方面考虑,还是希望使用者可以用正确的方式去�实例化类�。 所以,改成以下这种防护方式
function Toast(option){ if(!(this instanceof Toast)){ throw new Error('Toast instantiation error'); } this.prompt = ''; this.elem = null; this.init(option); }
这样,把锅甩回去,岂不是更妙👽
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
虽然现在已经是ES6的时代,但是,还是有必要了解下ES5是怎么写一个类的。
本文详述JavaScript面向对象编程中的类写法,并分步骤讲述如何写出优雅的类。
一、例子
例子为一个轻提示组件
Toast
。需要实现的功能:
on
方法,显示提示off
方法,隐藏提示init
方法,初始化提示语二、类的构成
JavaScript的类,是用
函数对象
来实现。类的实例化形式如下:
其中的重点,就是
Function
的编写。类分为两部分:
constructor
+prototype
。也即构造器
+原型
。2.1 构造器
构造器从直观上来理解,就是写在函数内部的代码。
从Toast例子上看,构造器就是以下部分:
这里的
this
,指向的是实例化的类。每次通过
new Toast()
的方式进行实例化,构造器都会执行一遍。2.2 原型
原型上的方法和变量的声明,都是通过
Toast.prototype.*
的方式。那么在原型上普通的写法如下:
但是,该写法不好的地方:就是每次都要写前半部分
Toast.prorotype
,略显累赘。在代码压缩优化方面也不友好,无法做到最佳的压缩。
改进的方式如下:
这里的优化,是把原型指向一个新的空对象
{}
。带来的好处,就是可以用
{key:value}
的方式写原型上的方法和变量。但是,这种方式会改变原型上构造器
prototype.constructor
的指向。如果不重新显式声明
constructor
的指向,Toast.constructor.prototype.constructor
的会隐式被指向Object
。而正确的指向,应该是Toast
。虽然通过
new
实例化没有出现异常,但是在类继承方面,constructor
的指向异常,会产生不正确的继承判断结果。这是我们不希望看到的。所以,需要修正
constructor
。2.3 构造器和原型的不同
原型上的方法和变量,是该类所有实例化对象共享的。也就是说,只有一份。
而构造器内的代码块,则是每个实例化对象单独占有。不管是否用
this.**
方式,还是私有变量的方式,都是独占的。所以,在写一个类的时候,需要考虑该新增属性是共享的,还是独占的。以此,决定在构造器还是原型上进行声明。
三、代码规范
四、使实例化与new无关
类的实例化,一个强制要求的行为,就是需要使用new操作符。如果不使用new操作符,那么构造器内的this指向,将不是当前的实例化对象。
优化的方式,就是使用
instanceof
做一层防护。从上述代码可以看出,使用这个技巧,可以防止团队一些大头虾出现使用错误实例化方式,导致代码污染的问题。
这种忍者技巧很酷,但从另一方面考虑,还是希望使用者可以用正确的方式去�实例化类�。
所以,改成以下这种防护方式
这样,把锅甩回去,岂不是更妙👽
The text was updated successfully, but these errors were encountered: