An Introduction to Server Sent Events

Idea behind SSEs – A web app “subscribes” to a stream of updates generated by server and whenever a new event generates, a notification will be sent to client.

Traditional methods and their limitations –

  • Polling – The application continuously polls a server for data. Client makes a request and waits for the response data from server. If none is available, empty response will be sent. Extra polling will create greater HTTP overhead.
  • Long Polling –  Its a slight variation of polling. Here, if server does not have any data available, it will hold the request open until new data is available. Hence, this is also referred as “Hanging Get”.  When data gets available, server will respond, closes the connection and the process is repeated.  Downside of this implementation is that it requires hacks such as appending script tags to an “infinite” iframe. We can do better than hacks!!!

With SSEs, server will send new data only when the data is available. It opens a single unidirectional channel between server and client.

The main difference between SSEs and long polling is that SSEs are handled directly by browser and the user just simply listen for messages.

When one should choose WebSockets over Server-Sent Events?

WebSockets provide bi-directional, full duplex communication. Having two way communication is more useful for games, messaging apps and for cases where you need real time updated to be sent in both directions. However, in some scenarios data doesn’t need to be sent from both directions. You simply need updates from server. A few examples – friend’s status updates, news feeds etc.

SSEs are sent over traditional HTTP. That means they do not require a special protocol or server implementation to get working. WebSockets on the other hand, require full-duplex connections and new Web Socket servers to handle the protocol.

Lets start the implementation

  • Create an EventSource object and pass it the url where your SSE server is located.
if (!!window.EventSource) {
  var source = new EventSource("http://127.0.0.1:8080/");
} else {
  // Result to xhr polling
}

Here the SSE server is located at  http://127.0.0.1:8080/. 

  • Set up a handler for the message event.
source.addEventListener("message", function(e) {
 console.log(e.data);
 //displaying newly pushed data
 document.getElementById("log").innerHTML += event.data + "<br>";
}, false);
source.addEventListener("open", function(e) {
  // Connection was opened.
}, false);
source.addEventListener("error", function(e) { 
 if (e.readyState == EventSource.CLOSED) { 
    // Connection was closed. 
 } 
}, false);

When updates are available from server, onmessage handler fires and new data can be accessed by e.data. If the connection gets closed, the browser will automatically reconnect to the source after ~3 seconds. You can control this timeout via the server implementation code.

  • Event Stream format
    • Content-Type should be set to text/event-stream.
    • The response should contain a data:  line, followed by the message, followed by two “\n” characters to end the stream.
      data: My message\n\n
      //multi line data
      data: first line\n
      data: second line\n\n
    • You can associate an ID with the event.
      id: 12345\n
      data: GOOG\n
      data: 556\n\n

      Setting ID helps the browser in keeping track of the events fired so far, so if the connection to server dropped, the browser can determine the event to fire again with the help of HTTP header Last-Event-ID.

    • You can also specify the event name.
      event: userlogon\n
      data: {"username": "John123"}\n\n
      source.addEventListener("userlogon", function(e) {
        var data = JSON.parse(e.data);
        console.log('User login:' + data.username);
      }, false);

How to create simple SSE server in node.js

You can use sse npm module for creating sse server.

var SSE = require('sse'),
    http = require('http'),
    val = 0,
    msg;

var server = http.createServer(function(req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Access-Control-Allow-Origin': '*'
  });

  setInterval(function() {
    val++;
    msg = "id: msg1\ndata: test" + val + "\n\n";
    res.write(msg);
  }, 3000);
});

server.listen(8080, "127.0.0.1", function() {
  var sse = new SSE(server);
  sse.on("connection", function(client) {
    client.send("hi there");
  });
});

Screenshot of the running SSE in browser :

sse-implementation

Advertisements

What happen when you type URL in browser

