Said in the previous
Limited to this is a self-examination manual, the answer is not so detailed, if there is a link under a knowledge point, and they have not in-depth understanding, should click the link or search in-depth understanding.
Two other parts:
- Front end test questions self-test Vue web browser performance optimization part
- Front end test question self – check algorithm design mode operating system part
JS
type
Simple data types for JavaScript
Number
, String
, Boolean
, Undefined
, Null
, Symbol
The return value of the Typeof operator
- number
- string
- boolean
- undefined
- object
- function
- symbol
Typeof NaN returns number
Typeof NULL also returns object, which is a legacy issue
Why can numbers and strings use methods?
Because numbers and strings are converted to wrapper objects when using methods
A wrapper object is created by its corresponding constructor
(1).toString() // (new Number(1)).toString()
Copy the code
new Number(1) {
__proto__
: Number ,[[PrimitiveValue]]
: 1 }The wrapper object has an internal value [[PrimitiveValue]], which is the original value of the wrapper
This object is destroyed after the expression ends, so you cannot add attributes to strings/numbers
0.1 + 0.2 === 0.3 // false?
0.1 + 0.2! = The principle behind 0.3
-
JS uses IEEE 754 double precision 64 bits to store data, so this problem is not unique to JS
-
64 bits: 1 sign bit, 11 exponent bits, and 52 mantissa bits
JS can say that the largest integer is 2^ 53-1 (52 binary 1s), not 2^ 52-1
-
0.1 and 0.2 behave as infinite loops in binary, so rounding at the end of mantissa bits is called precision loss
-
When the two numbers are added together, the result is a decimal place that ends in 4 instead of 0
The solution
-
ToFixed can be accurate to a certain place, discarding the decimal place
-
Number.EPSILON [‘epsɪl – (-52)]
const isEquel = (a, b) = > Math.abs(a - b) < Number.EPSILON / / equal Copy the code
-
Convert to integer operations
/** * Exact addition */ function add(num1, num2) { const num1Digits = (num1.toString().split('. ') [1] | |' ').length; const num2Digits = (num2.toString().split('. ') [1] | |' ').length; const baseNum = Math.pow(10.Math.max(num1Digits, num2Digits)); return (num1 * baseNum + num2 * baseNum) / baseNum; } add(0.1.0.2); / / 0.3 Copy the code
Type conversions and rules
Go to the Boolean
All but five are converted to true
- undefined
- null
- 0 (including +0 and -0)
- NaN
- “” Empty string
toString
toString(10.2) // "1010" When you enter a number, the second parameter can be in the base
toString(new Date()) // Wed Jan 20 2021 20:06:24 GMT+0800
toString([1.2]) / / 1, 2, ""
Copy the code
The toString method is overridden on many built-in types
Tostring.call (x) === ‘[Object Array]’
valueOf
- Null and undefined cannot call valueOf without wrapping an object
- The valueOf [[primitiveValue]] in the wrapper object is returned. The valueOf [[primitiveValue]] is returned
- All built-in object types, except for the Date prototype that implements valueOf, return something like:
1536416960724
The number of milliseconds since midnight on January 1, 1970; Nothing else is customObject.prototype.valueOf
, returns the caller itself.
toPrimitive
A built-in function for converting an object to its original value. Symbol. ToPrimitive overrides an object’s conversion to its original value
It has a parameter hint, which typically has two passable values “number” and “string”, which are passed in or out internally depending on the context
- “Number” : Call valueOf before toString
- “String” : toString is called before valueOf
- Non-date objects are passed “number” by default, and Date objects are passed “string” by default; But it’s actually called
toString
For more detailed transformation of objects, see the toPrimitive Abstract Operation in the toPrimitive ECMAScript7 specification
Go to the number
-
Boolean, true goes to 1 false goes to 0
-
Null goes to 0, undefined goes to NaN
-
string
- If the string contains only numbers (including the hexadecimal format “0x”), convert it to the corresponding decimal.
- If the string is empty,
""
or"\n"
, return 0. - In other cases, convert to NAN
-
Object, calls the ToPrimitive method, PreferredType takes “number”, i.e
1. Call the valueOf method
2. Call toString
3. Go to string
Object to a digital instance
Number([1]) // 1
1. [1].valueof () returns [1]
2. [1]. ToSting () returns “1”
3. “1” becomes “1”
Number([1,1]) // NaN
1. [1, 1].valueof () returns [1, 1]
2. [1,,1].tosting () returns “1,1”
3. “1,1” is converted to NaN
Implicit conversions and valueOf, toString
When javascript converts an object to a basic type, it calls the internal function ToPrimitive to do the conversion.
There are two points
- Non-date type first
valueOf
后toString
. - The Date type first
toString
后valueOf
Considering that both types actually call toString and valueOf doesn’t change the output (except for the wrapper type),
So implicit conversions to the default object are calledtoString
[] = =false // true [] first call toString to convert to "", "" Boolean is false! []// false
{} + 1 // [object Object]1
Copy the code
The cast type in the symbol is implicitly converted
a +
The transformation of the b
Select * from table where object is not wrapped
Left and right values combine \ symbols | + |
---|---|
string number | number -> string |
string boolean | boolean -> string |
string object | object -> object.toString() |
number boolean | boolean -> number |
number object | number -> string,object -> object.toString() |
boolean boolean | boolean -> number |
boolean object | boolean -> string,object -> object.toString() |
object object | object -> object.toString() |
null number | null -> 0 |
null object | null -> “null”,object -> object.toString() |
null boolean | null -> 0,boolean -> number |
null string | null -> “null” |
null null | 0 |
undefined number | undefined -> NaN |
undefined object | undefined -> “undefined”,object -> object.toString() |
undefined boolean | undefined -> NaN,boolean -> number |
undefined string | undefined -> “undefined” |
undefined undefined | NaN |
undefined null | NaN |
Note that undefined to number converts to NaN, and NULL converts to 0
According to the permutation and combination in the above table, we can see:
1. Convert an object (non-wrapper) to a string first (actually call toPrimitive)
Pay special attention to the Date object, which is also converted to a string
new Date() + 1 // "Fri Mar 19 2021 10:59:08 GMT+0800"
Copy the code
2. One side is a string, and the other side is converted to a string
1 + 1 = "1"
3. A Boolean value on one side and a number or Boolean value on the other. The Boolean value is converted to a number
4. Null or undefined on one side, string or number on the other, follow the other side; If neither, null or undefined is converted to a number first
undefined + true // NaN
null + true // 1
Copy the code
5. Retrieve the rule from top to bottom until both sides are strings or numbers.
Pay attention to+a
andb + a
, the conversion of a is different: +a is converted to number, while b +a needs to be converted and added according to the above rules
a = =
The transformation of the b
Object (non-wrapper) comparison or comparison of different types:
2. On one side, the object first calls toString (actually toPrimitive) 3. When one side is a Boolean value converted to the number 4. When both sides are a number and a string, the string is converted to the number 5. Continue to retrieve rules from top to bottom until both sides are of the same type.
Other situations
null= =undefined // True undefined and NULL do not work with other false values' == '
NaN= =NaN // False to determine NaN, number.isnan should be used
Copy the code
The instance
-
‘true’ == true // false
- If 3 is met, true is converted to 1
- Conforms to 4, “true” is converted to NaN
- NaN == 1 returns false
-
[] = =! [] // true
-
! [] convert to false: convert to true for all Boolean types except 0, “”, NaN, undefined, null, and null, and then convert to false
-
If 2 and 3 are matched, [] is converted to “”, and false is converted to 0
-
If 4 is met, “” goes to 0
-
0 == 0 returns true
-
Built-in language
About the Symbol
ES6 Introduction #Symbol
Symbol is a unique value that acts as a key to an object and prevents the property from being overwritten or overwritten by an existing property
By writing apply, we can use Symbol as the key to prevent overwriting attributes on passed functions
function myApply(ctx,args = []){
if(typeof this! = ='function') {
throw new TypeError('not a function! ')}const symbol = Symbol(0)
ctx[symbol] = this
constresult = ctx[symbol](... args)delete ctx[symbol]
return result
}
Fuction.prototype.apply = myApply
Copy the code
Its second function is that it gives us the possibility to access built-in methods and override built-in behavior.
Symbol stores the keys for the various built-in methods,
By overriding an iterator on a class, you can change the behavior of an instance using an iterator such as
class Collection {
*[Symbol.iterator]() {
let i = 0;
while(this[i] ! = =undefined) {
yield this[i]; ++i; }}}let myCollection = new Collection();
myCollection[0] = 1;
myCollection[1] = 2;
for(let value of myCollection) {
console.log(value);
}
Copy the code
The iterator (iterator)
An iterator is an object that conforms to the following specification
-
The next function is accessible on the
-
The next function returns {value, done}, where value is the value of the current iteration, and done is a Boolean value indicating whether the iteration is over
-
Iterator objects can be iterated explicitly by repeated calls to next (). Iterating over an iterator is said to consume the iterator because it is usually executed only once. After generating the termination value, additional calls to next () should continue to return {done: true}.
var it = makeIterator(['a'.'b']); it.next() // { value: "a", done: false } it.next() // {value: "b", done: false} {value: "b", done: false it.next() // { value: undefined, done: true } function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false}, {value: undefined.done: true}; }}; }Copy the code
Iterator interface
ES6 specifies that the default Iterator interface is deployed on the data structureSymbol.iterator
Property, or as long as a data structure hasSymbol.iterator
Property is considered “traversable.”
It’s a function that returns an iterator.
We can access it through Symbol. Interator
let arr = ['a'.'b'.'c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
Copy the code
The data structure with the native Iterator interface is as follows.
- Array
- Map
- Set
- String
- TypedArray
- The Arguments object for the function
- The NodeList object
Generator function
Generators were replaced by async functions shortly after they appeared, and I learned async syntax all over the place.
But it’s important to understand the basic syntax, because it has to do with iterators, which in turn has to do with for of, deconstruction, and so on;
At the same time async is the syntax sugar of generator function, after understanding the principle of Gennerator async principle is also very easy to understand.
Syntax for Generator functions
Generator and iterator [MDN]
What does the generator generate? Generating iterator
Generator functionfunction * name{}
Is a function that returns an iterator that automatically maintains its own state.
Basic usage
-
Add * to the function keyword to declare the generator function. When the generator function is called, it returns an iterator.
-
Yield is the point at which execution is suspended after the next call to the iterator.
-
The result of the expression after yield is returned as the value of next;
-
The argument passed to NEXT is the result of the entire yield expression at the previous NEXT pause
-
The last return of the generator function has no yield effect, but it is retained on the value of the object returned by the first subsequent call to next
function* f() {
for (let i=0; i<3; i++){
if(yield i) yield 10 Return and record the state of the function
}
return 20
}
const iter = f()
iter.next() {value:0,done:false}
iter.next() // {value:1,done:false}
iter.next(true) {value:10,done:false} {value:10,done:false} {value:10,done:false} {value:10,done:false
iter.next(true) // {value:2,done:false} The previous yield is yield
iter.next() {value:20,done:true} return value 20 is saved
iter.next() //{value:undefined,done:true}
Copy the code
We can easily write the iterator interface through a generator
class O {
constructor(p = []) {
p.forEach(([key, value]) = > (this[key] = value))
}
*[Symbol.iterator]() {
const keys = Object.keys(this)
for (let i = 0; i < keys.length; i++) {
yield this[keys[i]]
}
}
}
const c = new O([
['a'.1],
['b'.2],
['c'.3]])for (let value of c) {
console.log(value)
}
/ / 1 2 3
Copy the code
Yield * [Iterator] The Iterator delegate
Delegate an iteration to another iterator
let delegatedIterator = (function* () {
yield 'Hello! ';
yield 'Bye! '; } ());let delegatingIterator = (function* () {
yield 'Greetings! ';
yield* delegatedIterator;
yield 'Ok, bye.'; } ());for(let value of delegatingIterator) {
console.log(value);
}
// "Greetings!
// "Hello!"
// "Bye!"
// "Ok, bye."
Copy the code
See Generator function syntax for raising an error, and methods on the prototype
Principle of the Generator function
In addition to the state machine model consisting of Switch cases, the closure technique is used to store generator function context information.
Regenerator wraps generator functions with utility functions, adding methods such as next/return to them. At the same time, the returned generator object is wrapped so that calls to methods such as next will eventually enter the state machine model composed of Switch cases. In addition, the closure technique is used to save the context information of the generator function.
Learn more about Generators
Simple implementation
Async/Await/Generator implementation principle
// The generator function splits the code into switch-case blocks based on yield statements, and then executes each case separately by switching between _context.prev and _context.next
function gen$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return 'result1';
case 2:
_context.next = 4;
return 'result2';
case 4:
_context.next = 6;
return 'result3';
case 6:
case "end":
return_context.stop(); }}}// Low configuration context
var context = {
next:0.prev: 0.done: false.stop: function stop () {
this.done = true}}// Invoke with low configuration
let gen = function() {
return {
next: function() {
value = context.done ? undefined: gen$(context)
done = context.done
return {
value,
done
}
}
}
}
// Test use
var g = gen()
g.next() // {value: "result1", done: false}
g.next() // {value: "result2", done: false}
g.next() // {value: "result3", done: false}
g.next() // {value: undefined, done: true}
Copy the code
Async functions and Generator functions
Async/Await/Generator implementation principle
As we know, async functions are the syntax-sugar of generator functions, and they differ in three ways
- Async /await comes with an executor that automatically performs the next step without manually calling next()
- The async function returns a Promise object, and the Generator returns a Generator object
- Await returns the resolve/reject value of the Promise
function run(gen) {
// Wrap the return value as a promise
return new Promise((resolve, reject) = > {
var g = gen()
function _next(val) {
// Error handling
try {
var res = g.next(val)
} catch(err) {
return reject(err);
}
if(res.done) {
// Return the last return value
return resolve(res.value);
}
// Res. value is wrapped as a promise to be compatible with yield followed by a primitive type
Promise.resolve(res.value).then(
val= > {
// The next function is automatically executed by executing _next recursively
_next(val);
},
err= > {
// Throw an error
g.throw(err)
});
}
_next();
});
}
function* myGenerator() {
try {
console.log(yield Promise.resolve(1))
console.log(yield 2) / / 2
console.log(yield Promise.reject('error'))}catch (error) {
console.log(error)
}
}
const result = run(myGenerator) // The result is a Promise
// Output 1 2 error
Copy the code
Prototype chain
How to determine the array type?
-
xxx instanceof Array
-
xxx.construtor === Array
-
Array.isArray(xxx) === true
-
Object.prototype.toString.call(xxx) === ‘object Array’
Describe the process of new
1. Create a new object
2. This points to the new object
3. Execute the code, which assigns a value to this
4. Return to this
The principle of instanceof
instance instanceof constructor
-
__proto__ (instance) and constuctor (prototype) refer to the same object
-
If not, continue up the prototype chain for instance
function myInstanceof(l, r) { while (l) { if (l.__proto__ == r.prototype) { return true } l = l.__proto__ } return false } Copy the code
Object
-
Object.prototype.entries: Returns an array of all enumerable property name and value pairs for the Object itself.
-
Object.keys() : returns the keys of all the enumerable properties of the Object itself.
-
Json.stringify () : Serializes only the enumerable properties of the object itself.
-
Object.assign() : Ignore enumerable as false and copy only the enumerable properties of the Object itself.
Pay special attention to
For in iterates over the properties on the prototype and needs to work with hasOwnProperty
for (let key in obj) {
if (obj.hasOwnProperty(key)){
// dosomething}}Copy the code
inheritance
There are several inheritance methods in ES5
JS prototype chain and inheritance don’t get asked again
-
Prototype chain inheritance
The disadvantage of assigning a subclass stereotype to an instance of the parent class is that the subclass cannot change the parameters passed to the constructor of the parent class, and when the stereotype chain contains a stereotype of a reference type value, the value of that reference type is shared by all instances.
Child.prototype = new Parent('parent'); Copy the code
-
Constructor internal inheritance
Call the superclass function in the subclass constructor and pass this and the arguments. The disadvantage is that you can only inherit the properties given in the superclass constructor
function Child(){ Parent.call(this.'yellow'); // This code implements partial inheritance through the constructor, binding this and executing the parent constructor this.type = 'child'; } Copy the code
-
Composite inheritance (combining prototype chain inheritance and constructor inheritance)
-
Original type inheritance
Inside the object() function, we create a temporary constructor, pass in the object as the prototype for the constructor, and finally return a new instance of the temporary type.
function object(o){ function F(){} F.prototype = o; return new F(); } var person = { friends : ["Van"."Louis"."Nick"]};var anotherPerson = object(person); Copy the code
-
Parasitic inheritance
function createAnother(original){ var clone = object(original);// Create a new object by calling the object function clone.sayHi = function(){// Enhance the object in some way (enhance: add properties or methods to it) alert("hi"); }; return clone;// Return this object } Copy the code
-
Combinatorial parasitism
- The first step is to assign the stereotype of the subclass to an empty object whose stereotype is the parent class and change its constructor property. This step is used to drag the subclass onto the stereotype chain of the parent class
- The second step is the same as constructor internal inheritance: call the superclass function in the subclass constructor and pass this and the arguments
function extend(subClass,superClass){ var prototype = object(superClass.prototype);// Create an object whose prototype is that of the parent class prototype.constructor = subClass;// Enhance the object subClass.prototype = prototype;// Specify an object } function Father(name){ this.name = name; } Father.prototype.sayName = function(){ alert(this.name); }; function Son(name,age){ Father.call(this,name);}}}}}}}}}}}}}}}}}}}} this.age = age; } //Son.prototype = new Father(); // Extend instead of creating a new instance of the superclass extend(Son,Father); Copy the code
ES6 class
inheritance
A subclass instance inherits the properties and methods of a superclass instance
-
When a subclass inherits, the super method must be called inside the constructor, executing the constructor of the superclass (same as in ES5 constructor inheritance).
class Point { constructor(x, y) { this.x = x; this.y = y; }}class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // Error will be reported if no call is made this.color = color; }}Copy the code
-
Prototype chain inheritance
-
Constructors as objects, the properties of constructors, namely static methods, are inherited
// Both of the above are post-extends JS auto-completion class A {} class B extends {} A.prototype // {} No attribute A.prototype.__proto__ === B.prototype // True is equivalent to the extends method of combinatorial parasitism B.__proto__ === A // this allows B to access static methods on A Copy the code
scope
How does JavaScript support block-level scope
Variable ascension
- Variable declarations: unbundle declarations and assignments, with declarations promoted to the top of the scope and assignments left in place
- Function declaration: The function declaration is clipped to the front of the scope (after the variable declaration).
- If variable declaration, declaration will be promoted; Function declarations are converted to variable declarations, and declarations are promoted.
What is the difference between a let and a var?
-
Var is function scope, let is block-level scope
-
Var has variable promotion, let has no variable promotion
To be precise, the creation of both lets and var is promoted, but the let is not accessible until the original announcement, which is the reason for the temporary dead zone
-
Lets cannot declare the same variables in the same scope; var does not
-
Let declarations in the global environment will not be mounted on Windows while var declarations will
A temporary dead zone for a let
Temporary dead zone: in a block-level scope, a variable declared by a let cannot access a variable of the same name on the scope chain in the area before the declaration.
A declaration and assignment statement in JS that has three states:
1. Create
The creation is completed before the function begins execution and it is not yet accessible, but it intercepts access to the function context and reports an error
let
Only the creation is completed before the function executes
2. The initialization
After initialization, the variable can be accessed and its value is undefined; The var variable is created and initialized before the function executes,
let
Is initialized at the original clause
3. The assignment
Var and let are assigned in the original sentence
What is a closure?
Simply put, any function that references a free variable and is not destroyed is a closure
A free variable is one that is neither an argument to a function nor a declared variable
How do you use closures in practice?
- Fixed the problem of setTimeout in the for loop printing index with the same final value
- Callbacks use closures to change external variables
- Storing private variables
- Throttling, anti – shake function
- Higher order components of React
Further closures
Scope chains and closures: How does the JavaScript engine choose when the same variable appears in the code
A free variable belongs to the call context at or below this level on the call stack, but it is not destroyed with the call context.
The compiler creates a closure as follows:
1. Before each function executes, it compiles and creates an execution context
2. If a function definition is found inside, the function is quickly scanned. If the function uses free variables, the function is determined to be a closure and the closure object of the execution context to which the free variables belong is created, which is an internal object stored in the heap space.
3. Mount the free variable to the closure object. If any subsequent free variables use the execution context, they will also be mounted to the closure object of the execution context; An execution context corresponds to a closure object
4. Variables that are not used by internal functions remain on the stack
Why do closures cause memory leaks?
A closure that is not destroyed will not destroy any closure objects associated with it.
If the closure is not executed, the object will continue to occupy memory.
Why are closures a memory leak when using variables?
A function that creates a variable uses a variable, and a closure that uses a variable on the closure variable uses a variable. Both have the same purpose and both use memory. Why is the latter a memory leak?
First, variables created during function execution are created at execution time and are destroyed with the context of the call. The closure object associated with the closure is symbiotic with the closure, occupying a block of memory whether or not the closure is executed.
Second, when the closure is executed, the closure variable is used, which is not a memory leak. When the closure is not executed, the closure variable cannot be accessed by the outside world and keeps occupying memory, then it is a memory leak.
this
The point of this?
- The global environment points to window
- The global call function points to window
- An object call function points to an object
- The arrow function points to the external this
When called as a variable, this points to window, not to the context in which the function was called
For more information on how reference affects this, see JavaScript In-depth interpretation of this from the ECMAScript specification
Apply, call, and bind
What do these three do?
- Apply and call are used to execute a function and force it to change the reference to this. The difference is in the way the arguments are written
- Bind generates a mandatory binding to the function referred to by this based on the arguments passed in
Event loop
Why distinguish between macro and micro tasks?
If a large number of tasks are executed, the callback of some tasks is delayed (all of them are at the end of the queue). As a result, the application effect is delayed. So the designer divides the task into macro task and micro task, and the micro task can be carried out in the macro task.
Which are macro tasks and micro tasks
Macro task:
-
Script execution
-
Event callback
-
setTimeout/setInterval
-
requestAnimationFrame
Micro tasks:
- promise.then
- MutationObserver (for monitoring DOM changes)
Describe the event loop
Execute a macro task, and then execute the microtasks generated from the macro task. If a microtask is generated from the microtask, the microtask is executed until the queue of microtasks is cleared, and then the next cycle is started
See event loops for more details
- Tasks, microtasks, queues and schedules
- This time, understand the JavaScript execution mechanism thoroughly
Questions about Promise and async
async function foo() {
console.log('foo')}async function bar() {
console.log('bar start')
await foo()
console.log('bar end')}console.log('script start')
setTimeout(function () {
console.log('setTimeout')},0)
bar();
new Promise(function (resolve) {
console.log('promise executor')
resolve();
}).then(function () {
console.log('promise then')})console.log('script end')
Copy the code
1. Initialize foo and bar in the main coroutine, and print script start when you encounter console.log;
2. Resolve to setTimeout, initialize a Timer, and create a new task
3. Execute the bar function, give control to the coroutine, output bar start, encounter await, execute foo, output foo, create a Promise to return to the main coroutine
4. Add the returned promise to the microtask queue, execute new Promise, output Promise Executor, and return Resolve to the microtask queue
5. Output script end
6. Check the microtask queue before the end of the current task, execute the first microtask, and hand the controller to the coroutine and output bar end
7. Execute the second microtask and output promise then
8. After the current task is completed, enter the next task and output setTimeout
Note in particular that when await non-Promise values, it implicitly creates a Promise instance with the value resolve
The Promise of the API
Promise[MDN]
Promise.all(iterable)
This method returns a new Promise object that will only be triggered if all promise objects in the iterable object succeed, or if any promise object in the iterable object fails. The new promise object, after triggering the success state, returns an array of all promise returns from iterable as the success callback, in the same order as iterable. If the new Promise triggers a failure state, it will use the error message from the first promise in the iterable that triggers a failure as its failure error message. The promise. all method is often used to handle the state collection of multiple Promise objects.
Promise.race(iterable)
First, race returns a promise; When any of the iterable promises succeeds or fails, Race passes the promise’s success return value or failure details as arguments to the resolve or reject promise returned by Race.
So, if a Promise instance in the array executes quickly, it inherits the result and state of the execution, whether it succeeds or fails
/ / race method
Promise.race = function(promises){
return new Promise((resolve,reject) = >{
for(let i=0; i<promises.length; i++){ promises[i].then(resolve,reject) }; })}//all (get all promises, execute then, put the results in an array, return them together)
Promise.all = function(promises){
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
i++;
if(i == promises.length){
resolve(arr);
};
};
return new Promise((resolve,reject) = >{
for(let i=0; i<promises.length; i++){ promises[i].then(data= >{
processData(i,data);
},reject);
};
});
}
Copy the code
Promise is a specification compliant implementation
One of the most detailed handwritten Promise tutorials ever
/ / source
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value= > {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn= >fn()); }};let reject = reason= > {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn= >fn()); }};try{
executor(resolve, reject);
} catch(err) { reject(err); }}then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
onRejected = typeof onRejected === 'function' ? onRejected : err= > { throw err };
let promise2 = new Promise((resolve, reject) = > {
if (this.state === 'fulfilled') {
setTimeout(() = > {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch(e) { reject(e); }},0);
};
if (this.state === 'rejected') {
setTimeout(() = > {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch(e) { reject(e); }},0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() = > {
setTimeout(() = > {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch(e) { reject(e); }},0);
});
this.onRejectedCallbacks.push(() = > {
setTimeout(() = > {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch(e) { reject(e); }},0)}); }; });return promise2;
}
catch(fn){
return this.then(null,fn); }}function resolvePromise(promise2, x, resolve, reject){
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if(x ! =null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y= > {
if(called)return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, err= > {
if(called)return;
called = true; reject(err); })}else{ resolve(x); }}catch (e) {
if(called)return;
called = true; reject(e); }}else{ resolve(x); }}Copy the code
Extension: VUE asynchronous batch update
NextTick: MutationObserver is just a cloud, microTask is the core!
The changes are collected by watcher. Watcher puts itself in the array to be updated. The callback function in this macro task called this. After the macro task finishes, the nextTick callback array is executed in the microtask. The first function executed in the nextTick callback array is the Watcher array to notify the update vm instance to update, and then the nextTick callbacks collected are executed in sequence.
Call the microtask in the form: promise.resolve or MutationObersever
Handwritten code
Handwritten EmitEvent
class EventEmitter {
constructor() {
this.events = {}
}
on(eventName, callback = () => {}, once = false) {
// const name = !! once ? 'onceEvents' : 'events'
if (typeofcallback ! = ='function')
throw new Error('callback must be a function')
if (typeofeventName ! = ='string')
throw new Error('eventName must be a string')
if (this.events[eventName] === undefined) this.events[eventName] = []
this.events[eventName].push({
callback,
once
})
}
once(eventName, callback) {
this.on(eventName, callback, true)}off(eventName, callback) {
if (typeofeventName ! = ='string')
throw new Error('eventName must be a string')
const nameOfevent = this.events[eventName]
if (Array.isArray(nameOfevent)) {
this.events[eventName] =
typeofcallback ! = ='function'
? []
: nameOfevent.filter(e= >e.callback ! == callback) } }emit(eventName, ... args) {
if (typeofeventName ! = ='string')
throw new Error('eventName must be a string')
const nameOfevent = this.events[eventName]
if (Array.isArray(nameOfevent)) {
for (const e of nameOfevent) {
e.callback.apply(this, args)
}
this.events[eventName] = nameOfevent.filter(e= >! e.once) } } }Copy the code
Hand throttle
The principle of throttling function:
- Closures store the private variable lock
- Function run after the lock, and set the timer to unlock
The complex edition of JavaScript topics follows underscore learning to reduce costs
// Throttling function
/ / lite version
function throttle(fn, { interval = 500 } = {}) {
let lock = false
return function (. args) {
if (lock) return false
lock = true
setTimeout(() = > {
lock = false
}, interval)
return fn.apply(this, args)
}
}
export function throttle(fn, {
interval = 500
} = {}) {
if (typeoffn ! ="function") return new Error("Type error");
const _self = fn;
let timer,
firstTime = true; // Whether to call for the first time
return function(. args) {
const _me = this;
if (firstTime) {
fn.apply(_me, args);
return (firstTime = false);
}
if (timer) {
return false;
}
timer = setTimeout(() = > {
clearTimeout(timer);
timer = null;
_self.apply(_me, args);
}, interval);
};
}
Copy the code
Handwriting anti – shake debounce
Anti – shaking function timer version principle:
- Save the timer reference timer with a closure
- Clear the timer when called
- Generate a new timer
Record the time of the previous run
Learn shock-protection with underscore
// Start to execute the program only for the first time
function debounce(fn, { immediate = 500 } = {}) {
let timestamp = 0
return function (. args) {
const pre = timestamp
timestamp = Date.now()
// if (! pre) return
if (timestamp - pre >= immediate) return fn.apply(this, args)
}
}
// The delayed execution scheme only executes the last time and the last time is also delayed
function debounce(fn, delay) {
let timer = null
return function (. args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() = > fn.apply(this, args), delay)
}
}
/ / [JavaScript project follow the underscore learn stabilization] https://github.com/mqyqingfeng/Blog/issues/22
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this;
var args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
// If it has already been executed, do not execute it
varcallNow = ! timeout; timeout =setTimeout(function(){
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}}Copy the code
Write apply and bind by hand
Implement apply and then bind
apply
function myApply(ctx,args = []){
if(typeof this! = ='function') {
throw new TypeError('not a function! ')}const symbol = Symbol(0)
ctx[symbol] = this
constresult = ctx[symbol](... args)delete ctx[symbol]
return result
}
Fuction.prototype.apply = myApply
Copy the code
bind
function myBind(ctx,... preArgs){
const fn = this
return (. args) = > fn.apply(ctx,[...preArgs,...args])
}
Function.prototype.bind = myBind
Copy the code
Write a curry,
Currying functions: fixed function parameters, reduced parameter input, privatization of parameters; Improve the function parameter applicability, reduce generality;
- Fn. length gives you the number of arguments to the function
- Decide whether to continue curry or execute based on the number of arguments received
- Notice the connection of the parameters
function curry(fn, ... args) {
// Continue to accept parameters and then curify
return args.length < fn.length ? (. params) = > {
returncurry(fn, ... args, ... params) } : fn(... args) }Copy the code
Handwritten deep copy
- Array and object type distinctions are created and then recursed
- The original type is returned directly
/ / a simple version
function deepCopy(obj) {
if (typeof obj == "object") {
const result = obj.constructor === Array ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) result[key] = deepCopy(obj[key])
}
return result
} else return obj;
}
// How to solve the circular reference?
function deepCopy(obj) {
// Use map to tag objects to avoid infinite loops
const map = new Map(a)function traverse(obj) {
if (typeof obj == 'object' && !map.get(obj)) {
map.set(obj, true)
const result = obj.constructor === Array ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) result[key] = traverse(obj[key])
}
return result
} else return obj
}
return traverse(obj)
}
Copy the code
The handwritten VIRTUAL Dom generates real Dom nodes
The idea is exactly the same as deep copy, recursive traversal
AppendChild (createElement(child)) = depCopy (obj[key])
// Assume the structure of the virtual DOM
/ / {
// tag:'div', // element tag
// attrs:{// attribute
// class:'a',
// id:'b'
/ /},
// text:' I am content ', // text content
// children:[] // child element
// }
function createElement(virtualDom) {
const { tag, attrs, text, children } = virtualDom
const el = document.createElement(tag)
Object.keys(attrs).forEach(key= > el.setAttribute(key, attrs[key]))
if(text ! = =null|| text ! = =undefined) el.innerText = text
for (let child of children) {
el.appendChild(createElement(child))
}
return el
}
Copy the code
Write a new
- Built-in this
- Setting the This prototype
- Executive function
- Return value judgment
// The trigger class used to trigger the microtask uses setTimeout normally
class MicTaskTrigger {
constructor(callback = () => {}) {
this.counter = 1
this.node = document.createTextNode(String(this.counter))
this.callback = callback
this.observer = new MutationObserver(() = > {
this.callback()
})
this.observer.observe(this.node, {
characterData: true})}changeCallback(callback) {
this.callback = callback
}
trigger(callback = () => {}) {
this.callback = callback
this.counter = (this.counter + 1) % 2
this.node.data = String(this.counter)
}
}
const mic = new MicTaskTrigger() // Mic is a trigger that triggers a microtask
class MyPromise {
constructor(fn) {
// Three states
this.state = 'pending' // fulfilled rejected
this.value = undefined
this.reason = undefined
this.ResolvedCallbacks = []
this.RejectedCallbacks = []
let resolve = value= > {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
mic.trigger(() = >
this.ResolvedCallbacks.forEach(callback= >
callback.call(this.this.value)
)
)
}
}
let reject = value= > {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = value
if (this.RejectedCallbacks.length)
mic.trigger(() = > {
this.RejectedCallbacks.forEach(callback= >
callback.call(this.this.reason)
)
})
else throw this.reason
}
}
// Automatically execute functions
try {
fn.call(this, resolve, reject)
} catch (e) {
reject(e)
}
}
// then
then(onFulfilled, onRejected) {
if (typeof onFulfilled === 'function') {
// If the state is already determined, the callback is executed when the then call is made
if (this.state === 'fulfilled')
return mic.trigger(() = > onFulfilled.call(this))
this.ResolvedCallbacks.push(onFulfilled)
}
if (typeof onRejected === 'function') {
if (this.state === 'rejected')
return mic.trigger(() = > onRejected.call(this))
this.RejectedCallbacks.push(onRejected)
}
}
catch(onRejected) {
this.then(null, onRejected)
}
}
const promise = new MyPromise((resolve, reject) = > {
console.log(111)
resolve({ data: 100 })
})
promise.then(res= > console.log(++res.data))
promise.then(res= > console.log(++res.data))
Copy the code
Write a Promise
-
Completion of asynchronous execution callback, then and catch single call into the callback, state fixed call then direct callback;
No chained calls, no handling for cases where the return value is a Promise, no error bubbling and no error handling within then
-
state
- State Current state
- The value passed in by the value call resolve, which is the result of success
- The reason call rejects the incoming value, which is the result of a failure
- ResolvedCallbacks collect successful callbacks
- RejectedCallbacks failed to collect callbacks
-
Inside the constructor
-
Resolved and Rejected change the state and put the callback function in the event queue while in the pending state
-
We execute the function passed by the user in a try-catch, passing in the above two functions and giving the user the right to change the state
-
Reject is called in catch
-
-
Collect the incoming success and failure callbacks in the then function; If the status is determined, the incoming callback function is put in the queue without collection
-
Catch execute this.then(null, onRejected)
// The trigger class used to trigger the microtask uses setTimeout normally
class MicTaskTrigger {
constructor(callback = () => {}) {
this.counter = 1
this.node = document.createTextNode(String(this.counter))
this.callback = callback
this.observer = new MutationObserver(() = > {
this.callback()
})
this.observer.observe(this.node, {
characterData: true})}changeCallback(callback) {
this.callback = callback
}
trigger(callback = () => {}) {
this.callback = callback
this.counter = (this.counter + 1) % 2
this.node.data = String(this.counter)
}
}
const mic = new MicTaskTrigger() // Mic is a trigger that triggers a microtask
class MyPromise {
constructor(fn) {
// Three states
this.state = 'pending' // fulfilled rejected
this.value = undefined
this.reason = undefined
this.ResolvedCallbacks = []
this.RejectedCallbacks = []
let resolve = value= > {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
mic.trigger(() = >
this.ResolvedCallbacks.forEach(callback= >
callback.call(this.this.value)
)
)
}
}
let reject = value= > {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = value
if (this.RejectedCallbacks.length)
mic.trigger(() = > {
this.RejectedCallbacks.forEach(callback= >
callback.call(this.this.reason)
)
})
else throw this.reason
}
}
// Automatically execute functions
try {
fn.call(this, resolve, reject)
} catch (e) {
reject(e)
}
}
// then
then(onFulfilled, onRejected) {
if (typeof onFulfilled === 'function') {
// If the state is already determined, the callback is executed when the then call is made
if (this.state === 'fulfilled')
return mic.trigger(() = > onFulfilled.call(this.this.value))
this.ResolvedCallbacks.push(onFulfilled)
}
if (typeof onRejected === 'function') {
if (this.state === 'rejected')
return mic.trigger(() = > onRejected.call(this.this.reason))
this.RejectedCallbacks.push(onRejected)
}
}
catch(onRejected) {
this.then(null, onRejected)
}
}
const promise1 = new MyPromise((resolve, reject) = > {
console.log(111)
setTimeout(() = > resolve({ data: 100 }), 5000)
})
promise1.then(res= > console.log(++res.data))
promise1.then(res= > console.log(++res.data))
Copy the code
Array flattening
let arr = [[1.2.2], [6.7.8[11.12[12.13[14]]].10]]
/ / native
arr = arr.flat(infinity)
/ / the recursive method
function flatten(arr){
let res = []
arr.forEach(item= > {
// Check whether item is an array
if(Array.isArray(item)) res = res.concat(flatten(item))
else res.push(item)
})
return res
}
Copy the code
SetTimeout implementation setInterval
Because of the event loop mechanism, setInterval can cause two or more tasks to be executed much less than the setInterval
For example, perform a computation-intensive task after setting the setInterval to execute; At the first point in time, a callback of setInterval is pushed into the macro task queue while the intensive calculation task is still incomplete. At the second point in time, the second callback of setInterval is pushed into the macro task queue. At this time, the two tasks in the macro task queue are connected, resulting in the situation that the two tasks are executed in succession much less than the setInterval.
The principle of setInterval is a recursive call within the callback of setTimeout, which can ensure that the interval between the execution of two tasks is at least greater than the setInterval.
Detailed can see “JavaScript advanced programming” 22.3 advanced timer
// Simple implementation
function mySetInterval(fn, millisec){
function interval(){
setTimeout(interval, millisec);
fn();
}
setTimeout(interval, millisec)
}
// Add the number of execution times and cancel the timer
class MySetInterval {
constructor(fn, { interval, count = Infinity } = {}) {
this.fn = fn
this.interval = interval
this.count = count
this._count = 0 // Use count
this._isOn = false
this._timer = null
}
_interval() {
this._timer = setTimeout(() = > this._interval(), this.interval)
this.fn()
if(+ +this._count === this.count) this.off()
}
on() {
if (this._isOn) return
this._isOn = true
this._timer = setTimeout(() = > this._interval(), this.interval)
}
off() {
if (!this._isOn) return
this._isOn = false
this._count = 0
clearTimeout(this._timer)
this._timer = null}}const itt = new MySetInterval(() = >console.log(111), {interval:1000.count:5 })
itt.on() / / 111 * 5
itt.on() / / 111 * 3
itt.off() // Stop follow-up
Copy the code
Handwritten response
let obj = {}
let input = document.getElementById('input')
let span = document.getElementById('span')
// Data hijacking
Object.defineProperty(obj, 'text', {
configurable: true.enumerable: true.get() {
console.log('Got the data')},set(newVal) {
console.log('Data updated')
input.value = newVal
span.innerHTML = newVal
}
})
// Input listen
input.addEventListener('keyup'.function(e) {
obj.text = e.target.value
})
Copy the code
V – show
How to use native JS to implement a simplest V-show directive?
Don’t panic when you see the problem. What you are looking for is the above response
<button onClick="model.isShow = true">According to</button>
<button onClick="model.isShow = false">hidden</button>
<div v-show="isShow">Hello World!</div>
<script>
// Step 1: Define data and views
var model = {
isShow: false
}
var view = document.querySelector('div')
// Step 2: Define the view refresh method
var updateView = function(value) {
view.style.display = value ? ' ' : 'none'
}
// Step 3: Set the initial view representation
var directiveKey = view.getAttribute('v-show')
updateView(model[directiveKey])
// Step 4: Listen for data changes, and then refresh the view to achieve data-driven purposes
Object.defineProperty(model, 'isShow', {
set: function(val) {
updateView(val)
}
})
</script>
Copy the code
The CSS and HTML
How to understand HTML semantics?
- Increase code readability
- Good for search engine crawler analysis
- The complete page structure can be rendered even if the CSS fails to load
CSS selectors with weights
CSS selector weights detailed
The selector | An expression or example | instructions | The weight |
---|---|---|---|
The ID selector | #aaa | 100 | |
Class selectors | .aaa | 10 | |
Label selector | h1 | Elements of the tagName | 1 |
Property selector | [title] | See here, | 10 |
Adjacent selector | selecter + selecter | Split into two selectors and calculate | |
Brother selector | selecter ~ selecter | Split into two selectors and calculate | |
Parent selector | selecter > selecter | Split into two selectors and calculate | |
Descendant selector | selecter selecter | Split into two selectors and calculate | |
Wildcard selector | * | 0 | |
Various pseudo-class selectors | Such as :link, :visited, :hover, :active, :target, :root, :not, etc | 10 | |
Pseudo-elements | Such as: the first letter, : : first – line, : : after, : : before and: : selection | 1 |
- 1,0,0,0 > 0,99,99,99. That is to say, compare each level from left to right, only if the previous level is equal.
- Comparisons are made according to this rule, whether inline, internal, or external. Instead of the intuitive interline > Inside > Outside style; ID > class > element. The reason for this illusion is that it is true that the weight of the first row is the highest, so it has the highest weight. The internal style may generally be written after the external style reference, so it overrides the previous one.
- In the case of the same weight, the later style overrides the previous style.
- Of wildcards, sub-selectors, adjacent selectors, etc. Although the weight is 0000, it also takes precedence over inherited styles, and the 0 weight takes precedence over unauthorized values.
What is the difference between border-box and Content-box?
-
offsetWidth = border + padding + width
-
When box-sizing:border-box is set, offserWidth = width = border + padding + content, content is the space left
The default IE box model is border-box
The superposition of magin
When two vertical margins meet, they will merge into one margin
-
The sibling nodes margin-top and margin-bottom will overlap
-
Margin-top overlay or margin-bottom overlay for parent and child nodes
-
An element has no content, margin or border, and its margin-top and margin-bottom will overlap
Margin-top :20px margin-bottom:20pxCopy the code
-
In the previous case, the overlapped vertical margins will also overlap with the margins of other elements
For example, multiple P labels with empty contents are superimposed
<p><p> <p>1<p> <p><p> <p><p> <pCopy the code
-
In the second case, the parent node overlaps the parent node’s sibling node after stacking the parent node’s vertical margins
Solution: Using BFC to wrap one of the sibling nodes eliminates the stack situation
Margin negative
- Margin-left and margin-top are negative, which affect themselves and fall into the preceding elements
- Margin-right and margin-bottom are negative and affect the following elements, which are trapped in themselves
BFC
Format context [MDN]
What is the BFC? What are its features?
BFC (Block Format Content) Block level format context, box model layout CSS rendering mode, refers to a separate render area or is an isolated independent container.
The BFC generates a new rendering layer that solves the sibling margin folding problem because they are not at all on the same level.
Features:
-
The upper and lower margins of two adjacent containers belonging to the same BFC will overlap
-
The margin-left of the element touches the border-left of its containing block
-
The BFC region does not overlap with the float element
-
The float element is also counted when calculating the BFC height
-
Child elements within the BFC region do not affect external elements
What are the conditions for BFC?
- Float to none
- Position is absolute or fixed
- The overflow is not visible
- Display is flex, inline-block, and so on
Absolute and relative positioning basis
-
Relative to oneself
-
Absolute based on the most recent has been positioning (postion: relative and absolute, fixed) ancestor element
Flex
Flex Layout tutorial: Syntax section
Flex Layout tutorial: Examples
Flex properties
- Flex-direction Specifies the main axis direction. Row column Row-reverse Column-reverse
- The flex – wrap a newline
- Autocrate-content How is the main axis content arranged
- Flex-start Start end alignment
- Flex-end Aligns the end
- Center Aligns the center end
- Space-between Is aligned so that items are equally spaced between each other
- Space-around Equal spacing on both sides of each project. As a result, the space between items is twice as large as the space between items and borders
- How do the alignment-items cross axes align
flex-start
: Aligns the starting points of the intersecting axes.flex-end
: The end point alignment of the cross axis.center
: Midpoint alignment of intersecting axes.baseline
: Baseline alignment of the first line of text for the project.stretch
(Default) : If the project has no height set or is set to AUTO, it will take up the entire container height.
- Align-content How do elements in multiple lines align
- Self-align How does the cross axis of a single item align the property the same as that of an align-items
Flex: 1?
CSS elastic box ——- Details of the three brothers: Flex-grow, Flex-shrink, and Flex-basis
Flex: 1 allocates the main axis size of the parent box, which is actually short for three properties
- flex-grow: 1;
- flex-shrink: 1;
- flex-basis: auto;
The following default Flex-direaction is: Row, where the size on the main axis is the width
flex-basis
The semantics are the width of the base of the box,
Determine the width of a subbox with a priority higher than width. For example, flex-basis:200px; Width :100px, flex-basis 200px is preferred
flex-grow
The semantics are how does the box grow
When the width of the parent element is greater than the sum of the widths of the children, how do the children allocate the remaining width of the parent element, i.e. grow up over the size of the basis element?
Flex: 1 splitting parent boxes is where Flex-grow comes in
Formula:
Remaining width = parent width – sum of flex – basis for each child element
Self in flex-grow = self flex-grow/sum of child flex-grow
Width = Flex-basis + Remaining width * Flex-grow ratio
flex-shrink
The semantics are how does the box shrink
When the width of the parent element is less than the sum of the widths of the child elements, how the child element shrinks beyond the width of the parent element.
Excess width = sum of flex – basis for each child element – width of the parent
The flex-Shrink weighting ratio = the flex-Shrink weighting of itself/the sum of the flex-Shrink weights of each child element
The weight is flex-basis, flex-shrink weight = flex-shrink * flex-basis
Formula: Width = Flex-basis – excess width * Flex-shrink weighted ratio
In the middle
(horizontal, vertical, horizontal vertical) in the middle
-
Position + margin(suitable for the corresponding width and height)
.h{ position:absolute; left:50%; margin-left: -25px; /* Half the width of the box */ } .v{ position:absolute; top:50%; margin-top: -25px; /* Half the width of the box height */ } .vh{ position:absolute; top:50%; left:50% margin-top:-25px; margin-left: -25px; } Copy the code
-
position + tansform
.h{ position:absolute; left:50%; transform:translate(-50%.0); } .v{ position:absolute; top:50%; transform:translate(0, -50%); } .vh{ position:absolute; top:50%; left:50% transform:translate(-50%, -50%); } Copy the code
-
flex
.f{ /* Parent box */ display:flex } .h{ justify-content:center } .v{ align-items:center } .vh{ justify-content:center; align-items:center; } Copy the code
Two species uniquely centered horizontally
-
margin: 0 auto; Suitable for subboxes of certain width
-
Converts to an inline block element
.h{ display:inline-block; text-align:center; } Copy the code
Perpendicular centered unique
- Line-height is set to the height
Unique to the horizontal and vertical center
.vh{
/* Browser compatibility is guaranteed */
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
margin:auto;
}
Copy the code
floating
Remove the floating
I’m going to add to the next element
.clear{
clear:all
}
Copy the code
Add to the parent box
.clear:after{
clear:all
}
Copy the code
Add overflow trigger BFC to parent box (float element is also counted when calculating BFC height)
.box{
overflow:hidden
}
Copy the code
How to inherit line-height?
-
Write directly to a size such as 18px or 20px and inherit directly
-
Direct write ratio such as 1 or 1.5, direct inheritance
-
When writing percentages such as 200%, convert to the parent element line-height and inherit the size instead of inheriting the percentage
.f{ font-size:20px; line-height:200%; } .son{ font-size:16px; } /* The height of the child element is 40px */ Copy the code
The mobile terminal
What is REM?
Px: absolute pixel
Em: based on the font-size of the parent element
Rem: based on the font size of the root HTML element
How to implement responsiveness?
CSS responsive
/* Set font size */ in the media Query to the width of the screen
@media only screen and (max-width: 320px) {html {
font-size: 5px ! important; }}@media only screen and (min-width: 320px) {html {
font-size: 5px ! important; }}@media only screen and (min-width: 384px) {html {
font-size: 6px ! important; }}@media only screen and (min-width: 480px) {html {
font-size: 7.5 px. ! important; }}/* When rem is in units,1rem = 5px */
Copy the code
Js dynamic Settings
// Preexecute, the initialization resize event does not execute
setRem()
// The original configuration
function setRem () {
let doc = document.documentElement
let width = doc.getBoundingClientRect().width
let rem = width / 75
doc.style.fontSize = rem + 'px'
}
// Listen for window changes
addEventListener("resize", setRem)
Copy the code
Vh and VW understand
First understand screen viewport height [window.screen.height] and web viewport height [window.innerheight]
The former is the height of the entire phone screen, the latter is used to display web content after removing the navigation bar height;
window.innerHeight = 100vh
xcss
How is RPX calculated?
After the applet is compiled, RPX will do a px conversion. The conversion is based on 375 physical pixels, which means that under a screen of 375 physical pixels wide, 1rpx = 1px.
For example: the iPhone6 screen is 375px wide and has 750 physical pixels, so 1rpx = 375/750 px = 0.5px.