function countMyself() {// Check to see if the counter has been initializedif ( typeof countMyself.counter == 'undefined' ) {// It has not... perform the initializationcountMyself.counter = 0;}
// Do something stupid to indicate the valuealert(++countMyself.counter);}
var uniqueID = (function() {var id = 0; // This is the private persistent value// The outer function returns a nested function that has access// to the persistent value. It is this nested function we're storing// in the variable uniqueID above.return function() { return id++; }; // Return and increment})(); // Invoke the outer function after defining it.
function MyClass () { // constructor functionvar privateVariable = "foo"; // Private variable
this.publicVariable = "bar"; // Public variable
this.privilegedMethod = function () { // Public Methodalert(privateVariable);};}
// Instance method will be available to all instances but only load once in memoryMyClass.prototype.publicMethod = function () {alert(this.publicVariable);};
// Static variable shared by all instancesMyClass.staticProperty = "baz";
var myInstance = new MyClass();
class MyClass {// class constructor, equivalent to// the function body of a constructorconstructor() {const privateVariable = 'private value'; // Private variable at the constructor scopethis.publicVariable = 'public value'; // Public property
this.privilegedMethod = function() {// Public Method with access to the constructor scope variablesconsole.log(privateVariable);};}
// Prototype methods:publicMethod() {console.log(this.publicVariable);}
// Static properties shared by all instancesstatic staticProperty = 'static value';
static staticMethod() {console.log(this.staticProperty);}}
// We can add properties to the class prototypeMyClass.prototype.additionalMethod = function() {console.log(this.publicVariable);};
var myInstance = new MyClass();myInstance.publicMethod(); // "public value"myInstance.additionalMethod(); // "public value"myInstance.privilegedMethod(); // "private value"MyClass.staticMethod(); // "static value"
function Person(){if(Person.count == undefined){Person.count = 1;}else{Person.count ++;}console.log(Person.count);}
var p1 = new Person();var p2 = new Person();var p3 = new Person();
A convenient way to use classes and compile them into JavaScript is TypeScript.Here is a playground where you can find some examples showing you how it works.Even if you're not using TypeScript at the moment, you can have a look because you can compare TypeScript with the JavaScript result on a side-by-side view. Most examples are simple, but there is also a Raytracer example which you can try out instantly.I recommend especially looking into the "Using Classes", "Using Inheritance" and "Using Generics" examples by selecting them in the combobox - these are nice templates you can instantly use in JavaScript. Typescript is used with Angular.
To achieve encapsulation of local variables, functions etc in JavaScript, I suggest to use a pattern like the following (JQuery uses the same technique):
<html><head></head><body><script>'use strict';// module pattern (self invoked function)const myModule = (function(context) {// to allow replacement of the function, use 'var' otherwise keep 'const'
// put variables and function with local module scope here:var print = function(str) {if (str !== undefined) context.document.write(str);context.document.write("<br/><br/>");return;}// ... more variables ...
// main methodvar _main = function(title) {
if (title !== undefined) print(title);print("<b>last modified: </b>" + context.document.lastModified + "<br/>");// ... more code ...}
// public methodsreturn {Main: _main// ... more public methods, properties ...};
})(this);
// use modulemyModule.Main("<b>Module demo</b>");</script></body></html>
var Test = function() {// "super private" variable, accessible only here in constructor. There are no real private variables//if as 'private' we intend variables accessible only by the class that defines the member and NOT by child classesvar test_var = "super private";
//the only way to access the "super private" test_var is from herethis.privileged = function(){console.log(test_var);}();
Test.test_var = 'protected';//protected variable: accessible only form inherited methods (prototype) AND child/inherited classes
this.init();};//end constructor
Test.test_var = "static";//static variable: accessible everywhere (I mean, even out of prototype, see domready below)
Test.prototype = {
init:function(){console.log('in',Test.test_var);}
};//end prototype/class
//for example:$(document).ready(function() {
console.log('out',Test.test_var);
var Jake = function(){}
Jake.prototype = new Test();
Jake.prototype.test = function(){console.log('jake', Test.test_var);}
var jake = new Jake();
jake.test();//output: "protected"
});//end domready
好吧,另一种方法来看看这些事情中的最佳实践,就是看看coffeescript是如何翻译这些概念的。
#this is coffeescriptclass Test#static@prop = "static"
#instanceconstructor:(prop) ->@prop = propconsole.log(@prop)
t = new Test('inst_prop');
console.log(Test.prop);
//this is how the above is translated in plain js by the CS compilerTest = (function() {Test.prop = "static";
function Test(prop) {this.prop = prop;console.log(this.prop);}
return Test;
})();
t = new Test('inst_prop');
console.log(Test.prop);
var ajaxAction = (function (jqXHR) {return function (sender, args) {if (!jqXHR || jqXHR.readyState == 0 || jqXHR.readyState == 4) {jqXHR = $.ajax({url: args.url,type: 'POST',contentType: 'application/json',data: JSON.stringify($(sender).closest('form').serialize()),success: function (data) {// Do something here with the data.}});}};})(null);
var p = function Person() {this.x = 10;this.y = 20;}p.prototype.counter = 0;var person1 = new p();person1.prototype = p.prototype;console.log(person1.counter);person1.prototype.counter++;var person2 = new p();person2.prototype = p.prototype;console.log(person2.counter);console.log(person1.counter);
function Increment() {var num = 0; // Here num is a private static variablereturn function () {return ++num;}}
var inc = new Increment();console.log(inc());//Prints 1console.log(inc());//Prints 2console.log(inc());//Prints 3
class Foo {
static bar() {return 'I am static.'}
}
//`bar` is a property of the classFoo.bar() // returns 'I am static.'
//`bar` is not a property of instances of the classvar foo = new Foo()foo.bar() //-> throws TypeError
ES6类不会为静态引入任何新的语义学。你可以在ES5中这样做:
//constructorvar Foo = function() {}
Foo.bar = function() {return 'I am static.'}
Foo.bar() // returns 'I am static.'
var foo = new Foo()foo.bar() // throws TypeError
function MyObject() {};MyObject.prototype.staticAttribute = "some value";
并从这个构造函数实例化的每个对象访问它,就像这样…
var childObject1 = new MyObject(); // Instantiate a child objectvar childObject2 = new MyObject(); // Instantiate another child objectconsole.log(childObject.staticAttribute); // Access the static Attribute from child 1console.log(childObject.staticAttribute); // Access the static Attribute from child 2
cgf.first = true;$.on('click', '.my-button', function(){// Don't allow the user to press the submit twice.if (cgf.first){// first time behavior. such as submit}cgf.first = false;}
var Person = function(name) {this.name = name;// first time Person.count is undefined, so it is initialized with 1// next time the function is called, the value of count is incremented by 1Person.count = Person.count ? Person.count + 1 : 1;}
var p1 = new Person('User p1');console.log(p1.constructor.count); // prints 1var p2 = new Person('User p2');console.log(p2.constructor.count); // prints 2
您可以使用Person函数或任何实例为静态变量赋值:
// set static variable using instance of Personp1.constructor.count = 10; // this change is seen in all the instances of Personconsole.log(p2.constructor.count); // prints 10
// set static variable using PersonPerson.count = 20;console.log(p1.constructor.count); // prints 20
function Animal() {if (isNaN(this.totalAnimalCount)) {this.totalAnimalCount = 0;}this.totalAnimalCount++;};Object.defineProperty(Animal.prototype, 'totalAnimalCount', {get: function() {return Animal['totalAnimalCount'];},set: function(val) {Animal['totalAnimalCount'] = val;}});var cat = new Animal();console.log(cat.totalAnimalCount); //Will produce 1var dog = new Animal();console.log(cat.totalAnimalCount); //Will produce 2 and so on.
class MyClass {constructor(val) {this.instanceVar = val;MyClass.staticVar = 10;}}
var class1 = new MyClass(1);console.log(class1.instanceVar); // 1console.log(class1.constructor.staticVar); // 10
// New instance of MyClass with another valuevar class2 = new MyClass(3);console.log(class1.instanceVar); // 1console.log(class2.instanceVar); // 3
var functionClass = function ( ) {var currentClass = Shape;_inherits(currentClass, superClass);function functionClass() { superClass.call(this); // Linking with SuperClass Constructor.// Instance Variables list.this.id = id; return this;}}(SuperClass)
Closures - closure's copies are function with preserved data.
Each closure's copies are created to a function with their own free values or references, Whenever you use function inside another function, a closure is used.
A closure in JavaScript is like maintaining a copy of all the local variables of its parent function by the innerFunctions.
function closureFun( args ) {// Local variable that ends up within closurevar num = args;num++;return function() { console.log(num); }}var closure1 = closureFun( 5 );var closure2 = closureFun( 777 );closure1(); // 5closure2(); // 777closure2(); // 778closure1(); // 6
The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.
Created some methods by using ``, So that every once can understand the function classes easily.
'use strict';var Shape = function ( superClass ) {var currentClass = Shape;_inherits(currentClass, superClass); // Prototype Chain - Extends
function Shape(id) { superClass.call(this); // Linking with SuperClass Constructor.// Instance Variables list.this.id = id; return this;}var staticVariablesJOSN = { "parent_S_V" : 777 };staticVariable( currentClass, staticVariablesJOSN );
// Setters, Getters, instanceMethods. [{}, {}];var instanceFunctions = [{key: 'uniqueID',get: function get() { return this.id; },set: function set(changeVal) { this.id = changeVal; }}];instanceMethods( currentClass, instanceFunctions );
return currentClass;}(Object);
var Rectangle = function ( superClass ) {var currentClass = Rectangle;
_inherits(currentClass, superClass); // Prototype Chain - Extends
function Rectangle(id, width, height) { superClass.call(this, id); // Linking with SuperClass Constructor.
this.width = width;this.height = height; return this;}
var staticVariablesJOSN = { "_staticVar" : 77777 };staticVariable( currentClass, staticVariablesJOSN );
var staticFunctions = [{key: 'println',value: function println() { console.log('Static Method'); }}];staticMethods(currentClass, staticFunctions);
var instanceFunctions = [{key: 'setStaticVar',value: function setStaticVar(staticVal) {currentClass.parent_S_V = staticVal;console.log('SET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);}}, {key: 'getStaticVar',value: function getStaticVar() {console.log('GET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);return currentClass.parent_S_V;}}, {key: 'area',get: function get() {console.log('Area : ', this.width * this.height);return this.width * this.height;}}, {key: 'globalValue',get: function get() {console.log('GET ID : ', currentClass._staticVar);return currentClass._staticVar;},set: function set(value) {currentClass._staticVar = value;console.log('SET ID : ', currentClass._staticVar);}}];instanceMethods( currentClass, instanceFunctions );
return currentClass;}(Shape);
// ===== ES5 Class Conversion Supported Functions =====function defineProperties(target, props) {console.log(target, ' : ', props);for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}function staticMethods( currentClass, staticProps ) {defineProperties(currentClass, staticProps);};function instanceMethods( currentClass, protoProps ) {defineProperties(currentClass.prototype, protoProps);};function staticVariable( currentClass, staticVariales ) {// Get Key Set and get its corresponding value.// currentClass.key = value;for( var prop in staticVariales ) {console.log('Keys : Values');if( staticVariales.hasOwnProperty( prop ) ) {console.log(prop, ' : ', staticVariales[ prop ] );currentClass[ prop ] = staticVariales[ prop ];}}};function _inherits(subClass, superClass) {console.log( subClass, ' : extends : ', superClass );if (typeof superClass !== "function" && superClass !== null) {throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);}subClass.prototype = Object.create(superClass && superClass.prototype,{ constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });if (superClass)Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;}
下面的代码片段是测试关于每个实例都有自己的实例成员副本和公共静态成员。
var objTest = new Rectangle('Yash_777', 8, 7);console.dir(objTest);
var obj1 = new Rectangle('R_1', 50, 20);Rectangle.println(); // Static Methodconsole.log( obj1 ); // Rectangle {id: "R_1", width: 50, height: 20}obj1.area; // Area : 1000obj1.globalValue; // GET ID : 77777obj1.globalValue = 88; // SET ID : 88obj1.globalValue; // GET ID : 88
var obj2 = new Rectangle('R_2', 5, 70);console.log( obj2 ); // Rectangle {id: "R_2", width: 5, height: 70}obj2.area; // Area : 350obj2.globalValue; // GET ID : 88obj2.globalValue = 999; // SET ID : 999obj2.globalValue; // GET ID : 999
console.log('Static Variable Actions.');obj1.globalValue; // GET ID : 999
console.log('Parent Class Static variables');obj1.getStaticVar(); // GET Instance Method Parent Class Static Value : 777obj1.setStaticVar(7); // SET Instance Method Parent Class Static Value : 7obj1.getStaticVar(); // GET Instance Method Parent Class Static Value : 7
class MyClass {constructor() {}static staticMethod() {console.log('Static Method');}}MyClass.staticVar = 777;
var myInstance = new MyClass();// calling from instancemyInstance.constructor.staticMethod();console.log('From Inside Class : ',myInstance.constructor.staticVar);
// calling from classMyClass.staticMethod();console.log('Class : ', MyClass.staticVar);
class Dog {
static bark () {console.log('woof');}// classes are function objects under the hood// bark method is located on the Dog function object
makeSound () { console.log('bark'); }// makeSound is located on the Dog.prototype object
}
// to create static variables just create a property on the prototype of the classDog.prototype.breed = 'Pitbull';// So to define a static property we don't need the `static` keyword.
const fluffy = new Dog();const vicky = new Dog();console.log(fluffy.breed, vicky.breed);
// changing the static variable changes it on all the objectsDog.prototype.breed = 'Terrier';console.log(fluffy.breed, vicky.breed);
class ACTGeneratedPages {constructor(table_data, html_table_id) {this.flags = {};//static flags for any processes
//any your code here
}
call_popup(post_id) {
let _this = this;document.getElementById('act-popup-template').style.display = 'block';
if (!this.flags.popup_save_inited) {//second time listener will not be attacheddocument.querySelector('.act-modal-save').addEventListener('click', function (e) {//saving data code herereturn false;});}
this.flags.popup_save_inited = true;//set flag here}
}
function IHaveBeenCalled() {console.log("YOU SHOULD ONLY SEE THIS ONCE");return "Hello World: "}function testableFunction(...args) {testableFunction=inner //reassign the functionconst prepend=IHaveBeenCalled()return inner(...args) //pass all arguments the 1st timefunction inner(num) {console.log(prepend + num);}}testableFunction(2) // Hello World: 2testableFunction(5) // Hello World: 5
这使用...args,速度较慢,有没有办法第一次使用父函数的范围而不是传递所有参数?
我的用例:
function copyToClipboard(...args) {copyToClipboard = inner //reassign the functionconst child_process = require('child_process')return inner(...args) //pass all arguments the 1st timefunction inner(content_for_the_clipboard) {child_process.spawn('clip').stdin.end(content_for_the_clipboard)}}
function copyToClipboard(...args) {copyToClipboard = inner //reassign the functioncopyToClipboard.child_process = require('child_process')return inner(...args) //pass all arguments the 1st timefunction inner(content_for_the_clipboard) {copyToClipboard.child_process.spawn('clip').stdin.end(content_for_the_clipboard)}}