These are the list of steps that get executed when you type url in browser:

  • If requested object is present in browser cache and is not expired, browser will directly display the content on the page.
  • DNS lookup for the IP address for the server  –                                               Lets say we want to connect to google.com, DNS(Domain Name System) service will come into picture and will resolve the domain name with a specific IP address.
  • Browser initiates a TCP connection with the server
  • Browser sends a HTTP Get request to the server –                                       Browser will prepare a HTTP Get call according to the specification of HTTP protocol and will trigger the request to the server.
  • Server sends the appropriate response to the browser –                           Web server(e.g. Apache) will handle the incoming request and will generate the response. This response is sent back to browser as per the HTTP guidelines.
  • Browser receives the response from the server
  • Browser displays the HTML response –                                                             The browser first renders the bare bone html structure, and then it sends multiple GET requests to fetch other hyper linked stuff e.g. images. Static files like images, javascript, css files are all cached by the browser so that in future it doesn’t have to fetch them again.

Comparison of ES6 new features with ES5

  1. Support for constants

In ES6 –
const PI = 3.141593

In ES5 –
Object.defineProperty(window, "PI", {
value: 3.141593,
enumerable: true,
writable: false,
configurable: false
})

2) Scoping
2.1) Block-Scoped Variables

In ES6 –
for (let i = 0; i < a.length; i++) {
let x = a[i]

}
for (let i = 0; i < b.length; i++) {
let y = b[i]

}

let callbacks = []
for (let i = 0; i <= 2; i++) {
callbacks[i] = function () { return i * 2 }
}
callbacks[0]() === 0
callbacks[1]() === 2
callbacks[2]() === 4

In ES5 –
var i, x, y;
for (i = 0; i < a.length; i++) {
x = a[i];

}
for (i = 0; i < b.length; i++)
y = b[i];

}

var callbacks = [];
for (var i = 0; i <= 2; i++) {
(function (i) {
callbacks[i] = function() { return i * 2; };
})(i);
}
callbacks[0]() === 0;
callbacks[1]() === 2;
callbacks[2]() === 4;

2.2) Block-Scoped Functions

In ES6-
{
function foo () { return 1 }
foo() === 1
{
function foo () { return 2 }
foo() === 2
}
foo() === 1
}

In ES5-
(function () {
var foo = function () { return 1; }
foo() === 1;
(function () {
var foo = function () { return 2; }
foo() === 2;
})();
foo() === 1;
})();

3) Arrow Functions
3.1) Expressive Bodies – More expressive closure syntax.

In ES6-
odds = evens.map(v => v + 1)
pairs = evens.map(v => ({ even: v, odd: v + 1 }))
nums = evens.map((v, i) => v + i)

In ES5-
odds = evens.map(function (v) { return v + 1; });
pairs = evens.map(function (v) { return { even: v, odd: v + 1 }; });
nums = evens.map(function (v, i) { return v + i; });

3.2) Statement Bodies – More expressive closure syntax.

In ES6-
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v)
})

In ES5-
nums.forEach(function (v) {
if (v % 5 === 0)
fives.push(v);
});

3.3) Lexical this – More intuitive handling of current object context.

In ES6-
this.nums.forEach((v) => {
if (v % 5 === 0)
this.fives.push(v)
})

In ES5-
// variant 1
var self = this;
this.nums.forEach(function (v) {
if (v % 5 === 0)
self.fives.push(v);
});

// variant 2 (since ECMAScript 5.1 only)
this.nums.forEach(function (v) {
if (v % 5 === 0)
this.fives.push(v);
}.bind(this));

4) Extended Parameter Handling
4.1) Default Parameter Values – Simple and intuitive default values for function parameters.

In ES6 –
function f (x, y = 7, z = 42) {
return x + y + z
}
f(1) === 50

In ES5 –
function f (x, y, z) {
if (y === undefined)
y = 7;
if (z === undefined)
z = 42;
return x + y + z;
};
f(1) === 50;

4.2) Rest Parameter – Aggregation of remaining arguments into single parameter of variadic functions.

In ES6 –
function f (x, y, ...a) {
return (x + y) * a.length
}
f(1, 2, "hello", true, 7) === 9

In ES5 –
function f (x, y) {
var a = Array.prototype.slice.call(arguments, 2);
return (x + y) * a.length;
};
f(1, 2, "hello", true, 7) === 9;

4.3) Spread Operator – Spreading of elements of an iterable collection (like an array or even a string) into both literal elements and individual function parameters.

In ES6 –
var params = [ "hello", true, 7 ]
var other = [ 1, 2, ...params ] // [ 1, 2, "hello", true, 7 ]

var str = “foo”
var chars = [ …str ] // [ “f”, “o”, “o” ]

