JavaScript is a language with a very low entry barrier. Even a technician who has never been exposed to JavaScript can write a simple and useful program code within a few hours.
But if you conclude from this: JavaScript is a simple language. Then you are dead wrong. If you want to write high-performance code, you also need to have the basic qualities of a senior programmer.
A java or c programmer may not necessarily be able to write high-performance javascript code, but it is easier to write high-performance javascript code.
The simplicity of JavaScript is based on its "broad-minded" inclusiveness. When it is declared, there is no need to specify a type, and it can even be converted to any type. It is object-oriented, but has no restrictions on classes. It is a language that advocates freedom and is very rigorous. If you are a liberal, then embrace JavaScript!
Object-oriented programming (OOP) is a popular programming method. However, JavaScript's OOP is very different from JAVA and C, mainly reflecting its different inheritance methods. JavaScript is inherited based on the prototype PROTOTYPE. All objects are based on the prototype chain, which is ultimately traced back to the Object object.
I don’t want to discuss too much about the differences between the inheritance method of JavaScript and the inheritance method of other languages. Mainly discusses how to encapsulate JavaScript Class in order to better manage and maintain basic code, reduce duplicate code, and achieve better modular programming.
The following are some of the better Class encapsulation libraries found on github:
1. MY-CLASS
Project address: https://github.com/ jiem/my-class
Let’s look at the basic usage first:
a. Create a new class
(function(){
//New class
varPerson=my.Class({
//Add static method
STATIC:{
AGE_OF_MAJORITY: 18
},
//Constructor
constructor:function(name,age){
this.name=name;
this.age=age;
},
//Instance method
sayHello:function(){
console.log('Hellofrom' this.name '!');
},
//Instance method
drinkAlcohol:function (){
this.age
console.log('Tooyoung!Drinkmilkinstead!'):
console.log('Whiskeyorbeer?');
}
} );
//Exposed to namespace
myLib.Person=Person;
})();
varjohn=newmyLib.Person('John',16);
john.sayHello ();//log"HellofromJohn!"
john.drinkAlcohol();//log"Tooyoung!Drinkmilkinstead!"
b. Inherit a class
(function(){
//Dreamer inherits Person
varDreamer=my. Class(Person,{
//Constructor method
constructor:function(name,age,dream){
Dreamer.Super.call(this,name,age);
this.dream=dream ;
},
//Instance method
sayHello:function(){
superSayHello.call(this);
console.log('Idreamof' this.dream '!');
},
//Instance method
wakeUp:function(){
console.log('Wakeup!');
}
});
//Super Access the parent class
varsuperSayHello=Dreamer.Super.prototype.sayHello;
//Exposed to the global namespace
myLib.Dreamer=Dreamer;
})();
varsylvester=newmyLib. Dreamer('Sylvester',30,'eatingTweety');
sylvester.sayHello();//log"HellofromSylvester!IdreamofeatingTweety!"
sylvester.wakeUp();//log"Wakeup!"
c. Add new methods to the class
//Add new methods to myLib.Dreamer
my.extendClass(myLib.Dreamer,{
//Add static methods
STATIC:{
s_dongSomeThing:function(){
console. log("dosomething!");
}
},
//Add instance method
touchTheSky:function(){
console.log('Touchingthesky');
} ,
//Add instance method
reachTheStars:function(){
console.log('Sheissopretty!');
}
});
d. Implement a class method
//Declare a new class
myLib.ImaginaryTraveler=my.Class({
travel:function(){console.log('Travelingonacarpet!');},
crossOceans: function(){console.log('SayinghitoMobyDick!');}
});
(function(){
//Dreamer inherits Person's method of implementing ImaginaryTraveler
varDreamer=my.Class( Person,ImaginaryTraveler,{
//Constructor method
constructor:function(name,age,dream){
Dreamer.Super.call(this,name,age);
this.dream=dream ;
}
//...
});
//Exposed to the global namespace
myLib.Dreamer=Dreamer;
})();
varaladdin =newDreamer('Aladdin');
aladdininstanceofPerson;//true
aladdininstanceofImaginaryTraveler;//false
aladdin.travel();
aladdin.wakeUp();
aladdin.sayHello() ;
If you are afraid of forgetting the new operator
varPerson=my.Class({
//youcannowcalltheconstructorwithorwithoutnew
constructor:function(name,city){
if(!(thisinstanceofPerson))
returnnewPerson(name,city);
this.name=name;
this.city=citye;
}
});
Let’s take a look at the source code analysis of my.class:
The implementation idea of my.Class is basically like this. If there is only one parameter, then a base class is declared. This parameter is used to declare the methods, properties and constructors of the new class. It is not inherited, but it can be inherited.
The idea of inheritance is that if there are two parameters, the first parameter is inherited as the parent class, and the second parameter is used to declare the methods, attributes and constructors of the new class, which can also be inherited.
If there are more than three parameters, except the first parameter as the inherited parent class, the last parameter is used to declare the methods, attributes and constructors of the new class. The middle parameter is the method that uses the class to extend the new class. Of course, new methods can also be extended through my.extendClass.
At the same time, the class library provides support for both commonJS and the browsing environment!
/*globalsdefine:true,window:true,module:true*/
(function(){
//Namespaceobject
varmy={};
//Guaranteed AMD Sub-modules are available
if(typeofdefine!=='undefined')
define([],function(){
returnmy;
});
elseif(typeofwindow!=='undefined ')
//Ensure that the client is available
window.my=my;
else
//Ensure that the background is available
module.exports=my;
//==== ================================================== ======================
//@methodmy.Class
//@paramsbody:Object
//@paramsSuperClass:function, ImplementClasses:function...,body:Object
//@returnfunction
my.Class=function(){
varlen=arguments.length;
varbody=arguments[len-1];/ /The last parameter is the method that specifies itself
varSuperClass=len>1?arguments[0]:null;//The first parameter refers to the inherited method, both the instance and the static part are inherited
varhasImplementClasses=len> 2;//If there is a third parameter, then the second one is implementClass, which actually only inherits the instance object
varClass, SuperClassEmpty;
//Guaranteed constructor method
if(body.constructor=== Object){
Class=function(){};
}else{
Class=body.constructor;
//Guarantee that the constructor is not overwritten later
deletebody.constructor;
}
//Processing the superClass part
if(SuperClass){
//Middleware implements inheritance of instance attributes
SuperClassEmpty=function(){};
SuperClassEmpty.prototype=SuperClass.prototype;
Class.prototype=newSuperClassEmpty();//Prototypal inheritance, dereference
Class.prototype.constructor=Class;//Guaranteed constructor
Class.Super=SuperClass;//Parent object access interface
//Static method inheritance, overloading the superClass method
extend(Class,SuperClass,false);
}
//Processing the ImplementClass part, in fact only inherits the instance attribute part, except SuperClass#arguments[0] #And body#arguments[length-1]#
if(hasImplementClasses)
for(vari=1;i//implement is the inherited instance attribute part, overloaded Parent object implementClass method
extend(Class.prototype,arguments[i].prototype,false);
//The processing itself declares the body part, the static part must be specified STATIC, and the instance part must delete the STATIC part
extendClass( Class,body);
returnClass;
};
////============================== ==============================================
/ /@methodmy.extendClass
//@paramsClass:function,extension:Object,?override:boolean=true
varextendClass=my.extendClass=function(Class,extension,override){
//Static part Inherit the static part
if(extension.STATIC){
extend(Class,extension.STATIC,override);
//Guarantee that the instance part does not inherit the static method
deleteextension.STATIC;
}
//Instance attributes are inherited from the instance part
extend(Class.prototype,extension,override);
};
//================ ================================================== ===========
varextend=function(obj,extension,override){
varprop;
//In fact, the flase here indicates the method of overriding the parent object
if(override===false){
for(propinextension)
if(!(propinobj))
obj[prop]=extension[prop];
}else{
// In fact, the methods of the parent object are not covered here, including toString
for(propinextension)
obj[prop]=extension[prop];
if(extension.toString!==Object.prototype.toString)
obj.toString=extension.toString;
}
};
})();
2. KLASS Project address: https://github.com/ded/klass
Let’s look at how to use it first:
a. Create a new class
//Declare a class
varPerson=klass(function(name){
this.name=name
})
.statics ({//Static method
head:':)',
feet:'_|_'
})
.methods({//Instance method
walk:function() {}
})
b. Inherit a class
//SuperHuman inherits Person
varSuperHuman=Person.extend(function(name){
//Automatically calls the parent class’s constructor
})
.methods ({
walk:function(){
//Explicitly declare to call the walk method of the parent class
this.supr()
this.fly()
},
fly :function(){}
})
newSuperHuman('Zelda').walk()
c, declare a class in literal mode
varFoo=klass({
foo:0,
initialize:function(){
this.foo=1
},
getFoo:function(){
returnthis.foo
},
setFoo:function(x){
this.foo= x
returnthis.getFoo()
}
})
d. Implement a class method
Because sometimes you may want to override or mix an instance method, you can do this:
//You can pass a literal to inherit
varAlien=SuperHuman.extend({
beam:function(){
this .supr()
//beamintospace
}
})
varSpazoid=newAlien('Zoopo')
if(beamIsDown){
//Override beam method
Spazoid.implement({
beam:function(){
this.supr()
//fallbacktojets
this.jets()
}
})
}
Let’s take a look at klass source code analysis:
The basic design idea of klass is very clear, and it tries its best to imitate the inheritance methods of other languages. For example: the subclass constructor calls the parent class's constructor, and you can also explicitly declare to call the parent class's method.
This kind of judgment is based on regular matching: fnTest=/xyz/.test(function(){xyz;})?/bsuprb/:/.*/; keyword "super"
If It is explicitly declared that the method of the parent class is to be called. When the method is declared, it is packaged into a function that internally calls the method of the parent class and returns the same value to the method of the current class.
On the other hand, the construction method is also relatively flexible. If initialize is explicitly declared, then this is the constructor. Otherwise, if the parameter is a function, then it is used as the constructor, otherwise the parent class's constructor is used.
Add static methods through statics, and add instance methods through instance's implements and static method methods.
Inheritance is achieved through the extend of the parent class.
At the same time, the class library provides support for both commonJS and the browsing environment!
/**
*Klass.js-copyright@dedfat
*version1.0
*https://github.com/ded/klass
*Followoursoftwarehttp://twitter.com/dedfat:)
*MITLicense
*/
!function(context,f){
//fnTest is used to verify whether it is possible to find out how to call the super parent class method through regular expressions
varfnTest=/xyz/.test(function(){xyz;})?/bsuprb/:/.*/,
noop=function(){},
proto='prototype',
isFn =function(o){
returntypeofo===f;
};
//Basic class
functionklass(o){
returnextend.call(typeofo==f?o:noop ,o,1);
}
//Wrap it into a function that borrows the super method of the same name
functionwrap(k,fn,supr){
returnfunction(){
//Cache the original this.super
vartmp=this.supr;
//Temporarily change this.super to borrow the method of the same name from super above
//Provide an explicit statement in o (fnTest.text(fn)= =true) To borrow the super method of the same name, use
this.supr=supr[proto][k];
//Borrow execution and save the return value
varret=fn.apply(this,arguments);
//Restore the original this.super
this.supr=tmp;
//Return the return value to ensure that the return value after wrapping is consistent with the original
returnret;
};
}
//If o and super have methods with the same name, and o explicitly declares to borrow the method of the same name from super, wrap it into a function to be executed for use
//If there is no explicit declaration to borrow the method of the same name from super , or it is a unique method of o, or if it is not a method, just use
functionprocess(what,o,supr){
for(varkino){
//If it is a non-inherited method, execute it according to the method annotation rules , finally put into what
if(o.hasOwnProperty(k)){
what[k]=typeofo[k]==f
&&typeofsupr[proto][k]==f
&&fnTest.test(o[k])
?wrap(k,o[k],supr):o[k];
}
}
}
//Inherited method Implementation, fromSub is used to control whether it is inherited. in the above klass, fromSub is 1, indicating that it is not inherited. The constructor does not use super to execute
functionextend(o, fromSub){
//noop as The media class implements dereference of prototypal inheritance
noop[proto]=this[proto];
varsupr=this,
prototype=newnoop(),//Create instance objects for prototypal inheritance, dereference
isFunction=typeofo==f,
_constructor=isFunction?o:this,//If o is a construction method, use it, otherwise this determines the constructor
_methods=isFunction?{}:o, //If o is a {...}, methods should be used to put it in the fn prototype. If there is initialize in it, it is the constructor. If o is a function, it is determined by the above _constructor. o is a constructor
fn=function() {//Because kclass relies on kclass, what is actually returned in the end is fn, which is actually the constructor of the new class
//1 If o is {...}, it will be directly filtered by methods and added to fn In the prototype of o, if there is initialize in o, then there is initialize in the prototype of fn, then it is the constructor method
//2 If o is a function, methods cannot add anything to the prototype of fn, but _constructor will Accept o as the constructor
//3 If o is {....} and there is no initialize in it, then this is the constructor. If it is determined by call in klass, obviously the constructor is noop. If in In non-base classes, the constructor is the constructor of the parent class
//Since o is not a function, the constructor of the parent class will not be automatically called, but the constructor of the parent class is regarded as the constructor of the current class----this It is all determined by the pointing of this
console.log(this);
if(this.initialize){
this.initialize.apply(this,arguments);
}else{
//Call the parent class constructor
//As shown in 3 above, o is not a function, and the parent class constructor will not be called
//The basic class has no parent class, and the parent class constructor will not be called
from Sub | ==noop);
_constructor.apply(this,arguments);
}
};
//Construct prototype method interface
fn.methods=function(o){
process(prototype,o,supr);
fn[proto]=prototype;
returnthis;
};
//Execute the prototype of the new class and ensure the constructor of the new class
fn .methods.call(fn,_methods).prototype.constructor=fn;
//Ensure that new classes can be inherited
fn.extend=arguments.callee;
//Add instance methods or static methods, statics: static method, implement instance method
fn[proto].implement=fn.statics=function(o,optFn){
//Guarantee that o is an object object. If o is a string, then it is When adding a method, if o is an object, it means it is added in batches
//Because it needs to be copied from o
o=typeofo=='string'?(function(){
varobj= {};
obj[o]=optFn;
returnobj;
}()):o;
//Add instance method or static method, statics: static method, implement instance method
process(this,o,supr);
returnthis;
};
returnfn;
}
//Backend use, nodejs
if(typeofmodule!=='undefined' &&module.exports){
module.exports=klass;
}else{
varold=context.klass;
//Anti-conflict
klass.noConflict=function(){
context.klass=old;
returnthis;
};
//For front-end browsers
//window.kclass=kclass;
context.klass=klass;
}
}(this,'function');
3. 간단한 구현도 있습니다 구현 아이디어는 매우 간단합니다. 즉, ECMAScript5 프로토타입을 사용하여 Object.create 메서드를 상속하고 이를 메서드로 캡슐화하는 것입니다. ECMAScript5 환경은 지원하지 않으므로 번역되어 성능이 저하됩니다.
functionF(){};
F.prototype=superCtor.prototype;
ctor.prototype=newF()
ctor.prototype.constructor=ctor;
마지막 매개변수가 현재 클래스의 메서드 선언이라는 점을 제외하면 다른 매개변수는 상위 클래스에서 상속되어 순환 상속이 필요하지만 여기에서의 처리는 비교적 간단하고 덮어쓰기가 포함되지 않습니다. 직접 추가할 수 있습니다.
varClass=(function(){
/* *
*함수 상속.(node.js)
*
*@paramctorsubclass'sconstructor.
*@paramsuperctorsuperclass의 생성자.
*/
varinherits=function(ctor,superCtor){
//부모 클래스를 명시적으로 지정
ctor.super_=superCtor;
//ECMAScript5 프로토타입 상속 및 역참조
if(Object.create){
ctor.prototype=Object.create(superCtor.prototype,{
생성자:{
값:ctor,
열거 가능:false,
쓰기 가능 :true,
configurable:true
}
});
}else{
//Object.create 메서드 없이 원활한 성능 저하
functionF(){}; .prototype=superCtor.prototype;
ctor.prototype=newF();
ctor.prototype.constructor=ctor;
}
}; 🎜>returnfunction(){
//마지막 매개변수는 새 클래스 메서드, 속성 및 생성자 선언입니다.
varsubClazz=arguments[arguments.length-1]||function(){}; 초기화는 생성자이고 그렇지 않으면 생성자는 빈 함수입니다.
varfn=subClazz.initialize==null?function(){}:subClazz.initialize;
//마지막 매개변수를 제외하고 클래스를 상속하면 더 많은 상속이 가능합니다. 확장 메서드로도 사용 가능
for(varindex=0;index
inherits(fn,arguments[index])
}
// 메서드 새로운 클래스 구현
for(varpropinsubClazz){
if(prop=="initialize"){
continue;
}
fn.prototype[prop]=subClazz[prop]
}
returnfn;
}
})()
다음 예를 참조하세요.
복사 코드
코드는 다음과 같습니다.
*/
initialize:function(name){
this.name=name
},
/**
*건축자.
*
*@paramname고양이 이름
*/
eat:function(){
alert (this. name "iseatingfish.");
}
})
/**
*먹기 기능.
*/
varBlackCat=Class(Cat,{
/**
*BlackCat 클래스의 정의.
*/
initialize:function(name,age){
//calltheconstructorofsuperclass.
BlackCat.super_.call(this,name)
this.age=age
} 🎜>/ **
*건축자.
*
*@paramname고양이 이름.
*@paramageCat'sage.
*/
eat:function(){
alert(this.name "(" this.age ")iseatingdog.")
}
});
/**
*먹기 기능.
*/
varBlackFatCat=Class(BlackCat,{
/**
*BlackFatCat 클래스의 정의입니다.
*@paramweightCat'sweight.
*/
초기화:함수(이름, age,weight ){
//calltheconstructorofsuperclass.
BlackFatCat.super_.call(this,name,age)
this.weight=weight;
/**
*건축자.
*
*@paramname고양이 이름.
*@paramageCat'sage.
*@paramweightCat의 체중입니다.
*/
eat:function(){
alert(this.name "(" this.age ")iseatingdog.Myweight:" this.weight)
}
}); >/* *
*먹기 기능.
*/
varDog=Class({});
varcat=newBlackFatCat("John",24,"100kg")
cat.eat(); //true
alert(catinstanceofCat);
//true
alert(catinstanceofBlackCat);//true
alert(catinstanceofBlackFatCat)
//true
alert( cat.constructor ===BlackFatCat);
//false
alert(catinstanceofDog);
mootools 클래스의 소스 코드 분석 라이브러리는 여기에서 볼 수 있습니다: http://www.cnblogs.com/hmking/archive/2011/09/30/2196504.html
구체적인 사용법 보기:
a 새 클래스 만들기
코드 복사
코드는 다음과 같습니다.
varCat=newClass({
initialize:function(name ){
this.name=name ;
}
})
varmyCat=newCat('Micia')
alert(myCat.name);//alerts'Micia' varCow=newClass({ 초기화:function(){ alert('moooo'); } });
b. Implementation of inheritance
varAnimal=newClass( {
initialize:function(age){
this.age=age;
}
});
varCat=newClass({
Extends:Animal,
initialize: function(name,age){
this.parent(age);//callsinitalizemethodofAnimalclass
this.name=name;
}
});
varmyCat=newCat('Micia', 20);
alert(myCat.name);//alerts'Micia'.
alert(myCat.age);//alerts20.
c. Implementation of extended class
varAnimal=newClass({
initialize:function(age ){
this.age=age;
}
});
varCat=newClass({
Implements:Animal,
setName:function(name){
this .name=name
}
});
varmyAnimal=newCat(20);
myAnimal.setName('Micia');
alert(myAnimal.name);//alerts' Micia'.
5. Understanding JavaScript: Syntax Nectar Look at usage examples first
a. Create a class
//Create class Person
varPerson=Class(object,{
Create:function( name,age){
this.name=name;
this.age=age;
},
SayHello:function(){
alert("Hello,I'm" this .name "," this.age "yearsold.");
}
});
varBillGates=New(Person,["BillGates",53]);
BillGates.SayHello() ;
b. Inherited class
//Employee inherits Person
varEmployee=Class(Person,{
Create:function(name,age,salary){
Person.Create.call(this,name,age);
//Call the constructor of the base class
this.salary=salary;
},
ShowMeTheMoney:function(){
alert(this.name "$" this.salary);
}
});
varSteveJobs=New(Employee,["SteveJobs",53,1234]);
SteveJobs.SayHello();
SteveJobs.ShowMeTheMoney();
The following is source code analysis: Obviously, there is an additional New method, and the creation of classes and instances of new classes are cleverly encapsulated. Forming a meaningful whole! Another difference is that all classes are based on literals, not functions. The code is very short, but the principles are rich and clever, so you can savor it carefully!
//Function to create a class, used to declare the class and Inheritance relationship
functionClass(aBaseClass,aClassDefine){
//Create a temporary function shell of the class
functionclass_(){
this.Type=aBaseClass;
//We give each class a convention A Type attribute, referencing its inherited class
for(varmemberinaClassDefine)
this[member]=aClassDefine[member];
//Copy all definitions of the class to the currently created class
};
class_.prototype=aBaseClass;
returnnewclass_();
};
//Function to create objects, used for object creation of any class
functionNew(aClass,aParams){
//Create a temporary function shell for the object
functionnew_(){
this.Type=aClass;
//We also assign a Type attribute to each object, based on which we can access the class to which the object belongs
if(aClass.Create)
aClass.Create.apply(this, aParams);
//We agree that the constructor of all classes is called Create, which is similar to DELPHI
};
new_.prototype=aClass;
returnnewnew_();
};
Due to the general writing, there may be many places that have not been parsed, and there may be inaccuracies. Please correct me.
After reading the above analysis, you can also write your own encapsulation class library according to the information. As for how to implement it, it depends on personal preference. But the basic ideas are the same prototype-based inheritance method and new circular copy method.
Original text from: Mu Yi http://www.cnblogs.com/pigtail/