javascript_basic
Javascript
- The single quote/double quotes patterns are identical in terms of functionality
- ; can be ignore if unnecessary, but it’s not a good habit.
- There’s no Integer in JavaScript (except BigInt), all are float(64 bits).
- Index starts from 0, like for String and Array.
JS behaves like C style for supports operators.
1 | + Add |
printing in JS
Printing is an easy way to show result, there are several ways to print variable value. here we go.
- in one line
1
2console.log("hello \
jason"); - in multiple lines
1
2
3console.log("hello \n jason");
console.log(`hello
jason`);//template string - show one parameter at last position
1
2
3const name = "jason";
console.log("hello", name); # a space is added between after 'hello' automatically
console.log("hello %s", name); # no auto added space - show multiple parameters at different positions
1
2const msg = "welcome";
console.log("hello %s msg %s", name, msg); - variable can be at any position
1
2
3
4console.log(name, "hi"); #has auto added space before 'hi'
console.log(name, "hi", name); # has auto added space before and after 'hi'
console.log(name, "hi %s", name); # NOT support, %s must be in the first string if has
console.log(name + "hi %s", name); # support - template string
1
console.log(`${last_name} hi`); // last_name is name of a variable
Types
1 | ==========================javascript types============================================= |
auto-boxing
javaScript has two main type categories, primitive(string, number, boolean) and object.
1 | // primitive |
A primitive is converted to its wrapper type(auto-boxing) only when a method of the wrapper type is invoked, when auto-boxing happens, a temporary object is created and destroyed after that call.
It’s a primitive data type. It has no methods, it is nothing more than a pointer points to a raw data memory reference, which explains the much faster random access speed than object.
So what happens when you do s.charAt(i) for instance?
1 | s[0] == s.charAt(0) |
Since s is not an instance of String, JavaScript will auto-box s, which has typeof string to its wrapper type, String, with typeof object or more precisely.
The auto-boxing behaviour casts a back and forth to its wrapper type as needed
.
If you want to force the auto-boxing or to cast a primitive to its wrapper type, you can use Object.prototype.valueOf, but the behaviour is different. Based on a wide letiety of test scenarios auto-boxing only applies the ‘required’ methods, without altering the primitive nature of the letiable. Which is why you get better speed.
Set on wrapped temporary object has no lasting effect as that temporary is destroyed soon after
1 | const str = 'hello'; |
Numbers and Dates
1 | function number_date() { |
3 16 12 [Number: 12]
3.141592653589793 0.3273509254139666 4 1 3
Wed Nov 04 2020 18:26:24 GMT+0800 (China Standard Time) 700 18
1.5
1
0.8324244498379996
2
true
false
1 | function string_number_convert() { |
123
123
NaN
123
123
123
2
2
123
123
2hello
Special number NaN
1 | function sepcial_number() { |
special number: Infinity and -Infinity,NaN are numbers
NaN: any number of other numeric operations that don not yield a meaningful result.
Infinity
-Infinity
number
NaN
NaN
NaN
false
true
false
false
false
false
true
false
String
Sting index starts with 0, not support -1 as the last index.
There are two ways to create a string, one uses string primitive, the other uses String object.
1 | let s_hi = "Hello"; |
But you can call any of the methods of the String object on a string literal value—JavaScript automatically converts the string literal to a temporary String object, calls the method, then discards the temporary String object
strings are immutable array-like objects
, you can’t change individual characters.
There is another big feature for string is template string
, you access var from string directly, more like Bash, it’s easy to create complex string by accessing var.
1 | let name = "jason"; |
run js from string
1 | function eval_demo() { |
1 | function string_demo() { |
100 hi number 100
9hello, boy boy 9 16
3
hello, boy boy
he
9HELLO, BOY BOY
9hexxo, boy boy
false
false
true
9hello, boy boy
9hello, boy boy
9hello, boy boy 9hello, boy boy 9hello, boy boy
some String APIs support regex
when use with regex with such API, patter must be written in way /pattern/
, not "pattern"
.
- search: check if match return -1 if no match
- match: got the matched value, return null if no match
- replace: repalce matched part, return a new string
match: return an object that looks like an array, if no matched, null returned
- index: the start matched index
- [0]: the full matched string
- [1]…[n]: the substring matched in ()
1 | function string_regex_api() { |
0 -1
9boy, hello boy
9hello, girl boy
0 9hello hello
9h
Array
Array element can have different types, but most time, it stores same type.
Like string, there are two ways to create an array, but both created object
1 | let array_p = ['a', 2]; |
Array supports method same like Python
- pop(), push(elm) at end
- shift(), unshift(elm) at head
- reverse, sort
- join
- find: return the first element, filter use callback for testing, return a new filtered array.
- indexOf/lastIndexOf: return index or last of the element, -1 if not found
- includes: like indexOf, but return true or false.
- forEach, map, reduce, filter always use this if possible to avoid for loop
- forEach,map, reduce, filter provides second argument(thisArgs) used as this by callback handler
- slice(subarray, copy array if no parameter), concat(combine two arrays): new array is returned, orignal unchanged
- some/every: return true if all/some pass test.
- Array.isArray(obj): return true if an arry
check an element in an array with several ways
- for to loop every element
- indexOf
- includes
NOTE: index from 0 and element can be any type, not same
1 | function check_array_type() { |
object
var arr is an array
[ 'a', 2, 3 ] [ 'a', 2, 3, 3, 4, 5 ] [ 'a', 2, 3 ] [ 2, 3 ] [ 2 ] a,2,3 2 2 -1 true [ 2, 3 ] a;2;3
a
2
3
a
2
3
0
1
2
arrCustom
[ 3, 4, 5 ]
[ 2, 3 ]
6
false
true
delete an element from array
Remove? | |
---|---|
An item | array.splice(index, 1) |
First item | array.shift() |
Last item | array.pop() |
What about delete? | Try to avoid delete, causes sparse arrays. |
delete do NOT change length and leave empty slot! others NOT
Using delete creates these kinds of holes. It removes an item from the array, but it doesn’t update the length property. This leaves the array in a funny state that is best avoided.
1 | function array_del() { |
[ 'a', <1 empty item>, 'c', 'd' ] 4
[ 'a', 'c', 'd' ] 3
MAP
Map is a litte different with Array, map uses keys as index while Array uses number.
1 | function map_demo() { |
Map { 'b' => 2 } 1 2 true
item: b 2
b 2
b 2
b
Enum
There is no Enum in javacript at all, use object to simulate it
1 | function enum_demo() { |
[ 1, 2, 3 ]
Function
arguments
If you pass too many, the extra ones are ignored. If you pass too few, the missing parameters get assigned the value undefined, but you can access all arguments by arguments
.
1 | function test_arg(a, b, c = 12) |
Function closure
This feature—being able to reference a specific instance of a local binding in
an enclosing scope—is called closure. A function that references bindings from
local scopes around it is called a closure
1 | var f2 = (function(){ |
Another case
1 | function makeAdder(a) { |
when makeAdder() is called, a scope object is created with one property: a, which is the argument passed to the makeAdder() function. makeAdder() then returns a newly created function. Normally JavaScript’s garbage collector would clean up the scope object
created for makeAdder() at this point, but the returned function maintains a reference back to that scope object. As a result, the scope object will not be garbage-collected until there are no more references to the function object that makeAdder() returned
.
Arrow function
As js supports annymous function(a function without name), more over, you can even skip function
keyword for annymous function, that’s arrow function =>
, like annymous function, you can use arrow function as a callback directly, or save it as function object, call it later on
There are severls rule to define an arrow function.
parameter rule
- If there are 0 Parameters, arrow functions use empty parenthesis: () => { statements; }
- If there is 1 Parameter, arrow functions can omit the parenthesis around the parameter: parameter => { statements }
- If there are 2+ Parameters, parameters go inside parenthesis: (param1, param2, …) => { statements }
return rule
- If an arrow function is simply
returning a single line of code
, you can omit the statement brackets and the return keyword. - if you arrow function does NOT return, say just long or printing, you can NOT omit brackets, that means brackets is not omitted in most case, with brackents if you want to return a value, you must use
return
keyword, otherwise, undefined is returned.
Definition and Call
1 |
|
jason
hi
undefined
3
undefined
3
Class/Object/object
object
There are two ways to declare a class ES5 way, ES6(ES2015), object is light weighted Object
, object no built-in properties and methods, it’s more effecient thant Object, object behaves like a Map, key:value pairs, but it’s not a map hence object.get('a')
will report error as object no built-in stuff.
object key must be string, but Map key can be anything.
Object.assign() copies the values (of all enumerable own properties) from one or more source objects to a target object. It has a signature of Object.assign(target, …sources).
The target object is the first parameter and is also used as the return value.
- Object.assign() is useful for merging objects or cloning them shallowly.
property
1 | let a = 1, b = 2; |
1 | function object_demo() { |
16 jason
16 jason
16 jason
your name jason
id 16
get_name_again [Function: get_name_again]
get_name [Function: get_name]
get_name_v2 [Function]
{ a: 1, b: 2 }
{ b: 2, c: 3 } 3 2 true
[ 'b', 'c' ]
false
Class
ES5 class
1 | function Person(name) { |
With ES6, add keyword like class, construtor, static, super, extends
1 | class Person { |
1 | function es5_class_demo() { |
jason
cob
2
frank
10
1 | function es6_class_demo() { |
hello 1 prefix_hello
loop properties
- for…in: which returns all the enumerable properties of an object, regardless of whether they are own properties, or inherited from the prototype chain.
- 返回对象自身的和继承的可枚举属性(不含 Symbol 属性)。
- Object.keys(ob): which returns all own, enumerable properties of an object, an ECMA5 method
- 返回一个数组,包括自身的(不含继承) 所有可枚举属性(不含 Symbol 属性)。
- Object.getOwnPropertyNames(obj): which returns all own properties of an object, both enumerable or not
- 返回一个数组,包括自身的(不含继承) 所有属性(不含Symbol属性,但包括不可枚举属性)。
- Object.getOwnPropertySymbols(obj): which returns all own symbol properties of an object, enumerable or not
- 返回一个数组。包含对象自身(不含继承)的所有 Symbol 属性。
- Reflect.ownKeys(obj)
返回一个数组,包含对象所有的属性(不含继承)== 3 + 4 。 - obj.hasOwnProperty(prop): check if a property is inherited or actually belongs to that object
- obj.propertyIsEnumerable(prop) if a property is enumerable.
use Object.defineProperty() to define non-enumerable property
1 | function loop_properties() { |
id
name
12
[ 'id', 'name' ]
[ 'id', 'name', 'get_name' ]
[ Symbol(get_id), Symbol(id) ]
[ 'id', 'name', 'get_name', Symbol(get_id), Symbol(id) ]
true
1 | function getAllPropertyNames(obj) { |
[
'abc', 'xyz',
'foobar', '#',
'constructor', '__defineGetter__',
'__defineSetter__', 'hasOwnProperty',
'__lookupGetter__', '__lookupSetter__',
'isPrototypeOf', 'propertyIsEnumerable',
'toString', 'valueOf',
'__proto__', 'toLocaleString',
'#'
]
[ 'abc', 'xyz', 'foobar', '#' ]
Symbol
A “symbol” represents a unique identifier, it’s mostly used to avoid conflict, you can image it as a unique string
.
1 | // id is a symbol with the description "id" |
That call checks the global registry, and if there’s a symbol described as key, then returns it, otherwise creates a new symbol Symbol(key) and stores it in the registry by the given key.
Symbols don’t auto-convert to a string, and Symbolic properties do not participate in for..in loop.
1 | function symbol_demo() { |
Symbol(id) Symbol(id)
John 10
age 30
get_age [Function: get_age]
30
Iterator/Generator
Iterator
Iterator is an object, with next method, it wrapps an object(string, array, map) to make it iterable, so that you can iterate the wrapped object by for/of
, most of time, you did not call iterator at all, but now how see how it works.
1 | // String, Array, Map etc has a property Symbol.iterator which returns an Iterator. |
Iterator Abstract Interface required
First let simulate an Iterator which has next()
method, it returns an object which has two keys value
and done
1 | //user is an object. |
Generator
When you define a function with function* (placing an asterisk after the word function), it becomes a generator. When you call a generator, it returns an iterator
.
Every time you call next on the iterator, the function runs until it hits a yield expression, which pauses it and causes the yielded value to become the next value produced by the iterator. When the function returns (the one in the example never does), the iterator is done.
1 | function generator_demo() { |
{ value: 'hello', done: false }
{ value: 'world', done: false }
{ value: 2, done: true }
hello
world
kk
dd
Async operation
There are couples of ways of syanc operation, from ES5(callback), ES6(Promise), ES7(async/await, really new), most of them just wants to make easier to understand and use, here we go
Promise(ES6)
Create Promise by three ways
- one is use new call resolve or reject based on condition —>common way
- the other two are call resolve() or reject directly
Promise.resolve('hello') and Promise.reject('hello') set Promise's state with Resolved or Rejected!
1 | //Basic Implementation of Promise |
resolve: 2
standard promise API
- catch(): registers a handler to be called when the promise is rejected, this callback can also register by .then(success, fail) as second parameter.
- .then(success, fail): register success or fail,
It returns another promise
, which resolves to the value that the handler function returns or, if that returns a promise, waits for that promise and then resolves to its result
1 | function promise_demo() { |
resolve
8
set timeout 1
reslove timeout 1
async/await
- async ensures that the function returns a promise, and
wraps non-promises in it
, nothing to do for promise return, console.log(async_function()), it shows promise!!! await makes JavaScript wait until that promise settles and returns its result
- If it’s an error, the exception is generated — same as if throw error were called at that very place.
- Otherwise, it returns the resolved result not promise.
Note:
await only works inside an async function, await won’t work in the top-level code as the top-level is not a async function.
await
literally
makes JavaScript wait until the promise settles, and then go on with the result. that doesn’t cost any CPU resources, because the engine can do other jobs in the meantime: execute other scripts, handle events.
async/await function no longer, like a regular JavaScript function, runs from start to completion in one go. Instead, it can be frozen at any point that has an await, and can be resumed at a later time
async/await aims to replace Promise.then().catch which is hard to understand
typical use for async/wait
1 | async function f() { |
Guide
When we use async/await, we rarely need .then, because await handles the waiting for us. And we can use a regular try..catch instead of .catch. That’s usually (but not always) more convenient
1 | function async_wait_demo() { |
Promise { 1 }
spread destructing operator
These are special cases for Array and object, shorthand.
1 | function operator_demo() { |
resolved data: 1
1
2
set timeout 32
[ 1, 2, 3 ]
{ a: 1, b: 2 }
[ 2, 3 ]
s t r
1 2 4
1 2 { oc: 3 }
1 2 3
1 2 3 { c: 3, d: 4 }
1 2 3 3
Modules
ES5
ES5 commonJS way used by node
1 | //one symbol(default) |
1 | //several symbols |
ES6
ES5 has severals way to export and import for a module while ES6 defines a standard way, here we go.
It only loads the required at compiling, you can load some exported symbols or all.
1 | import {stat as fileStat, readFile} from 'fs'; |
export ways
1 | //fs.js |
default export
Each module can only has one default export which has no export name(actuall it’s default
name)
1 | //fs.js |
Node finding module
1 | # js search module in such path order(current, global) |
Low-leve API for buffer
In some case, you may want to manipulate on buffer(bytes level) like in network programming, JS supports this by providing low-level API Binary buffer
and DataView
.
for in vs for of
The for…in statement iterates over the
enumerable properties(include inherited) of an object
, in anarbitrary order
different js engine may produce different result, it used tocheck attribute(key) of object
, the each key is a string!!!The for…of statement iterates over
values that the iterable object(string, array, map)
defines to be iterated over,get the value of each iterator object
like string, array, map!
Be Careful
- Make sure
not to modify an object while enumerating its properties with a for...in loop
. - Use a while loop or classic for loop instead of a for…in loop when iterating over an object whose contents might change during the loop.
1 | function for_in_of_demo() { |
string 0
string 1
string 2
string foo
string arrCustom
0
1
2
foo
3
5
7
let vs const vs var
let and const declarations allow you to create block-scoped variables
A variable declared with the var keyword is available from the function
it is declared in.
1 | // myVarVariable *is* visible out here |
var special
without declaration to access a variable, a global variable is defined after that access
, it's valid non strict mode
even it’s not good way to do so.
var Declaration Hoisting
The interpreter pulls all variable declarations to the top of its scope. It also allows you to use redundant var declarations without penalty.
1 | function foo() { |
equal to below
1 | function foo() { |
1 | function test() { |
15
undefined
15
set timeout 64
set timeout 128
[ 1, 2 ]
let
let is not hoisted
1 | console.log(age); // ReferenceError: age is not defined |
A let declaration also does not allow for any redundant declarations within a block scope. Doing so will result in an error:
1 | var name; |
const
1 | for (const i = 0; i < 10; ++i) {} // TypeError: assignment to constant variable |