In ES5 –
var params = [ "hello", true, 7 ];
var other = [ 1, 2 ].concat(params); // [ 1, 2, "hello", true, 7 ]

var str = “foo”;
var chars = str.split(“”); // [ “f”, “o”, “o” ]

5) Template Strings
5.1) String Interpolation – Intuitive expression interpolation for single-line and multi-line strings.

In ES6 –
var customer = { name: "Foo" }
var card = { amount: 7, product: "Bar", unitprice: 42 }
message = `Hello ${customer.name},
want to buy ${card.amount} ${card.product} for
a total of ${card.amount * card.unitprice} bucks?`

In ES5 –
var customer = { name: "Foo" };
var card = { amount: 7, product: "Bar", unitprice: 42 };
message = "Hello " + customer.name + ",\n" +
"want to buy " + card.amount + " " + card.product + " for\n" +
"a total of " + (card.amount * card.unitprice) + " bucks?";

6) Extended literals –
6.1) Binary & Octal Literal – Direct support for safe binary and octal literals.

In ES6 –
0b111110111 === 503
0o767 === 503

In ES5 –
parseInt("111110111", 2) === 503;
parseInt("767", 8) === 503;

7) Enhanced Object Properties –
7.1) Property Shorthand – Shorter syntax for common object property definition idiom.

In ES6 –
obj = { x, y }

In ES5 –
obj = { x: x, y: y };

7.2) Computed Property Names – Support for computed names in object property definitions.

In ES6 –
obj = {
foo: "bar",
[ "prop_" + foo() ]: 42
}

In ES5 –
obj = {
foo: "bar"
};
obj[ "prop_" + foo() ] = 42;

7.3) Method Properties – Support for method notation in object property definitions

In ES6 –
obj = {
foo (a, b) {

},
bar (x, y) {

}
}

In ES5 –
obj = {
foo: function (a, b) {

},
bar: function (x, y) {

}
};

8) Destructuring Assignment
8.1) Array Matching – Intuitive and flexible destructuring of Arrays into individual variables during assignment.

In ES6 –
var list = [ 1, 2, 3 ]
var [ a, , b ] = list
[ b, a ] = [ a, b ]

In ES5 –
var list = [ 1, 2, 3 ];
var a = list[0], b = list[2];
var tmp = a; a = b; b = tmp;

8.2) Object Matching, Shorthand Notation – Intuitive and flexible destructuring of Objects into individual variables during assignment.

In ES6 –
var { op, lhs, rhs } = getASTNode()

In ES5 –
var tmp = getASTNode();
var op = tmp.op;
var lhs = tmp.lhs;
var rhs = tmp.rhs;

8.3) Object Matching, Deep Matching – Intuitive and flexible destructuring of Objects into individual variables during assignment.

In ES6 –
var { op: a, lhs: { op: b }, rhs: c } = getASTNode()

In ES5 –
var tmp = getASTNode();
var a = tmp.op;
var b = tmp.lhs.op;
var c = tmp.rhs;

8.4) Parameter Context Matching – Intuitive and flexible destructuring of Arrays and Objects into individual parameters during function calls.

In ES6 –
function f ([ name, val ]) {
console.log(name, val)
}
function g ({ name: n, val: v }) {
console.log(n, v)
}
function h ({ name, val }) {
console.log(name, val)
}
f([ "bar", 42 ])
g({ name: "foo", val: 7 })
h({ name: "bar", val: 42 })

In ES5 –
function f (arg) {
var name = arg[0];
var val = arg[1];
console.log(name, val);
};
function g (arg) {
var n = arg.name;
var v = arg.val;
console.log(n, v);
};
function h (arg) {
var name = arg.name;
var val = arg.val;
console.log(name, val);
};
f([ "bar", 42 ]);
g({ name: "foo", val: 7 });
h({ name: "bar", val: 42 });

8.5) Fail-Soft Destructuring – Fail-soft destructuring, optionally with defaults.

In ES6 –
var list = [ 7, 42 ]
var [ a = 1, b = 2, c = 3, d ] = list
a === 7
b === 42
c === 3
d === undefined

