Learned notes from coderwhy’s JavaScript Advanced Syntax video lesson
If there is a mistake or inappropriate place, please forgive me, welcome to point out and expand, thank you
1. Enhancement of literals
var name = 'xxx'
var age = 12
var obj = {
// 1. Property shorthand
name: name,
age,
// 2. Method shorthand
foo: function () {
console.log(1)},foo2: () = > {
console.log(2)},foo3() {
console.log(3)},// how do you define the property name?
[name + 123] :'yyy'
}
obj.foo() / / 1
obj.foo2() / / 2
obj.foo3() / / 3
obj[name + 456] = 'zzz'
console.log(obj)
/ / {
// name: 'xxx',
// age: 12,
// foo: [Function: foo],
// foo2: [Function: foo2],
// foo3: [Function: foo3],
// xxx123: 'yyy',
// xxx456: 'zzz'
// }
Copy the code
2. Destructuring
- An array of deconstruction
var arr = ['aaa'.'bbb'.'ccc']
// The previous practice
// var a1 = arr[0]
// var a2 = arr[1]
// var a3 = arr[2]
// 1
var [a1, a2, a3] = arr
console.log(a1, a2, a3) //aaa bbb ccc
// 2
var [, , a4] = arr
console.log(a4) //ccc
// 3. Deconstruct an element and place the following elements in a new array
var [a5, ...newArr] = arr
console.log(a5, newArr) //aaa [ 'bbb', 'ccc' ]
// The default value for destructuring
var [a6, a7, a8, a9 = 'ddd'] = arr
console.log(a6, a7, a8, a9) //aaa bbb ccc ddd
Copy the code
- Object to deconstruct
var obj = {
name: 'xxx'.age: 123.address: 'in guangdong'
}
//1
var { name, age, address } = obj
console.log(name, age, address) / / XXX 123 in guangdong province
//2
var { age } = obj
console.log(age) / / 123
// 3
var { age: newAge } = obj
console.log(newAge) / / 123
// The default value for destructuring
var { color: newColor = 'red' } = obj
console.log(newColor) //red
//5
function foo(o) {
console.log(o.name, o.age) //xxx 123
}
foo(obj)
function foo2({ name, age }) {
console.log(name, age) //xxx 123
}
foo2(obj)
function foo3({ name, age=456}) {
console.log(name, age) //xxx 123
}
foo3(obj)
Copy the code
Let and const
- The basic grammar
// Let and var are both used to declare a variable
let bar = "bar"
// 2, const constant(constant/measure)
const name = "abc"
/ / 3.
// Note 1: Const is essentially a passed value that cannot be modified
// But if you pass a reference type (memory address), you can use the reference to find the corresponding object, to modify the internal properties of the object, this is ok
const obj = {
foo: "foo"
}
obj2.foo = "aaa"
console.log(obj.foo)// aaa
/ / 4.
// Note 2: Variable names defined by let/const are not repeatable
// let foo = "abc"
// let foo = "cba"
Copy the code
- Scope lifting
-
When the lexical context of the execution context is created, the variable is actually created, but it cannot be accessed in advance.
-
So we take it literally: in the scope of a declared variable, if the variable can be accessed before the declaration, then we can call it scope-raising.
// scope promotion: can be accessed ahead of time
console.log(foo)// undefined
var foo = "foo"
// let/const they are not scoped
// Foo is created but cannot be accessed
// Reference()Error: Cannot access 'foo' before initialization
console.log(foo)
let foo = "foo"
Copy the code
- Let, const, and window
- We know that declaring a variable globally via var actually adds a property to the window, but let/const does not add any property to the window.
- Version specifications based on earlier ECMA:
- Each execution context is associated with a variable object (VO), and variable and function declarations in source code are added to VO as properties. For and functions, arguments are also added to VO.
- In the latest version of the ECMA specification, some terms have been modified:
- Each execution context is associated with a VariableEnvironment (VE) to which variable and function declarations in the executing code are added as Environment records. For and functions, parameters are also added to the variable environment by the environment record.
This means that variables and environment records we declare are added to the variable environment, but the standard does not specify that the object is a Window object or any other object, so the JS engine will have its own implementation when parsing. For example, v8 actually implements their storage through a hashMap of VariableMap (VE->variables_).
What about the window object? The Window object is an early GO object, but in the latest implementations it is actually a global object added by the browser, and the value equality between window and var has always been maintained.
var a = 123
let b = 456
console.log(window.a) / / 123
console.log(window.b) //undefined
Copy the code
4. Scope
- ES5 scope (there is no block-level scope in ES5)
In ES5 only two things are scoped
// 1. Global scope
// 2. Function (local) scope
function foo() {
var bar = "bar"
}
Copy the code
- ES6 scope (added a block-level scope)
// ES6 code block-level scope
// Let /const/function/class declaration type is valid
{
let foo = 'why'
function demo() {
console.log('demo function')}class Person {}}console.log(foo) // foo is not defined
// Different browsers have different implementations (most browsers have no block-level scope for function to be compatible with previous code)
demo() //demo function
var p = new Person() // Person is not defined
Copy the code
// The code for the if statement is block-level scope
if (true) {
var foo = 'foo'
let bar = 'bar'
}
console.log(foo) //foo
console.log(bar) //bar is not defined
// switch statement code is also block-scoped
var color = 'red'
switch (color) {
case 'red':
var foo2 = 'foo'
let bar2 = 'bar'
}
console.log(foo2) //foo
console.log(bar2) //bar2 is not defined
// 3. The code for statement is also block-scoped
for (var i = 0; i < 10; i++) {
console.log('Hello World' + i)
// Hello World0
// Hello World1
// Hello World2
// Hello World3
// Hello World4
// Hello World5
// Hello World6
// Hello World7
// Hello World8
// Hello World9
}
console.log(i) / / 10
for (let j = 0; j < 10; j++) {}
console.log(j) //j is not defined
Copy the code
- Application scenarios of block-level scopes
Two ways to print different button numbers by clicking different buttons.
const btns = document.getElementsByTagName('button')
Var has no block-level scope
for (var i = 0; i < btns.length; i++) { ; (function (n) {
btns[i].onclick = function () {
console.log('the first' + n + 'One button gets clicked.')
}
})(i)
}
// let has block-level scope
for (let i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
console.log('the first' + i + 'One button gets clicked.')}}Copy the code
- The addition of block-level scope
const names = ['abc'.'cba'.'nba']
// 1, we can't use const, because each loop of I (generating a block-level scope) is different, and we need to assign I ++ from the last I to the next I
for (let i = 0; i < names.length; i++) {
console.log(names[i])
}
/ / 2, for... Of: New traversal number group (object) in ES6
// Because the value of each iteration (generating a block-level scope) is assigned to an item, the value of the previous item is not required to operate
for (const item of names) {
console.log(item)
}
Copy the code
- Let and const temporary dead zones
In ES6, we also have a concept called temporary dead zone: it means that variables declared by let and const in a code are not accessible until they are declared. We call this phenomenon temporal dead zone (TDZ).
var foo = 'foo'
// block-level scope
if (true) {
console.log(foo) //Cannot access 'foo' before initialization
let foo = 'abc'
}
Copy the code
- Var, let, const options
- Use of var:
- We need to be aware of the fact that var is unique: scope-raising, window global objects, and the lack of block-level scope are all legacy issues;
- It was actually a language flaw in JavaScript from the beginning of its design;
- For let, const:
- For lets and const, this is currently recommended in development;
- Const is preferred to ensure that data security cannot be tampered with.
- Use let only when it is clear that a variable will need to be reassigned later;
- This is the norm in many other languages, and we try to follow it;
5. Template substring
- The basic use
// ES6 concatenates strings and other identifiers before
const name = 'why'
const age = 18
const height = 1.88
console.log('my name is ' + name + ', age is ' + age + ', height is ' + height)
// ES6 provides template strings
/ / 1.
const message = `my name is ${name}, age is ${age}, height is ${height}`
console.log(message)
/ / 2,
const info = `age double is ${age * 2}`
console.log(info)
/ / 3.
function doubleAge() {
return age * 2
}
const info2 = `double age is ${doubleAge()}`
console.log(info2)
Copy the code
- Tag template string
// The first argument is still the entire string in the module string, but it is cut into multiple pieces and placed in an array
// The second argument is the first ${} in the module string.
function foo(m, n, x) {
console.log(m, n, x)
}
// Another way to call a function: label module string
foo` ` //[ '' ] undefined undefined
foo`Hello World` //[ 'Hello World' ] undefined undefined
const name = 'why'
const age = 18
foo`Hello${name}Wo${age}rld` //[ 'Hello', 'Wo', 'rld' ] why 18
Copy the code
6, functions,
- The default argument to the function
ES6 can provide default values for function arguments
function foo(m = 'aaa', n = 'bbb') {
console.log(m, n)
}
foo(0)// 0 bbb
// 2. Object parameters and default values and deconstruction
function printInfo({ name, age } = { name: 'why', age: 18 }) {
console.log(name, age)
}
printInfo({ name: 'kobe'.age: 40 }) //kobe 40
// Another way to write it
function printInfo1({ name = 'why', age = 18 } = {}) {
console.log(name, age)
}
printInfo1() //why 18
// 3. Parameters with default values are best left last
function bar(x, y, z = 30) {
console.log(x, y, z)
}
bar(10.20) / / 10 20 to 30
// 4. The length attribute of the function with a default value
function baz(x, y, z, m, n = 30) {
console.log(x, y, z, m, n)
}
console.log(baz.length)/ / 4
Copy the code
- The remainder of the function
function foo(m, n, ... args) {
console.log(m, n) / / 20 to 30
console.log(args) //[40, 50, 60]
console.log(arguments) //[Arguments] { '0': 20, '1': 30, '2': 40, '3': 50, '4': 60 }
}
foo(20.30.40.50.60)
//function foo (... args,m, n)
// Rest Paramaters must be put last
// Rest parameter must be last formal parameter
Copy the code
- Arrow function
Arrow functions have no explicit prototype, so they cannot be used as constructors to create objects using new.
function foo() {}
console.log(foo.prototype) / / {}
const f = new foo()
console.log(f.__proto__) / / {}
var bar = () = > {
console.log(this.arguments) // The arrow function itself does not have one
}
console.log(bar.prototype) //undefined
const f2 = new bar() //bar is not a constructor
Copy the code
7. Expand the grammar
const names = ['abc'.'cba'.'nba']
const name = 'why'
const info = { name: 'why'.age: 18 }
// 1
function foo(x, y, z) {
console.log(x, y, z)
}
// foo.apply(null, names)foo(... names)//abc cba nbafoo(... name)//w h y
// 2. Construct an array
const newNames = [...names, ...name]
console.log(newNames) //[ 'abc', 'cba', 'nba', 'w', 'h', 'y' ]
// 3. Construct object literals for ES2018(ES9)
constobj = { ... info,address: 'Guangzhou'. names }console.log(obj)
/ / {
// '0': 'abc',
// '1': 'cba',
// '2': 'nba',
// name: 'why',
// age: 18,
// address: 'guangzhou'
/ /}
Copy the code
- The expansion syntax is a shallow copy
const info = {
name: 'why'.friend: { name: 'kobe'}}constobj = { ... info,name: 'coderwhy' }
// console.log(obj)
obj.friend.name = 'james'
console.log(info.friend.name) //james
Copy the code
8. Numerical representation
const num1 = 100 / / decimal
// b -> binary
const num2 = 0b100 / / binary
// o -> octonary
const num3 = 0o100 / / octal
// x -> hexadecimal
const num4 = 0x100 // Hexadecimal
console.log(num1, num2, num3, num4) //100 4 64 256
// A large numeric concatenator (ES2021 ES12)
const num = 10 _000_000_000_000_000
console.log(num) / / 10000000000000000
Copy the code
9. Basic use of Symbol
- Before ES6, object property names are strings, so it is easy to cause the property name conflict, such as the original one, we hope to add a new attribute and value, but we were not sure what its original internal content, it is easy to cause conflict, so as to cover it inside a property;
- Symbol is a basic data type added to ES6. Translated as a Symbol, it is used to generate a unique value. Symbol creates values that are different even if they are created multiple times. The Symbol value is generated through the Symbol function, which can be used as the attribute name. That is, in ES6, the attribute name of the object can be a string or a Symbol value.
- We can also pass in a description when creating a Symbol value, which is a new feature in ES2019 (ES10).
Before ES6, the object's property name (key)
var obj = {
name: 'why'.friend: { name: 'kobe' },
age: 18
}
obj['newName'] = 'james'
console.log(obj) //{ name: 'why', friend: { name: 'kobe' }, age: 18, newName: 'james' }
// Use the Symbol in ES6
const s1 = Symbol(a)const s2 = Symbol(a)console.log(s1 === s2) //false
// In ES2019(ES10), Symbol also has a description.
const s3 = Symbol('aaa')
console.log(s3.description) //aaa
// 3.Symbol value as key
// 3.1. Used when defining object literals
const obj2 = {
[s1]: 'abc',
[s2]: 'cba'
}
// 3.2. New attributes
obj2[s3] = 'nba'
/ / 3.3. Object. DefineProperty way
const s4 = Symbol(a)Object.defineProperty(obj2, s4, {
enumerable: true.configurable: true.writable: true.value: 'mba'
})
console.log(obj2[s1], obj2[s2], obj2[s3], obj2[s4]) //abc cba nba mba
// Note: cannot pass. Grammar to obtain
console.log(obj2.s1) //undefined
// 4. Use Symbol as the attribute name of the key
/ / need Object. GetOwnPropertySymbols to get all the key Symbol
console.log(Object.keys(obj2)) / / []
console.log(Object.getOwnPropertyNames(obj2)) / / []
console.log(Object.getOwnPropertySymbols(obj2)) //[ Symbol(), Symbol(), Symbol(aaa), Symbol() ]
const sKeys = Object.getOwnPropertySymbols(obj2)
for (const sKey of sKeys) {
console.log(obj2[sKey])
// abc
// cba
// nba
// mba
}
// 5.Symbol.for(key)/Symbol.keyFor(symbol)
const sa = Symbol.for('aaa')
const sb = Symbol.for('aaa')
console.log(sa === sb) //true
const key = Symbol.keyFor(sa)
console.log(key) //aaa
const sc = Symbol.for(key)
console.log(sa === sc) //true
Copy the code
10 and the Set
Before ES6, there are two main data structures for storing data: array and object. In ES6, another two data structures are added: Set and Map, as well as their other forms WeakSet and WeakMap. A Set is a new data structure that can be used to store data, similar to an array except that its elements cannot be duplicated. To create a Set we need to use the Set constructor (there is no literal way to create it yet).
- Set common attributes:
- Size: Returns the number of elements in the Set;
- Set common methods:
- Add (value) : Adds an element and returns the Set object itself;
- Delete (value) : Deletes elements equal to this value from a set, returning Boolean;
- Has (value) : Determines whether an element exists in a set. Returns Boolean.
- Clear () : clears all elements of the set without returning a value;
- ForEach (callback, [, thisArg]) : pass through set by forEach;
- Also Set is support for… Ergodic of.
- The basic use
1. Create a Set structure
var set = new Set()
set.add(2)
set.add(2)
set.add(30)
set.add(40)
set.add(2)
set.add(230)
console.log(set) //Set(4) { 2, 30, 40, 230 }
// 2. Add objects with special attention:
// These are two different variables
set.add({})
set.add({})
console.log(set) //Set(6) { 2, 30, 40, 230, {}, {} }
// obj stores the address, set stores the element does not duplicate
const obj = {}
set.add(obj)
set.add(obj)
console.log(set) //Set(7) { 2, 30, 40, 230, {}, {}, {} }
// 3. Remove duplicate elements from array
const arr = [43.10.26.30.43.26.10]
// 3.1 The first method
// const newArr = []
// for (const item of arr) {
// if (newArr.indexOf(item) ! = = 1) {
// newArr.push(item)
/ /}
// }
// 3.2 The second method
const arrSet = new Set(arr)
// const newArr = Array.from(arrSet)
const newArr = [...arrSet]
console.log(newArr) //[43, 10, 26, 30]
/ / 4. The size attribute
console.log(arrSet.size) / / 4
// 5.Set method
// add
arrSet.add(1000)
console.log(arrSet) //Set(5) { 43, 10, 26, 30, 1000 }
// delete
arrSet.delete(43)
console.log(arrSet) //Set(4) { 10, 26, 30, 1000 }
// has
console.log(arrSet.has(100)) //false
// clear
// arrSet.clear()
console.log(arrSet) //Set(0) {}
// 6. Iterate through Set
arrSet.forEach(item= > {
console.log(item)
/ / 10
/ / 26
/ / 30
/ / 1000
})
for (const item of arrSet) {
console.log(item)
/ / 10
/ / 26
/ / 30
/ / 1000
}
Copy the code
11, WeakSet
Another data structure similar to Set is called WeakSet, which is also a data structure in which internal elements cannot be repeated.
- So what’s the difference from Set?
- Difference 1: WeakSet can only store object types, not basic data types;
- Difference two: The reference of WeakSet to elements is a weak reference. If there is no other reference to an object, then GC can recycle the object.
- Common methods of WeakSet:
- Add (value) : Add an element, return the WeakSet object itself;
- Delete (value) : Deletes the element equal to the value from WeakSet, and returns Boolean;
- Has (value) : Judge whether there is an element in WeakSet and return Boolean type.
const weakSet = new WeakSet(a)// 1. Difference 1: Only object types can be stored
// TypeError: Invalid value used in weak set
// weakSet.add(10)
// 2. Difference 2: A weak reference to an object
let obj = {
name: 'why'
}
const set = new Set(a)// create a strong reference
set.add(obj)
// create a weak reference
weakSet.add(obj)
console.log(weakSet)// WeakSet { <items unknown> }
// 3. Application scenario of WeakSet
const personSet = new WeakSet(a)class Person {
constructor() {
personSet.add(this)}running() {
if(! personSet.has(this)) {
throw new Error('Running method cannot be called on objects not created by constructors')}console.log('running~'.this) //running~ Person {}}}let p = new Person()
p.running()
// Throw an exception
// p.running.call({ name: 'why' })
Copy the code
If obj=null, even though the 0xa00 object has a reference. But because it is a weak reference, the GC will still reclaim the 0xa00 object.
12, the Map
- The new data structure is Map, which is used to store mappings. Before, we could use objects to store mappings. What’s the difference between them?
- In fact, our object store mapping can only use string (Symbol added in ES6) as attribute name (key);
- In some cases we might want to use a different type of key, such as an object, which is automatically converted to a string as the key;
- Common attributes of Map:
- Size: Returns the number of elements in the Map;
- Common methods of Map:
- Set (key, value) : Adds keys and values to the Map and returns the entire Map.
- Get (key) : obtains the value in the Map based on the key.
- Has (key) : Checks whether a key is included. Returns a Boolean type.
- Delete (key) : Deletes a key-value pair based on the key, returning a Boolean type.
- Clear () : Clears all elements;
- ForEach (callback, [, thisArg]) : traverses the Map through forEach;
- A Map can also be traversed by for of.
// 1. You cannot use objects as keys in JavaScript objects
const obj1 = { name: 'why' }
const obj2 = { name: 'kobe' }
const info = {
[obj1]: 'aaa',
[obj2]: 'bbb'
}
console.log(info) //{ '[object Object]': 'bbb' }
// 2.Map allows us to use object types as keys
// The use of the constructor
const map = new Map()
map.set(obj1, 'aaa')
map.set(obj2, 'bbb')
map.set(1.'ccc')
console.log(map)
// Map(3) {
// { name: 'why' } => 'aaa',
// { name: 'kobe' } => 'bbb',
// 1 => 'ccc'
/ /}
const map2 = new Map([
[obj1, 'aaa'],
[obj2, 'bbb'],
[2.'ddd']])console.log(map2)
// Map(3) {
// { name: 'why' } => 'aaa',
// { name: 'kobe' } => 'bbb',
// 2 => 'ccc'
/ /}
// 3. Common attributes and methods
console.log(map2.size) / / 3
// set
map2.set('why'.'eee')
console.log(map2)
// Map(4) {
// { name: 'why' } => 'aaa',
// { name: 'kobe' } => 'bbb',
// 2 => 'ddd',
// 'why' => 'eee'
/ /}
// get(key)
console.log(map2.get('why')) //eee
// has(key)
console.log(map2.has('why')) //true
// delete(key)
map2.delete('why')
console.log(map2)
// Map(3) {
// { name: 'why' } => 'aaa',
// { name: 'kobe' } => 'bbb',
// 2 => 'ddd'
// }
// clear(), all clear
// map2.clear()
// console.log(map2)
// 4. Iterate through the map
map2.forEach((item, key) = > {
console.log(item, key)
// aaa { name: 'why' }
// bbb { name: 'kobe' }
// ddd 2
})
for (const item of map2) {
console.log(item[0], item[1])
// { name: 'why' } aaa
// { name: 'kobe' } bbb
// 2 ddd
}
for (const [key, value] of map2) {
console.log(key, value)
// { name: 'why' } aaa
// { name: 'kobe' } bbb
// 2 ddd
}
Copy the code
13, WeakMap
WeakMap, another data structure of the Map type, also exists in the form of key-value pairs.
- So what’s the difference with Map?
- Difference 1: WeakMap key can only use objects, and does not accept other types as keys;
- Difference two: WeakMap key thinks the reference to the object is a weak reference. If no other reference refers to the object, then GC can reclaim the object.
- There are four common methods for WeakMap:
- Set (key, value) : Adds keys and values to the Map and returns the entire Map.
- Get (key) : obtains the value in the Map based on the key.
- Has (key) : Checks whether a key is included. Returns a Boolean type.
- Delete (key) : Deletes a key-value pair based on the key, returning a Boolean type.
const obj = {name: "obj1"}
// 1. Difference 2 between WeakMap and Map: Weak reference
const map = new Map()
map.set(obj, "aaa")
const weakMap = new WeakMap()
weakMap.set(obj, "aaa")
// 2. Difference 1: basic data types cannot be used
// weakMap.set(1, "ccc")
// 3
/ / get methods
console.log(weakMap.get(obj))//aaa
/ / from the method
console.log(weakMap.has(obj))//true
/ / delete method
console.log(weakMap.delete(obj))//true
// WeakMap { <items unknown> }
console.log(weakMap)//WeakMap { <items unknown> }
Copy the code
- Usage scenario: The use of WeakMap in the responsive principle (simple implementation)
// Application scenario (vuE3 responsive principle)
const obj1 = {
name: 'why'.age: 18
}
function obj1NameFn1() {
console.log('obj1NameFn1 executed ')}function obj1NameFn2() {
console.log('obj1NameFn2 executed ')}function obj1AgeFn1() {
console.log('obj1AgeFn1')}function obj1AgeFn2() {
console.log('obj1AgeFn2')}const obj2 = {
name: 'kobe'.height: 1.88.address: 'Guangzhou'
}
function obj2NameFn1() {
console.log('obj1NameFn1 executed ')}function obj2NameFn2() {
console.log('obj1NameFn2 executed ')}// 1. Create WeakMap
const weakMap = new WeakMap(a)// 2. Collect dependency structures
// 2.1. Data structures collected for obj1
const obj1Map = new Map()
obj1Map.set('name', [obj1NameFn1, obj1NameFn2])
obj1Map.set('age', [obj1AgeFn1, obj1AgeFn2])
weakMap.set(obj1, obj1Map)
// 2.2. Data structures collected for obj2
const obj2Map = new Map()
obj2Map.set('name', [obj2NameFn1, obj2NameFn2])
weakMap.set(obj2, obj2Map)
// 3. If obj1.name is changed
// Proxy/Object.defineProperty
obj1.name = 'james'
const targetMap = weakMap.get(obj1)
const fns = targetMap.get('name')
fns.forEach(item= > item())
// obj1NameFn1 is executed
// obj1NameFn2 is executed
Copy the code