Source code of my blog
77vincent / blog Goto Github PK
View Code? Open in Web Editor NEWThis is the place where my blogs are created.
Home Page: http://www.77vincent.com
This is the place where my blogs are created.
Home Page: http://www.77vincent.com
从2003年初一开始近视,100度,到大学基本稳定在475度,眼镜一戴就是十几年。
有了手术的想法,就要尽可能找最靠谱的术式、医院和医生。先后去了两家民营眼科医院,检查下来所有的手术方式都可选择,最终选择了目前最新进,最微创,术后抗冲击、稳定性最好,同时也最贵的全飞秒。并选择了知名的李海燕医生作为主刀医生。
2017年12月2号,周六,按预约时间早上八点到医院,缴费17000,取术后眼药,签手术同意书。此时护士接到手术室里的医生催促,便说等手术完毕再告知术后事项和用药指导。接着便被护士带领进入手术准备区,取下身上所有物品,比如手机、钥匙、钱包、首饰等(然而我并没有),套上手术服,戴上手术帽,然后进行眼部术前处理,包括冲洗、消毒、滴麻药。不到三分钟的时间,便被领进了手术室。
手术室很宽敞,也可以说是很空旷,一台很大的白色机器立在**,这次手术的主角,蔡司VisuMax,主刀医生,李海燕医生静静地坐在后面,似乎刚在看什么资料,一名护士站在不远的一侧,大家都很安静,也比较严肃。护士领我走到机器前,躺好又被滴了几滴麻药,医生还跟护士确认了一遍麻药有没有滴够,让我内心微微一惊,这个手术需要很多麻药吗?接着医生说稍等几分钟让麻药生效,接着便开始了手术。脸被遮住,只有术眼露出,眼镜被夹子撑大,正对着激光发射口,不到几秒钟的时间,激光的发射口就开始往下压,全部扣在眼睛上,是否有接触无从而知,眼睛此时没有什么触觉,只能观察到画面全部被发射口占据,周围一片黑暗,正**大部分视野是一个巨大的绿色光球,实际上应该只是一个小光点,不过现在看上去很大,几秒钟过后听到机器里一个很有磁性的女声说到,ready,我想机器应该开始运转,视野从外到内慢慢变朦,变糊,有点像毛玻璃的效果,绿色的光球慢慢暗淡,直至完全消失,画面全部变成黑蒙蒙的一片,我知道现在角膜内的透镜已经制作完毕,用时感觉不到二十秒。然后发射口被移开,依旧看不清任何东西,接着医生从侧面把角膜凸透镜抽出,毛玻璃的效果瞬间消失,但眼前的景象也不是很锐利,可以看到天花板上的灯光,有光晕感,像是美颜相机开了强力柔光效果。然后似乎有什么东西在眼球上滑动,应该是医生在擦洗、按压角膜,整个过程无痛,甚至可以说没有任何不适,硬要说有的话,大概是心理上的紧张不安。紧接着,另一只眼睛进行了同样的步骤。整个手术用时不超过十分钟。
世上有两种令人神往的能力,渴望却不可得,一是改变过去,二是预知未来,两者实质上是一种对应关系:想要改变过去,正是因为知晓了当下的结果,当下对于过去便是未来;而对于未来则是过去,因此想要提前知晓结果。
function adder(a, b) {
const carry = a&b
const sum = a^b
if (carry !== 0) {
return adder(sum, carry<<1)
}
return sum
}
function adderLoop(a, b) {
let carry = a&b
let sum = a^b
while (carry !== 0) {
const temp = carry<<1
carry = sum&temp
sum = sum^temp
}
return sum
}
Vim学习曲线陡峭,熟练后效率飙升。我之前在终端里作为主力编辑器使用,现在在VS code里使用Vim模式,以下和大家分享一些使用心得。
解读:
使用:
官网: http://www.vim.org/
教学(英文):http://www.openvim.com/
教学(中文):http://www.runoob.com/linux/linux-vim.html
In javascript, primitives are stored in individual memory space on every creation, so copying a primitive is dead simple and safe. Changes made to the copy will never affect the source one.
const source = 'Hello World'
const copy = source
copy = 'So long'
console.log(source) // => 'Hello World'
But when it comes to object type, simply assign an object to another variable does not truely copy the original one at all. Instead, the new one is only a reference to the original object, whatever changes made to either of them will affect the other one because fundamentally, they both refer to the same area of memory space where the object is stored.
const source = { a: 1 }
const copy = source
copy.a = 2
console.log(source.a) // => 2
In order to truly copy an object, there are two approaches to be distinguished from which are Shalow clone and Deep clone. Shallow clone only truly copies the first "layer", or at least, not all layers of the source object, as demonstrated below.
const source = {
a: 1,
b: { foo: 1 },
}
const copy = Object.assign({}, source) // This makes a shallow copy
// First layer of source object will be intact when modifying the copy
copy.a = 2
console.log(source.a) // => 1
// Second layer is still using reference
copy.b.foo = 2
console.log(source.b.foo) // => 2
As the name implied, deep clone means that the newly created object will be copied from the source object from bottom to top, whatever changes made to any layer of each one will not affect the other one as they are completely stored in two different area of memory space.
const source = {
a: 1,
b: { foo: 1 },
}
const copy = deepClone(source)
copy.b.foo = 2
console.log(source.b.foo) // => 1
Using recursion to go through the entire object, be sure to cover different types of object such as Object or Array, return the same type of value according to that of the input on each iteration, if the input is a primitive then just return the input as it is. For now I only covered Object and Array types which are mostly used in real applications but there are other iterable objects in Javascript like Set.
const deepClone = source => {
if (source === null || source === undefined) {
return source
} else if (source.constructor.name === 'Object') {
const clone = {}
for (let key in source) {
clone[key] = deepClone(source[key])
}
return clone
} else if (source.constructor.name === 'Array') {
return source.map(value => deepClone(value))
} else {
return source
}
}
class BinarySearchTree {
constructor() {
this.root = null
}
insert(data) {
const newNode = {
data,
left: null,
right: null,
}
if (this.root === null) {
this.root = newNode
} else {
this._insertNode(this.root, newNode)
}
return this
}
_insertNode(node, newNode) {
if (newNode.data < node.data) {
if (node.left === null) {
node.left = newNode
} else {
this._insertNode(node.left, newNode)
}
} else {
if (node.right === null) {
node.right = newNode
} else {
this._insertNode(node.right, newNode)
}
}
}
remove(data) {
this.root = this._removeNode(this.root, data)
return this
}
_removeNode(node, data) {
if (node === null) {
return null
} else if (data < node.data) {
node.left = this._removeNode(node.left, data)
return node
} else if (data > node.data) {
node.right = this._removeNode(node.right, data)
return node
} else {
if (node.left === null && node.right === null) {
return null
}
if (node.left === null) {
return node.right
} else if (node.right === null) {
return node.left
}
const aux = this._findMinNode(node.right)
node.data = aux.data
node.right = this._removeNode(node.right, aux.data)
return node
}
}
inOrder(node = this.root) {
if (node !== null) {
this.inOrder(node.left)
console.log(node.data)
this.inOrder(node.right)
}
}
preOrder(node = this.root) {
if (node !== null) {
console.log(node.data)
this.preOrder(node.left)
this.preOrder(node.right)
}
}
postOrder(node = this.root) {
if (node !== null) {
this.postOrder(node.left)
this.postOrder(node.right)
console.log(node.data)
}
}
search(data, node = this.root) {
if (node === null) {
return null
} else if (data < node.data) {
return this.search(node.left, data)
} else if (data > node.data) {
return this.search(node.right, data)
} else {
return node
}
}
_findMinNode(node) {
// if left of a node is null
// then it must be minimum node
if(node.left === null) {
return node
} else {
return this._findMinNode(node.left);
}
}
}
In general, "this" depends on how the function is called.
class ClassExample {
constructor(name) {
this.name = name
console.log(this)
}
}
function ConstructorExample(name) {
this.name = name
console.log(this)
}
new ClassExample('vincent')
// -> ClassExample { name: 'vincent' }
new ConstructorExample('vincent')
// -> ConstructorExample { name: 'vincent' }
function fn() {
console.log(this);
}
const obj = {
value: 5
};
const boundFn = fn.bind(obj);
boundFn(); // -> { value: 5 }
fn.call(obj); // -> { value: 5 }
fn.apply(obj); // -> { value: 5 }
const obj = {
value: 1,
method() {
console.log(this)
}
}
obj.method() // -> { value: 1, method: f }
function fn() {
console.log(this)
}
fn() // -> Window
const obj = {
method() {
console.log(this)
}
}
const method = obj.method
method() // -> Window
const obj = {
method() {
console.log(this)
},
arrowMethod: () => {
console.log(this)
},
createArrowFn() {
return () => console.log(this)
}
}
obj.method() // -> { fn: ƒ, arrowFn: ƒ, createArrowFn: f }
obj.arrowMethod() // -> Window
// call, apply, bind won't work as expected
obj.arrowMethod.call(obj) // -> Window
obj.arrowMethod.apply(obj) // -> Window
const method = obj.arrowMethod.bind(obj)
method() // -> Window
// The inner arrow function is created when the outer createArrowFn is called
// that's the moment when "this" inside the arrow function gets set which is "obj"
// because that is what the "this" is in the createArrowFn scope
obj.createArrowFn()() // -> { fn: ƒ, arrowFn: ƒ, createArrowFn: f }
Primitives
1 // Number
'foo' // String
true // Boolean
null // Null
undefined // Undefined
Symbol() // Symbol (ES6)
Objects
{} // Object
[] // Array
function fn() {} // Function
new Set([]) // Set (ES6)
Primitives are equal if their values are equal.
1 === 1 // true
'foo' === 'foo' // true
true === true // true
null === null // true
undefined === undefined // true
Objects are not evaluated as equal even they appear to have the same value beacuse every object is an instance of the class "Object" which ocupies an individual area of memory space.
{} === {} // false
[] === [] // false
(function fn() {}) === (function fn() {}) // false
For primitives:literal syntax (left side) vs using constructor without "new" keyword (right side)
'foo' === String('foo') // true
1 === Number(1) // true
true === Number(true) // true
Creating primitives using constructor with "new" keyword will result in creating an object which is not a primitives anymore.
'foo' === new String('foo') // false
1 === new Number(1) // false
true === new Boolean(true) // false
These values are falsy
!!undefined // false
!!null // false
!!0 // false
!!"" // false
!!NaN // false
Objects are all truthy
!!(function () {}) // true
!!new Set() // true
!![] // true
!!{} // true
Do not use abstract equality check "==" because:
'' == 0 // true
0 == [] // true
[] == '' // true
'' == false // true
0 == false // true
[] == false // true
isNaN
isNaN('a') // true
isNaN(NaN) // true
isNaN({}) // true
isNaN((function() {})) // true
isNaN(undefined) // true
isNaN('0') // false
isNaN([]) // false
isNaN(false) // false
isNaN(true) // false
isNaN(null) // false
Iterate an object using the traditional "for in loop", this will also iterate properties which lies in its prototype.
for (let key in obj) {
console.log(key)
}
An object is not an iterable and therefore can not be iterated using the "for of loop" because "for of loop" can only be applied to iterables.
for (let key of obj) {
console.log(key)
}
// Uncaught TypeError: obj is not iterable
Ways of checking if a piece of data is an array
Array.isArray(data)
// or
Object.prototype.toString.call(data) === '[object Array]'
// or
data.constructor.name === 'Array'
Array can also be given associative items which is like key-value pairs in object, but the key-value pair will always be the last item of the array, and won't be counted into the array's length. Only "for in loop" will iterate all the items including the associative items.
let arr = [1, 2, 3]
arr.foo = 1 // [1, 2, 3, foo: 1]
arr.length // 3
for (let key in arr) {
console.log(key)
}
// 1, 2, 3, foo
for (let key of arr) {
console.log(key)
}
// 1, 2, 3
arr.map((v) => {
console.log(v)
})
// 1, 2, 3
Function can be assigned properties just like any other object.
fn.foo = 1
Can be iterated by the "for in loop"
for (key in fn) {
console.log(key)
}
// foo
This is how to add static class properties and methods to the constructor.
MyConstructor.prop = 1 // static class property
MyConstructor.method = () => {} // static class method
Using "function" keyword to create a function, hoisting will happen.
foo.name // "foo"
foo() // "foo"
function foo () { return foo.name }
Using named function expression to create a function.
bar()
// Uncaught ReferenceError: bar is not defined
const bar = function zoo () { return zoo.name }
bar.name // "zoo"
bar() // "zoo"
zoo.name // Uncaught ReferenceError: zoo is not defined
"Return" can be omitted along with the curly brackets.
const fn = a => a * 2
// is equal to
const fn = a => { return a * 2 }
// But can not simply use "return" without curly brackets.
const fn = a => return a * 2
// Unexpected token return
JS里的类实质上是构造函数,用Pascal命名式
function Counter () {
this.count = 0
}
箭头函数不能用于构造函数,因为lexical this缘故
const Counter = () => {
this.count = 0
}
let c = new Counter()
// Uncaught TypeError: Counter is not a constructor
给实例添加方法,坏实践是每个实例都有自己的方法,增加程序开销
const Counter = function Counter () {
this.count = 0
this.increase = function () { this.count++ }
}
好实践是通过原型链继承
Counter.prototype.increase = function () { this.count++ }
申明式定义
class MyClass { }
MyClass.name // "MyClass"
表达式定义,同函数定义规则一样,类名只在内部有效
const A = class B { }
A.name // "B"
B.name // ReferenceError: B is not defined
实例属性:放在constructor方法里
class MyClass {
constructor() {
this.a = 1
}
}
实例方法:之间不用逗号分隔
class MyClass {
methodA() {}
methodB() {}
}
类静态方法:使用static关键字
class MyClass {
static staticMethod() {}
}
类静态属性:通过static + getter模拟
class MyClass {
static get staticProps() { return 'some props' }
}
One of the most reliable ways to discern whether a corporation has begun to rot is to gauge the derivative of the utility its products provide over time. A company like Apple witnessed a huge spike in average product utility when they released the iPhone, which increased for some time, but eventually plateaued when they started removing vital phone functions like the 3.5mm jack. Generally speaking, most companies experience either an S-curve or a parabolic curve of this kind of utility: the former types generally find their niche, fill it, and operate in comfortable profit without innovating much more; the latter types manage to muck things up and crash and burn having failed to understand their product.
Angular. Its mere name is a hostile form on the tongue. Pronounce it slowly. /’eŋgjəlɚ/. The throat itself contorts around the hideous alien shape of this word, which means ugly, sharp, and artificial.
Here, I will illustrate the various ways in which my psyche was irreversibly traumatized by this pandemonium of demon-droppings, Google’s brainchild: the ANGULAR WEB DEVELOPMENT FRAMEWORK.
Have you ever had a brilliant idea for a weekend project, started it Saturday afternoon, and then steadily come to realize the project would take at least six months to fully implement? Google had a moment like that when they set out to document the inner workings of the ANGULAR WEB DEVELOPMENT FRAMEWORK. They then drip-fed an intern nothing but espresso for weeks until she had a Hello World code-along project that they were able to pass off as a complete documentation of their entire stack.
None of the errors you will encounter while building a WEB APPLICATION on the ANGULAR WEB DEVELOPMENT FRAMEWORK will be listed in this documentation. Indeed, very few of the design patterns or core concepts you will require will be present here, either. If you want to learn how to actually build a dangerous tool with ANGULAR, you will need to purchase an online course (I can recommend Maximillian Schwarzmueller’s comprehensive Complete Guide, which saved my job) that will reveal to you all of the Gotcha! moments and snare traps that await the naȉf who believes they can simply start writing Javascript like a React or Vue developer.
Angular’s actual documentation is more of a function, which I will pseudocode below.
Notice anything? Yes, that’s right: when bugfixing in ANGULAR, you need to specifically exclude the phrase angularjs
from every one of your searches. You can’t append a 2, or a 7, or hope that Just “ANGULAR”
will suffice to exclude the ill-fated first edition of this comprehensive software development stack. Needless to say this alone starts to grate after a while.
But then you get around to reading enough of these Stack Overflow “solutions” to people’s problems, and it begins to dawn on you that between the code you write and the code that runs in the browser, there isn’t just a compiler that will handily break all of your CSS for you, there’s a bona fide black box that demands you format your application in exactly such a way or else the entire thing will fail silently or worse, spit out an incorrect error message. You literally cannot trust anything that the ANGULAR WEB DEVELOPMENT FRAMEWORK tells you about what you have done wrong because not even it knows how its own system works. Did you declare an EntryComponent
in the Module
it’s intended to lazy-load into rather than the root Module
where it loses all benefits of lazy-loading? Nein! Did you try to use Two-Way Data Binding™ rather than an arcane daisy-chain of EventEmitter
s and Subscription
s and Service
s? Verboten!
The entire ANGULAR WEB DEVELOPMENT experience is like this. You run at full speed into a brick wall enough times, and eventually you learn to creep around at a snail’s pace, groping pathetically for any arbitrary obstacles that the FRAMEWORK might throw in your way. There is little in the world more frustrating than attempting to operate this monstrous and moody contraption that the allegedly smartest corporation in the world managed to excrete.
Imagine a car whose hood never opens, and whose dashboard says only DASHBOARD in blinding lights that don’t switch off. The car cannot be repaired once broken; it can only be replaced or modified from the outside in. It guzzles gas even when it’s not turned on. No service manual exists. If you want to know how it works, here’s the 5,280-page assembly guide. Good luck.
ANGULAR is slow. Writing apps takes a long time and the apps you create function very sluggishly once your app gets more complicated than Hello World
. This would be acceptable if the ANGULAR FRAMEWORK conferred any benefits to the user or the programmer, such as failing gracefully in the event of a runtime error, or compiling quickly, or providing an increase to app security. But ANGULAR possesses none of these. In fact, it collapses into a wailing heap at the mere mention of an Uncaught TypeError
.
Basically the only way to understand what Angular is actually doing is to read the millions of lines of source code the devs happily provide on GitHub. Since nobody actually does that, ANGULAR WEB DEVELOPERS typically settle for learning one or two design patterns that they know will not explode, and building an entire application out of them. Like a submarine built out of increasingly large doctor’s office inflatable gloves. It could probably work, given an endless supply of gloves and toddlers. Your only other option is to immerse yourself in the nonsensical, arbitrary madness that awaits the developer who attempts to learn how ANGULAR “works”.
I’ll tell you how it works. Your Components talk to your Services which relay data to your other Injectables via the Modules that your app Imports. What’s unclear about that? If you need clarification, go review the Material Design guidelines. They’ve got Components for everything you need to build. And keep your designs pixel perfect, please. It ought to be easy to do, since Material and Angular are designed by Google to supposedly work together nicely. And it will look and feel great when the padding on each list item eats up a third of the webpage, and opening a dropdown menu takes all of sixteen seconds. Don’t you feel freed from the constraints of an arbitrary and underdeveloped Internet?
Not a single part of ANGULAR’s design makes your code run faster. It increases only three things: complexity bloat, the time it takes to complete a simple feature, and — if you can somehow avoid driving yourself insane writing this spaghetti day in and day out — job security for you and your team. But be warned: the ANGULAR WEB DEVELOPMENT FRAMEWORK won’t do you any favors when a deadline is approaching.
Open up your IDE of choice, coder! Enter your IntelliJ IDEA License Key to begin. A License Key is required to continue. Thank you for entering your License Key. Please select the Type Script “Linter” you would like to use to “Lint” your Type Script Code. The ANGULAR WEB DFGHSDFG FGSGDFSFDS runs Type Script, which is Java Script with Types. That makes it Good. You must use an IDE that is compatible with Type Script. Type Script will occasionally update. This will break your code and the code in your dependencies. This is expected. Rejoice in the time you are paid to pick through worming function calls! This is living!
Do not be alarmed if your dependency libraries occasionally issue breaking changes after altering a single property on a class you never use. You can just add a manual file editing step to every build process. Or you could freeze the library at a compatible version and lose all future improvements. Thank you for choosing Type Script and ANGULAR.
ANGULAR will helpfully mix fake HTML ELEMENTS into your real HTML ELEMENTS because the entire app is getting shredded to pieces by their AHEAD OF TIME COMPILER anyway, so what does it matter if they pollute a correct specification with a capricious impostor? When composing an HTML FILE, please remember to use the ANGULAR-specific markup language, which includes DIRECTIVES for making your code even more interesting to debug. You can even write your own ANGULAR DIRECTIVES if you’d like to further obfuscate the purpose of the characters you type. The most toothsome feature of all this advanced ANGULAR-flavored HTML is that tracing errors to their source is exponentially more difficult than it is in almost any other library, framework, or coding environment in living memory. They will literally feed you the wrong error message. You can search for a missing closing tag for days before you realize that the actual error was buried somewhere deep in the conditionals and mysterious imported directives, and to attempt to explain it to an outsider would inspire either a look of horror, or one of pity. Oh, also you can’t write same-page anchor links anymore because that functionality was too helpful. Enjoy trying to manually scroll with The Java Script!
It’s alright though, you will have plenty of time to contemplate your ill-advised decision to continue programming with this beautiful FRAMEWORK because every time you edit any minor piece of HTML you need to recompile the entire application. Hot reloading works on the baby stuff, but once your app develops any degree of complexity, you need to wait 60 to 300 seconds while the processor crunches through your entire codebase to add a single HTML class to a single element in a popup. Hours of your life soon disappear into the void. Hours spent staring at the console message: 92% chunk asset optimization
. I hope you like podcasts!
“But wait, you can avoid all that compilation if you use this technique!! [Stack Overflow link*]” Can’t use that technique because the ANGULAR WEB DEVELOPMENT FRAMEWORK manages to compile apps without errors in development mode that throw errors in production mode. So you need to build production, every single time, to catch every bug.
Do you hate writing legible CSS? ANGULAR provides all sorts of confusing ways to convert explicit styling rules to pseudo-HTML that needs to recompile every time you change an element’s class. You don’t even need to learn FLEXBOX… until, of course, the manager demands to know why your layout isn’t “up to standard” — MATERIAL DESIGN standard — and then suddenly, you realize you’ve been incanting nonsense words at a black box, and the entire application rests on a precarious assembly of assumptions that are about to collapse, but you can’t fix them without undoing weeks of work, but the deadline, the deadline!
ANGULAR made me a better programmer because it taught me how to write a functional application while standing in a volcano, hopping across a lava pool on islands of solid rock. Anything I did that was not the most efficient way of doing it immediately resulted in an unbearable slowdown. Anything I attempted to do that was more complex than the most bare-bones solution of adhering Data Object A to Display Element B was liable to send the entire place up in flames. Yes — any error anywhere in your ANGULAR APPLICATION will cause the rest of the ANGULAR APPLICATION to behave unexpectedly. We ended up implementing a system where the app would just reload the page every time it noticed an uncaught error because it was simpler than attempting to filter through support tickets to determine whether a bug was its own error or the result of some other error that had quietly disappeared after leaving a crater in the functionality. Then they removed that fix: “Just don’t write errors. I thought you were using Test Driven Development?”
I will carry the knowledge of the ANGULAR WEB DEVELOPMENT FRAMEWORK with me for the rest of my life. There is no way to rid myself of it; it adheres to me more powerfully than any slime, and it clogs the wrinkles of my brain more thoroughly than any natural fluid could. I have no choice but to offer my services as an ANGULAR DEVELOPER if I am to feed my family. But there is hope. One day I may obtain a contract using another framework like React or Redux, or God willing a library that is unopinionated about the rest of your web stack like Vue. But for now I soldier on, clutching to the memories that I know are mine, fending off the invading hordes of Google-cepts that threaten to overtake the very essence of my identity. We live to fight another day.
Today I am working at Whiteboard Dynamics, where my time is less often spent Ctrl-C’ing the ANGULAR COMMAND LINE TOOL and more often spent writing clean, efficient, and functional code for products that don’t need to be rewritten every three months. All in all, I find the change to have restored several years to my life expectancy. We will write something in ANGULAR if you request — as I said, I will bear this cursed ability forever — but trust me: you’re better off going with a library people will enjoy working on. It’ll cost you less time and money, and you’ll get to keep your immortal soul.
A guide for building unit test with best practice in an Angular project.
Unit test in Angular is done by the use of Jasmine, a test framework and Karma, a nodeJS-based test runner. Jasmine is a behavior-driven development framework for testing Javascript code. Karma is neither a testing framework, nor an assertion library. It just launches instances of the chosen web browsers, hosts your application through a lightweight web server and loads unit test files, and displays the test results against each browser in the terminal.
There are two types of tests that can be made in an Angular projec, service-based test and componet-based test, due to that fact that an Angular program is mainly consist of these two elements, component and service.
Testing services is relatively easier than testing components. In a modern data-driven web application like Angular, services are basically a set of methods that operates data then return those data back to the component to be displayed. A service can be either strongly coupled to a component or a common one. A strongly coupled service is more like a an abstract method layer of a component from a functional programming perspective, the purpose of which is to extract those abstract data manipulation from a component and therefore reducing the code duplication and making a component easier to compose. So most of time, writing a unit test explicitly for a strongly-coupled service is trivial, cause everything will be well tested during the execution of its componet-based test.
On the other hand, a common or universal service needs to be well tested because it might affect multiple components that use it, or even other services that rely on it. The interface of this type of services, as well as their output, tent to be stable and consistent, so when something is not going well in a component which relies on common services, we can target on the component itself on prior(also their sibling service). As a result, it's reasonable that to focus on those common service when building unit test.
Below is the recommended approach, actually there are several approaches making a service-base unit test, they are virtually equivalent but with different syntax. I suggest we stick with only one approach by using the TestBed utility, this is especially good for testing services those also have their own dependency tree, Also, in component-based test, TestBed is a must-use utility, it would be more simplified and productive to stick with one common approach instead of many.
When there are dependencies, it's better to do the 'solitary test', which means a the dependency used is not the actual one but a mock so that the incorrectness in those dependencies do not affect the current unit being tested. More details at seciton Test with dependencies
describe('CommonService', () => {
let service: CommonService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ DependentService ]
});
service = TestBed.get(CommonService);
});
it('#doubleValue should return a doubled number', () => {
const input = 1;
expect(service.doubleValue(input)).toEqual(input * 2);
});
});
The question lies in what sort of services that needs to be tested and what to test.
Below are some low-level and common functions. They are not a product-specific which means their purposes are well-defined and the outputs are stable and predictable. They can be tested by given a custom test case which is even not relevant to the actual product.
intersection(a: any[], b: any[]): any[] {
const setA = new Set(a)
const setB = new Set(b)
return [...setA].filter(each => setB.has(each))
}
intersection([1, 2, 3, 4], [2, 3, 4, 5])
// [2, 3, 4]
insert(index: number, source: any[], item: any): any[] {
const copy = source.map(each => each)
copy.splice(index, 0, item)
return copy
}
insert(1, [1, 2, 3, 4], 99)
// [1, 99, 2, 3, 4]
Most of the services are product-specific which means their correctness are highly dependent on what the product is like and how the product works. They can be either strongly coupled with a component or common. They tend to be unstable due to the rapid change of the product itself.
dateFormat(dateString: string): string {
const date = new Date(dateString)
const y = date.getFullYear()
let d = date.getDate()
let m = date.getMonth() + 1
d = String(d).length === 1 ? 0 + String(d) : d
m = String(m).length === 1 ? 0 + String(m) : m
return `${y}-${m}-${d}`
}
dateFormat('2018/3/3')
// "2018-03-03"
class RequestService {
constructor() {
private http: HttpClient,
}
login(): object {
return http.get('http://...')
}
}
it('#login should return some value',
(done: DoneFn) => {
service.login().subscribe(value => {
expect(value).toBe('observable value');
done();
});
});
There are several concerns when testing a component as follows:
This is the very first step when testing a component. To test a component it's better we still stick with the TestBed approach, this approach covers all cases we might meet.
ng test
command it's not needed.describe('BannerComponent', () => {
let component: BannerComponent;
let fixture: ComponentFixture<BannerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BannerComponent ]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BannerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeDefined();
});
});
To test if some certains parts in the component work properly as expected. These parts can be user avatar, name, navigation bar, sign in button etc.
it('should have <p> with "banner works!"', () => {
const p = fixture.nativeElement.querySelector('#banner');
expect(p.textContent).toEqual('banner works!');
});
it('should have <p> with "banner works!"', () => {
const bannerElement: HTMLElement = fixture.nativeElement;
const p = bannerElement.querySelector('.');
expect(p.textContent).toEqual('banner works!');
});
The core idea of unit test is to only test a single target and eliminate the affects of other factors. It's possible that the unit breaks not because of errors from its own methods but from one of its dependencies when it uses the real dependency. So for those cutsom dependencies, or dependencies that communicate with backend, use the mock one, but not the real one.
class MockMyService extends MyService {
showTitle() {
}
getUser() {
return 'user info'
}
}
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MyComponent ],
providers: [
{ provide: MyService, useClass: MockMyService }
]
}).compileComponents();
}));
});
Angular use the library RxJS to handle asynchronous code, like fetching data from backend or custom event triggered by user interaction. When testing, these events need to be triggered manually, otherwise the code in their callback won't be tested.
// mockData will be the data that passed into the event and accessible in the callback in the subscribe function.
it('should display user info after data fetched', () => {
let myService = TestBed.get(MyService);
myService.customEvent.push(mockData)
})
it('should populate ', async(() => {
fixture.whenStable().then(() => {
fixture.detectChanges();
component.onDropdownChange();
expect(component.companyList.length).toBeGreaterThan(0);
expect(component.isCountrySelected).toBeTruthy();
expect(component.isCompanySelected).toBeFalsy();
expect(component.isPaygroupSelected).toBeFalsy();
})
}));
function insertionSortForward(input = []) {
// Copy the array
// as insertion sort modifies the input array in place
// which is not a good behavior for a functional programming paradiam
let array = input.slice()
for (let i = 1; i < array.length; i += 1) {
const value = array[i]
let j = i
while (j - 1 >= 0 && array[j - 1] > value) {
array[j] = array[j - 1]
j = j - 1
}
array[j] = value
}
return array
}
insertionSortForward([3, 2, 5, 4, 1])
// => [1, 2, 3, 4, 5]
function insertionSortBackward(input = []) {
let array = input.slice()
for (let i = array.length - 1 - 1; i >= 0; i -= 1) {
const value = array[i]
let j = i
while (j + 1 <= array.length - 1 && array[j + 1] > value) {
array[j] = array[j + 1]
j = j + 1
}
array[j] = value
}
return array
}
insertionSortBackward([3, 2, 5, 4, 1])
// => [5, 4, 3, 2, 1]
原因:如果采用后者,当文件里多次出现一个元素名时,首先要确保当前修改的元素处于正确的媒体查询内,当文件很长时,这个过程会很痛苦。
// bad
@media (max-width: $bp-laptop) {
.foo {}
.bar {}
}
// good
.foo {
@media (max-width: $bp-laptop) {}
}
.bar {
@media (max-width: $bp-laptop) {}
}
// bad
.boo {
@media (max-width: $bp-laptop) {
// some properties
&:before {}
}
}
// good
.boo {
@media (max-width: $bp-laptop) {}
&:before {
@media (max-width: $bp-laptop) {}
}
}
原因: 假如把某个颜色命名为:@color-footer-background,倘若之后,导航条也要使用这个颜色作为背景色,这个命名逻辑就失效,而这在CSS编写中是很常见的,久而久之,代码就会难以阅读.
// bad
@color-header-background: #0366D6;
// good
@color-navy-blue: #0366D6;
原因: 更容易阅读与编辑
// bad
@color-navyBlue: #0366D6;
// good
@color-navy-blue: #0366D6;
// 颜色
@color-orange-red: #CB2431;
// 字体
@font-sans: Arial,
原因:这样使得每个元素都有唯一入口,方便查询修改。
// bad
.foo {}
.foo:before {}
// good
.foo {
&:before {}
}
With maximum and minimum.
(min, max) => Math.random() * (max - min) + min
With maximum and minimum and round the result into an integer.
(min, max) => Math.floor(Math.random() * (max - min + 1)) + min
Spread operator, modify the target in place.
array1.push(...array2)
Using concat, a more functional approach.
let array3 = array1.concat(array2)
(array) => [...new Set(array)]
(array) => {
let arr = []
for (let i = 0; i < array.length; i++) {
if (arr.indexOf(array[i]) === -1) {
arr.push(array[i])
}
}
return arr
}
(array) => array.filter((item, index) => index === array.indexOf(item))
(arr) => {
let len = arr.length
for (let j = 1; j < len; j++) {
let key = arr[j]
let i = j - 1
while (i >= 0 && arr[i] > key) {
arr[i + 1] = arr[i]
i--
}
arr[i + 1] = key
}
return arr
}
(arr) => {
let len = arr.length
for (let i = 0; i < len; i++) {
for (let j = 1; j <= i; j++) {
if (arr[j - 1] > arr[j]) {
let temp = arr[j - 1]
arr[j - 1] = arr[j]
arr[j] = temp
}
}
}
return arr
}
# untrack / modified / deleted =====> added
git add <file name>
# added =====> commited
git commit [file name] -m "commit message"
# local branch A =====> remote branch A
git push
# local branch A <===== remote branch A
git pull
# local branch A =====> specified branch
git push origin <branch name>
# local branch A <===== specified branch
git pull origin <branch name>
# Pull from the upstream repository
git pull upstream <branch name>
# or
git pull upstream HEAD
# added =====> untrack / modified / deleted.
git reset [file name]
# committed =====> added.
git reset [file name] --soft HEAD~
# committed =====> modified / untrack / deleted.
git reset [file name] HEAD~
# committed =====> initial status (cautious).
git reset [file name] --hard HEAD~
# Switch to another branch
git checkout <branch name>
# Create a new branch and immediately switch to the branch
git checkout -b <new branch name>
# Revert files (Cautious)
git checkout <file name>
# List local branches
git branch
# List remote branches
git branch -r
# List local and remote branches
git branch -a
# Create local branch
git branch <branch name>
# Delete local branch
git branch -d <branch name>
# Push local branch to remote
git push -u origin <branch name>
# Delete remote branch
git push -d origin <branch name>
# Delete all files
git clean -f
# Delete repository
git clean -f <directory name>
# Only shows what would be done but without actually doing it.
git clean -d [whatever]
# List full history
git log
# List commits only made by a specified user
git log --author=username
# List history with more details
git log --stat
# Show details of the last commit
git show
# Show details of a specific commit
git show <commit ID>
# To see the current remote repository
git remote -v
# To set the upstream
git remote add upstream <url of the remote upstream repository>
The loop version is hard to write at the first glance, but it is quite efficient in both time and space.
function fibonacciLoop(n = 0) {
// store the last two number
const temp = []
for (let i = 0; i <= n; i += 1) {
// the very two first round will be skipped
if (i === 0) {
temp.push(0)
continue
}
if (i === 1) {
temp.push(1)
continue
}
// sum up the last two number
const sum = temp[0] + temp[1]
temp[0] = temp[1]
temp[1] = sum
}
// return the last one in the temporary storage
return temp[1]
}
Recursive version is easy to write because it is more intuitive, but the naive version will be quite low efficient.
function fibonacciRecursive(n = 0) {
// stop condition
if (n === 0) {
return 0
}
if (n === 1) {
return 1
}
return fibonacciRecursive(n - 2) + fibonacciRecursive(n - 1)
}
function fibonacciRecursive(n) {
const m = new Map()
return _fi(n, m)
}
function _fi(n = 0, map) {
// stop condition
if (n === 0) {
return 0
}
if (n === 1) {
return 1
}
// pruning
// if a value has already been calculated, take the value and return
const v = map.get(n)
if (v) {
return v
}
const ret = _fiRecursive(n - 2, map) + _fiRecursive(n - 1, map)
// store the calculated value in a map
map.set(n, ret)
return ret
}
我想很多人心中,大概都有一个神往的场景,梦境一样的画面,希望置身其中,在那里能感到一种永恒的舒适,也许现实中每个人的奔忙劳碌,其实都是在不断试图向那个画面靠近。
那个画面是长久并稳定的,也许细节上会有所变化,但关键的氛围始终差不多。那关键的氛围,在我看来,是由那个人与生俱来的性情,或许再加上一点早期经历所造就的。这里所说,有点先天的意思,深植于人格当中,像基因一样恒定。比方说我自己,那个氛围大概在初中时形成了:我牵着一个女人,走在一片茫茫的蓝紫色草原上,天色暗淡,辽阔寂静,漫无目的。后来的十多年里,随着心智的成长和阅历的积累,那个意向也经历了一系列变化,还衍生出多个子版本。比如我一个人骑着哈利波特里那样的飞天扫帚,夜里在老家边上的河**飞行,两边是沉静的、黯淡的山和树。也有现实的版本:我住在了海边山崖上的一个房子里,入夜时,透过卧室里占满整面墙的落地窗,看着近处海浪拍击峭壁,和远方无边的、墨蓝色的大海。
rs = t
Example A: -7 is a factor of 35
Example B: 8 is a factor of -40
Example C: The integer 4 has six factors: -4, -2, -1, 1, 2, 4.
Example A: 1.2 is a multiple of 0.4
Example B: -2π is a multiple of π.
q = (n - r)/d
https://eecs.berkeley.edu/academics/graduate/industry-programs/meng
https://www.csc.ncsu.edu/academics/graduate/
https://applygrad.ncsu.edu/apply/
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.