In ES5 –
var list = [ 7, 42 ];
var a = typeof list[0] !== "undefined" ? list[0] : 1;
var b = typeof list[1] !== "undefined" ? list[1] : 2;
var c = typeof list[2] !== "undefined" ? list[2] : 3;
var d = typeof list[3] !== "undefined" ? list[3] : undefined;
a === 7;
b === 42;
c === 3;
d === undefined;

CSS Shapes

For a long time, we are being forced to create contents in a rectangular boxes because non-rectangular shapes can led to frustration.
CSS shapes allows us to wrap the content around custom paths such as circle, ellipse, polygon etc.

Example –

<img class=”element” src=”image.png” /> 
<p>Lorem ipsum…</p>  
<style>   
  .element{     
    shape-outside: url(image.png);     
    shape-image-threshold: 0.5;     
    float: left;   
  } 
</style>
  • shape-outside – tells the browser to extract a shape from the image and around which the content will wrap.
  • shape-image-threshold – defines the opacity of the image.
  • float –  Its the key value. Without this, shapes effect won’t be seen.

Element have float area opposite to its float value. Lets say for an example, if the coffee image has float value as left, its float area will be to the right of cup. Even if we manage to show spaces on both side of image, still the content will be visible to the right side(opposite side) of the image.

Creating Shapes Manually – 

Shapes can be created manually. These are the functions –

  • circle()
  • ellipse()
  • inset()
  • polygon()

circle() –

.element{       
  shape-outside: circle(50%);       
  width: 300px;      
  height: 300px;   
  float: left; 
}

Here the content will wrap outside the circular path. 50% specifies the radius of the circle and its amount to half of the element’s height and width.
       Formula used for this – sqrt(width^2 + height^2) / sqrt(2)

ellipse() –

.element{       
  shape-outside: ellipse(150px 300px at 50% 50%);       
  width: 300px;      
  height: 600px;
}

ellipse(rx ry at cx cy), where rx and ry are the radii for the ellipse on the X-axis and Y-axis, while cxand cy are the coordinates for the center of the ellipse. 

polygon() –

.element{       
  shape-outside: polygon(0 0, 0 300px, 300px 600px);      
  width: 300px;      
  height: 600px; 
}

polygon(x1 y1, x2 y2, …) where you specify pairs of x y coordinates for each vertex (point) of a polygon. The minimum number of pairs to specify a polygon is three, a triangle.
For responsive polygons, percentage values can be given for the co-ordinates.

Creating shapes from reference boxes –

If you don’t specify function to the shape outside property,browser allows to derive shape from the element’s reference box. The default reference box is margin-box.

Example –

.element{       
  border-radius: 50%;      
  shape-outside: border-box;   
  float: left; 
}

wrap around the contour created by the border-radius.

Shape Margin –

Wrapping text around image is sometimes more closely. For that you can use shape-margin property.

.element{      
  shape-outside: circle(40%);      
  shape-margin: 1em;   
  float: left; 
}

Animating Shapes –

Mixing CSS shapes with CSS features can be use animate shapes.
You can animate the radii and centers for circle() and ellipse() shapes as long as they’re defined in values that the browser can interpolate.

 .element{       
  shape-outside: circle(30%);      
  transition: shape-outside 1s;   
  float: left; 
}  
.element:hover{       
  shape-outside: circle(50%);
}

Wrapping content inside a shape –

shape-inside  property is used for wrapping text inside a shape. But because of high efforts and research required, this property has been deferred to CSS Shapes Level 2. But this can be achieved by a hack i.e. use two floated elements with shape-outside, positioned at opposite sides of a container. The compromise is that you have to use one or two empty elements which have no semantic meaning, but serve as the struts to create the illusion of a shape inside.

<div> 
  <div class="left-shape"></div> 
  <div class="right-shape"></div>  
Lorem ipsum... 
</div>
.left-shape{      
  shape-outside: polygon(0 0, ...);   
  float: left;       
  width: 50%;      
  height: 100%; 
}  
.right-shape{      
  shape-outside: polygon(50% 0, ...);   
  float: right;      
  width: 50%;      
  height: 100%;
}

The inspector in Google Chrome has built-in support for highlighting shapes. Hover over an element with a shape-outside property and it will light up to illustrate the shape.

Empowering JavaScript Objects

