beforeEach(inject(function(_ModalService_){
close = ModalService.close;
}))
var app = angular.module('myApp',[]);
var app = angular.module('myApp');
angular.module('app',[
'app.avengers',
'app.dashboard',
'app.widgets',
'app.layout'
]);
angular.module('app',[
//Angular Modules
'ngRoute',
//Custome Modules
'common',
// 3rd Party Modules
'ui.bootstrap',
'breeze.angular'
]);
angular
.module('app.avengers')
.controller('Avenger',Avenger);
// "Classic" $scope syntax
function Avenger($scope){
$scope.name = 'Captain America';
$scope.prop = 'shield';
}
// "Controller As" syntax
function Avenger(){
var vm = this;
vm.name = 'Captain America';
vm.prop = 'shield';
}
6. Clean Codeangular
.module('app.dashboard')
.controller('Dashboard',Dashboard);
function Dashboard(common, dataservice){
// when minified, the common and dataservice may become a and b, which won't be found
}
angular
.module('app.dashboard')
.controller('Dashboard',['common','dataservice',Dashboard]);
function Dashboard(common, dataservice){
}
angular
.module('app.dashboard')
.controller('Dashboard',Dashboard);
Dashboard.$inject = ['$q','dataservice','logger'];
function Dashboard($q, dataservice, logger){
}
searchBtnIsEnabled: {value: function(){
var isEnabled;
this.searchBtn.isEnabled().then(function(result){
isEnabled = result;
console.log("the isEnabled is: "+isEnabled);
});
console.log(isEnabled);
}}
searchBtnIsEnabled: {value: function(callback){
this.searchBtn.isEnabled().then(function(result){
callback(result);
})
}}
this.searchBtnIsEnabled(function(enable){
console.log("The enable is: "+enable);
})
function sloppyFunc() {
console.log(this === window); // true
}
sloppyFunc();
function strictFunc() {
'use strict';
console.log(this === undefined); // true
}
strictFunc();
function func(arg1, arg2) {
console.log(this); // a
console.log(arg1); // b
console.log(arg2); // c
}
func.call('a', 'b', 'c'); // (this, arg1, arg2)
func.apply('a', ['b', 'c']); // (this, arrayWithArgs)
var savedThis;
function Constr() {
savedThis = this;
}
var inst = new Constr();
console.log(savedThis === inst); // true
Implemented in JavaScript, the new operator looks roughly as follows (a more accurate implementation is slightly more complex): function newOperator(Constr, arrayWithArgs) {
var thisValue = Object.create(Constr.prototype);
Constr.apply(thisValue, arrayWithArgs);
return thisValue;
}
var obj = {
method: function () {
console.log(this === obj); // true
}
}
obj.method();
<script>
console.log(this === window); // true
</script>
In Node.js, you normally execute code in modules. Therefore, the top-level scope is a special module scope: // `global` (not `window`) refers to global object:
console.log(Math === global.Math); // true
// `this` doesn’t refer to the global object:
console.log(this !== global); // true
// `this` refers to a module’s exports:
console.log(this === module.exports); // true
> (0,eval)('this === window')
true
Otherwise, if eval() is called directly, this remains the same as in the surroundings ofeval(). For example: // Real functions
function sloppyFunc() {
console.log(eval('this') === window); // true
}
sloppyFunc();
function strictFunc() {
'use strict';
console.log(eval('this') === undefined); // true
}
strictFunc();
// Constructors
var savedThis;
function Constr() {
savedThis = eval('this');
}
var inst = new Constr();
console.log(savedThis === inst); // true
// Methods
var obj = {
method: function () {
console.log(eval('this') === obj); // true
}
}
obj.method();
function Point(x, y) {
this.x = x;
this.y = y;
}
var p = Point(7, 5); // we forgot new!
console.log(p === undefined); // true
// Global variables have been created:
console.log(x); // 7
console.log(y); // 5
Thankfully, you get a warning in strict mode (this === undefined): function Point(x, y) {
'use strict';
this.x = x;
this.y = y;
}
var p = Point(7, 5);
// TypeError: Cannot set property 'x' of undefined
/** Similar to setTimeout() and setImmediate() */
function callIt(func) {
func();
}
If you call a sloppy-mode method as a function, this refers to the global object and global variables will be created: var counter = {
count: 0,
// Sloppy-mode method
inc: function () {
this.count++;
}
}
callIt(counter.inc);
// Didn’t work:
console.log(counter.count); // 0
// Instead, a global variable has been created
// (NaN is result of applying ++ to undefined):
console.log(count); // NaN
If you call a strict-mode method as a function, this is undefined. Things don’t work, either. But at least you get a warning: var counter = {
count: 0,
// Strict-mode method
inc: function () {
'use strict';
this.count++;
}
}
callIt(counter.inc);
// TypeError: Cannot read property 'count' of undefined
console.log(counter.count);
The fix is to use bind(): var counter = {
count: 0,
inc: function () {
this.count++;
}
}
callIt(counter.inc.bind(counter));
// It worked!
console.log(counter.count); // 1
bind() created a new function that always receives a this whose value is counter. var obj = {
name: 'Jane',
friends: [ 'Tarzan', 'Cheeta' ],
loop: function () {
'use strict';
this.friends.forEach(
function (friend) {
console.log(this.name+' knows '+friend);
}
);
}
};
obj.loop();
// TypeError: Cannot read property 'name' of undefined
In the previous example, this.name fails, because the function’s this is undefined, it is not the same as the this of the method loop(). There are three ways to fix … this.Fix 1: that = this. Assign this to a variable that isn’t shadowed (another popular name is self) and use that one. loop: function () {
'use strict';
var that = this;
this.friends.forEach(function (friend) {
console.log(that.name+' knows '+friend);
});
}
Fix 2: bind(). Use bind() to create a function whose this always has the correct value (the method’s this in the following example). loop: function () {
'use strict';
this.friends.forEach(function (friend) {
console.log(this.name+' knows '+friend);
}.bind(this));
}
Fix 3: forEach’s second parameter. This method has a second parameter whose value is passed to the callback as this. loop: function () {
'use strict';
this.friends.forEach(function (friend) {
console.log(this.name+' knows '+friend);
}, this);
}
loop: function () {
'use strict';
// The parameter of forEach() is an arrow function
this.friends.forEach(friend => {
// `this` is loop’s `this`
console.log(this.name+' knows '+friend);
});
}
I don’t like APIs that use this as an additional parameter of real functions: beforeEach(function () {
this.addMatchers({
toBeInRange: function (start, end) {
...
}
});
});
Turning such an implicit parameter into an explicit one makes things more obvious and is compatible with arrow functions.beforeEach(api => { api.addMatchers({ toBeInRange(start, end) { ... } }); });
robots.txt to tell the crawler explicitly what to search for..cn or .com.cn. If you want significant traffic from China (this might be important for e-commerce sites for instance), it may be worth maintaining a Chinese version of your website with a .cn domain name to rank higher in Baidu.module.exports and exports in Node.js. Here’s what I have learned.greetings.js and it contains the following two functions:
1
2
3
4
5
6
7
8
| // greetings.jssayHelloInEnglish = function() { return "Hello";};sayHelloInSpanish = function() { return "Hola";}; |
greetings.js increases when its encapsulated code can be utilized in other files. So let’s refactor greetings.js to achieve this goal. To comprehend what is actually happening, we can follow a three-step process:greetings.js:
1
2
| // greetings.jsvar exports = module.exports = {}; |
greetings.js that we want to become available in other files to the exportsobject:
1
2
3
4
5
6
7
8
9
10
| // greetings.js// var exports = module.exports = {}; exports.sayHelloInEnglish = function() { return "HELLO";}; exports.sayHelloInSpanish = function() { return "Hola";}; |
exports with module.exports and achieved the same result. If this seems confusing, remember that exports and module.exports reference the same object.
1
2
3
4
5
6
7
8
9
| module.exports = { sayHelloInEnglish: function() { return "HELLO"; }, sayHelloInSpanish: function() { return "Hola"; }}; |
greetings.js to a new file called main.js. This process can be described in three steps:require is used in Node.js to import modules. Imagine that this is how require is defined:
1
2
3
4
5
6
| var require = function(path) { // ... return module.exports;}; |
greetings.js in main.js:
1
2
| // main.jsvar greetings = require("./greetings.js"); |
1
2
3
4
5
6
7
8
9
10
| // main.jsvar greetings = { sayHelloInEnglish: function() { return "HELLO"; }, sayHelloInSpanish: function() { return "Hola"; }}; |
greetings.js as a property of our greetingsvariable in main.js.
1
2
3
4
5
6
7
8
| // main.jsvar greetings = require("./greetings.js");// "Hello"greetings.sayHelloInEnglish(); // "Hola" greetings.sayHelloInSpanish(); |
require returns an object, which references the value of module.exports for a given file. If a developer unintentionally or intentionally re-assigns module.exports to a different object or different data structure, then any properties added to the original module.exports object will be unaccessible.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // greetings.js// var exports = module.exports = {};exports.sayHelloInEnglish = function() { return "HELLO";};exports.sayHelloInSpanish = function() { return "Hola";};/* * this line of code re-assigns * module.exports */module.exports = "Bonjour"; |
greetings.js in main.js:
1
2
| // main.jsvar greetings = require("./greetings.js"); |
greetings to any code that is publicly available in greetings.js.module.exports to a data structure other than its default value is revealed when we attempt to invoke sayHelloInEnglish and sayHelloInSpanish:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // main.js// var greetings = require("./greetings.js"); /* * TypeError: object Bonjour has no * method 'sayHelloInEnglish' */greetings.sayHelloInEnglish(); /* * TypeError: object Bonjour has no * method 'sayHelloInSpanish' */greetings.sayHelloInSpanish(); |
greetings to a console:
1
2
| // "Bonjour"console.log(greetings); |
sayHelloInEnglish and sayHelloInSpanish on the string “Bonjour.” module.exports, in other words, is no longer referencing the default object that contain those methods.exportsand module.exports is clearer. Moreover, if you ever encounter an error in accessing publicly available methods in the future, then I hope that you have a better understanding of why those errors may occur.