There are a lot more concepts which are present in JavaScript but are not used frequently. This posts looks beyond everyday usage of JavaScript’s objects.

getters and setters

Lets see an example –

/**
* @param {string} prefix
* @constructor
*/
function Product(prefix) {
/**
* @private
* @type {string}
*/
this.prefix_ = prefix;
/**
* @private
* @type {string}
*/
this.type_ = "";
}

/**
* @param {string} newType
*/
Product.prototype.setType = function (newType) {
this.type_ = newType;
};

/**
* @return {string}
*/
Product.prototype.type = function () {
return this.prefix_ + ": " + this.type_;
}

var product = new Product("fruit");
product.setType("apple");
console.log(product.type()); //logs fruit: apple

Using a getter this code can be simplified.

/**
* @param {string} prefix
* @constructor
*/
function Product(prefix) {
/**
* @private
* @type {number}
*/
this.prefix_ = prefix;
/**
* @private
* @type {string}
*/
this.type_ = "";
}

/**
* @param {string} newType
*/
Product.prototype = {
/**
* @return {string}
*/
get type () {
return this.prefix_ + ": " + this.type_;
},
/**
* @param {string}
*/
set type (newType) {
this.type_ = newType;
}
};

var product = new Product("fruit");
product.type = "apple";
console.log(product.type); //logs "fruit: apple"
console.log(product.type = "orange"); //logs "orange"
console.log(product.type); //logs "fruit: orange"

defineProperty

The get propertyname () syntax works on object literals and in the previous example an object literal is assigned to Product.prototype. This is OK, but using object literals like this makes it harder to chain prototypes to get inheritance. You can create getters and setters on a prototype without an object literal using defineProperty.

/**
* @param {string} prefix
* @constructor
*/
function Product(prefix) {
/**
* @private
* @type {number}
*/
this.prefix_ = prefix;
/**
* @private
* @type {string}
*/
this.type_ = "";
}

/**
* @param {string} newType
*/
Object.defineProperty(Product.prototype, "type", {
/**
* @return {string}
*/
get: function () {
return this.prefix_ + ": " + this.type_;
},
/**
* @param {string}
*/
set: function (newType) {
this.type_ = newType;
}
});

var product = new Product("fruit");
product.type = "apple";
console.log(product.type); //logs "fruit: apple"

There’s more to defineProperty than adding getters or setters. The third argument to defineProperty is called the descriptor and in addition to set and get it allows you to customize the property’s accessibility and set a value. You could use the descriptor argument to defineProperty to create something like a constant that can never be modified or removed.

obj = {
foo: "bar",
};

//A normal object property
console.log(obj.foo); //logs "bar"
obj.foo = "foobar";
console.log(obj.foo); //logs "foobar"
delete obj.foo;
console.log(obj.test); //logs undefined

Object.defineProperty(obj, "foo", {
value: "bar",
});

console.log(obj.foo); //logs "bar", we were able to modify foo
obj.foo = "foobar";
console.log(obj.foo); //logs "bar", write failed silently
delete obj.foo;
console.log(obj.foo); //logs bar, delete failed silently

The last 2 attempts to modify foo.bar in the example failed silently as the default behavior of defineProperty is to prevent further changes. You can use configurable and writable to change this behavior. If you are using strict mode the failures are not silent, they are JavaScript errors.

var obj = {};

Object.defineProperty(obj, "foo", {
value: "bar",
configurable: true,
writable: true,
});

console.log(obj.foo); //logs "bar"
obj.foo = "foobar";
console.log(obj.foo); //logs "foobar"
delete obj.foo;
console.log(obj.test); //logs undefined

The configureable key allows you to prevent the property from being deleted from the object. It also allows you to prevent the property from being modified in the future with another call todefineProperty later. The writable key enables you to write to the property and change its value. If configurable is false as is the default case, attempting to call defineProperty a second time will result in a JavaScript error, it does not fail silently.

var obj = {};
Object.defineProperty(obj, "foo", {
value: "bar",
});

Object.defineProperty(obj, "foo", {
value: "boobar",
});

// Uncaught TypeError: Cannot redefine property: foo

Also note that values defined by defineProperty are by default not iterated over in a for in loop.

var i, inventory;

inventory = {
"apples": 10,
"oranges": 13,
};

Object.defineProperty(inventory, "strawberries", {
value: 3,
});

for (i in inventory) {
console.log(i, inventory[i]);
}

Output-
apples 10
oranges 13

Use the enumerable key to allow this.
You can use isPropertyEnumerable to test whether a property will appear in a for in loop. propertyIsEnumerable will also return false for properties defined further up an object’s prototype chain or for properties that aren’t otherwise defined on the object.

Couple more points about using defineProperty:

  • It is an error to combine the accessors set and get with writable set to true or to combine them with a value.
  • Defining a property as a number simply converts number to string just as it would in any other circumstance.
  • You can also use defineProperty to set value to be a function.

defineProperties

It allows you to define multiple properties in a single go.

var foo = {}

Object.defineProperties(foo, {
bar: {
value: "foo",
writable: true,
},
foo: {
value: function() {
console.log(this.bar);
}
},
});

foo.bar = "foobar";
foo.foo(); //logs "foobar"

Object.create

Object.create is an alternative to new that lets you create an object with a given prototype. This function has two arguments, the first is the prototype you want use for the newly created object, the second argument is a property descriptor and it takes the same form as you would give to Object.defineProperties.

var prototypeDef = {
protoBar: "protoBar",
protoLog: function () {
console.log(this.protoBar);
}
};
var propertiesDef = {
instanceBar: {
value: "instanceBar"
},
instanceLog: {
value: function () {
console.log(this.instanceBar);
}
}
}

var foo = Object.create(prototypeDef, propertiesDef);
foo.protoLog(); //logs "protoBar"
foo.instanceLog(); //logs "instanceBar"

Properties created in the properties descriptor argument to Object.create overwrite the values in the prototype argument.

Setting a non-primitive type like an Array or Object as a defined properties value in Object.create is probably a mistake since you will create a single instance shared by all created objects.

var prototypeDef = {
protoArray: [ ],
};
var propertiesDef = {
propertyArray: {
value: [ ],
}
}

var foo = Object.create(prototypeDef, propertiesDef);
var bar = Object.create(prototypeDef, propertiesDef);

foo.protoArray.push("foobar");
console.log(bar.protoArray); //logs ["foobar"]
foo.propertyArray.push("foobar");
console.log(bar.propertyArray); //also logs ["foobar"]

You could fix this problem by initialize the value of propertyArray with null and then add the array when you needed, or you could do something fancy like this using a getter.

var prototypeDef = {
protoArray: [ ],
};
var propertiesDef = {
propertyArrayValue_: {
value: null,
writable: true
},
propertyArray: {
get: function () {
if (!this.propertyArrayValue_) {
this.propertyArrayValue_ = [ ];
}
return this.propertyArrayValue_;
}
}
}

var foo = Object.create(prototypeDef, propertiesDef);
var bar = Object.create(prototypeDef, propertiesDef);

foo.protoArray.push("foobar");
console.log(bar.protoArray); //logs ["foobar"]
foo.propertyArray.push("foobar");
console.log(bar.propertyArray); //also logs ["foobar"]

Note

  • The expressions provided to any value in an Object.create property descriptor is evaluated when the property descriptor object is defined.
  • Never depend on a fixed order for when multiple properties are evaluated in a single call. If you really wanted to initialize one property before the other perhaps just useObject.defineProperty in that instance.
  • Since using Object.create does not involve a constructor function you lose the ability to use instanceOf to test Object identity. Instead use isPrototypeOf which is checked against.
  • The prototype object. isPrototypeOf will walk down the prototype chain and return true if any prototype matches the prototype object tested against.

sealing objects, freezing them and preventing extensibility

It is possible to restrict changes to an entire object in addition to restricting individual properties of an object via defineProperty.  Object.preventExtensionsObject.seal and Object.freeze each in turn add increasingly stricter restrictions on an object. In strict mode violating restrictions placed by these methods will result in JavaScript errors, otherwise they fail silently.

Object.preventExtensions will prevent new properties from being added to an object. It will not prevent changes to existing writable properties, and it will not prevent deletion of configurable   properties.Object.preventExtensions will also not remove the ability to callObject.defineProperty to modify existing properties.

var obj = {
    foo: "foo",
};
obj.bar = "bar";
console.log(obj); // logs Object {foo: "foo", bar: "bar"}
Object.preventExtensions(obj);
delete obj.bar;
console.log(obj); // logs Object {foo: "foo"}
obj.bar = "bar";
console.log(obj); // still logs Object {foo: "foo"}
obj.foo = "foobar"

console.log(obj); // logs {foo: "foobar"} can still change values

Object.seal goes further than Object. preventExtensions. In addition to preventing new properties from being added to an object, this function also prevents further configurability and removes the ability to delete properties. Once an object has been sealed, you can no longer modify existing properties with defineProperty.

"use strict";
var obj = {};
Object.defineProperty(obj, "foo", {
    value: "foo"
});
Object.seal(obj);
//Uncaught TypeError: Cannot redefine property: foo
Object.defineProperty(obj, "foo", {
    value: "bar"
});

But you can still change the values of properties.Finally, Object.freeze makes an object entirely immutable. You cannot add, remove, or change the values of properties on frozen objects. You can also no longer use Object.defineProperty on the object to change the values of existing properties.
"use strict";
var obj = {
    foo: "foo1"
};
Object.freeze(obj);
//All of the following will fail, and result in errors in strict mode
obj.foo = "foo2"; //cannot change values
obj.bar = "bar"; //cannot add a property
delete obj.bar; //cannot delete a property
//cannot call defineProperty on a frozen object
Object.defineProperty(obj, "foo", {
    value: "foo2"

});

valueOf and toString

You can use valueOf and toString to customize how an object you have defined behaves in contexts where JavaScripts expects a primitive value.

getOwnPropertyNames and keys

You can use object.getOwnPropertyNames to get all the properties defined on an object. There actually is an Object.keys method as well. The difference between Object.keys and Object.getOwnPropertyNames is that the latter also iterates over property names that are not enumberable, that is Object.getOwnPropertyNames will also return property names that are not iterated over in a for in loop.

var obj = {
    foo: "foo",
};
Object.defineProperty(obj, "bar", {
    value: "bar"
});
console.log(Object.getOwnPropertyNames(obj)); //logs ["foo", "bar"]

console.log(Object.keys(obj));  //logs ["foo"]


Symbol

Symbol is a special new primitive type defined in ECMAScript 6.
Symbols can be used as way to create and reference properties on objects.

var obj = {};

var foo = Symbol("foo");
obj[foo] = "foobar";

console.log(obj[foo]); //logs "foobar"

Symbols are unique and immutable.

//console logs false, symbols are unique:
console.log(Symbol("foo") === Symbol("foo"));

You can also use symbols with Object.defineProperty:

var obj = {};
var foo = Symbol("foo");
Object.defineProperty(obj, foo, {
    value: "foobar",
});

console.log(obj[foo]); //logs "foobar"

Properties added to objects with symbols will not be iterated over in a forin loop, but calling hasOwnProperty will work fine.

Symbols will not appear in the returned array from a call to Object.getOwnPropertyNames but there is a Object.getOwnPropertyNames.

Proxy

Proxies are exciting to me because it allows for the creation of catch all properties.

var obj = {

    foo: "foo",
};
var handler = {
    get: function (target, name) {
        if (target.hasOwnProperty(name)) {
            return target[name];
        }
        return "foobar";
    },
};
var p = new Proxy(obj, handler);
console.log(p.foo); //logs "foo"
console.log(p.bar);  //logs "foobar"
console.log(p.asdf); //logs "foobar"


In this example we are proxying object obj. We define a handler object that handles interaction with the proxy object. The get method  gets the target object as an argument as well as the name of the property that was accessed. We can use this information to return whatever we want, but in this case I return the object’s actual value if it has one and if not I return “foobar”.
Beyond just get there are other handlers you can add including set, has and more.

How to write Semantic HTML Table

What is a table – 
A table is an arrangement of information in a rectangular grid. It is used to express relationship between pieces of information. 

Structure of HTML table – 

  • HTML <table> tag is used as a wrapper for the table.
  • Each piece of information is described in a cell, represented as <td> HTML tag.
  • Cells are grouped to form a row ,represented as <tr> HTML tag.

Example – 

 <table>
    <tr>

       <td>Room Name</td>
       <td>Occupancy</td>
       <td>Price Per Room</td>
       <td>No. Rooms</td>
   </tr>
   <tr>
       <td>Basic Family Room</td>
       <td>4</td>
       <td>&euro;98.99</td>
       <td>5</td>
   </tr>
   <tr>
       <td>Deluxe 2 Bed</td>
       <td>2</td>
       <td>&euro;109.99</td>
       <td>5</td>
   </tr>

   <tr>
      <td colspan="4">
          <button type="submit">Book Now</button>
      </td>
   </tr>

</table>

Problems with Tables – 

  • Tough for search engine to understand.
  • Lack of semantic Info.
  • Hard to visualize code.
  • Prevents incremental (progressive) rendering and thereby takes longer to display.

The table can be made more semantic by including below tags – 
Solution – 

1) Adding a caption to the table – 
 
 <table>
    <caption>Rooms Detail</caption>
    <tr>

         <td>Room Name</td>
         <td>Occupancy</td>
         <td>Price per Room</td>
         <td>No. Rooms</td>
   </tr>
   <tr>
       <td>Basic Family Room</td>
       <td>4</td>
       <td>&euro;98.99</td>
       <td>5</td>
   </tr>
   <tr>
       <td>Deluxe 2 Bed</td>
       <td>2</td>
       <td>&euro;109.99</td>
       <td>5</td>
   </tr>

   <tr>
      <td colspan="4">
          <button type="submit">Book Now</button>
      </td>
   </tr>

</table>

  • The CAPTIONS tag is optional, but it explains the content of the table and is another excellent keyword placeholder for search engine optimization (SEO).

The caption can be treated as a title or more of a visible description of table.

2) Adding <THEAD>, <TBODY> and <TFOOT> to the table

  • Most tables contain first row that is usually the header for all of the rows following below them. The THEAD tag allows you to define that as an area. The cells inside THEAD tag is represented in <TH> tag.
  • In the same way, the TBODY tag lets you define body of the tables. 
  • TFOOT describes the footer of the table. This tag can be use to define the area at the bottom of the table that will provide information about the table or provide the action which can be performed on the table.

Each of these can have a CLASS or an ID selector making this a powerful way to identify your tables for CSS.

This makes the code look like this:

  1. Semantically more meaningful
  2. Easier to style with CSS separately from the rest of the table content

<table>
    <caption>Rooms Detail</caption>
    <thead>
      <tr>

         <th>Room Name</th>
         <th>Occupancy</th>
         <th>Price per Room</th>
         <th>No. Rooms</th>
     </tr>
   </thead>
   <tbody>
     <tr>
       <td>Basic Family Room</td>
       <td>4</td>
       <td>&euro;98.99</td>
       <td>5</td>
     </tr>
     <tr>
       <td>Deluxe 2 Bed</td>
       <td>2</td>
       <td>&euro;109.99</td>
       <td>5</td>
     </tr>
  </tbody>
  <tfoot>

    <tr>
      <td colspan="4">
         <button type="submit">Book Now</button>
      </td>
    </tr>
  </tfoot>

</table>

The Important Cruxes to shape your career

One may consider the following points in order to have a significant impact on career –

  • Be a problem-solver – Whatever the problems come across your way, always have an attitude of solving it.  Doing so not only will improve the effectiveness of your work, but will do wonders.
  • Do not allow fear of change to limit your career choices – Never let any fear or uncertainty for new responsibilities  from getting you to grow. It sometimes give you an opportunity to learn something new. Learn to recognize that some paths you encounter are detours and not right for you, while others are opportunities to be seized upon. Be mindful of these opportunities, be open to change, and be willing to challenge yourself.
  • Don’t be afraid to fail when trying something new – Look for opportunities to grow your skills and to focus on things that you do not do well. Focusing on what you do best is always tempting. It allows you to build on your strength as you get some experience under your belt. But after a while, though, it will limit you. Get out of your comfort zone and be willing to fail.  If you are unwilling to fail, then you will always take the safe path and not push yourself to learn new skills and accept new challenges.
  • Surround yourself with good people from whom you can learn from – From the company you join to the clients you work with, surround yourself with good people. If you work with good people, then overcoming challenges will be much easier.
  • Don’t accept a bad situation, either with colleagues or clients, simply because you think you have no other choice.