If only to know the surface of knowledge, that is only understanding. Change Angle, enhance depth, also can be handy is to master

preface

Everything I’ve been reading has been mixed up. I also made some notes, and found that some knowledge points may be more or more important in the interview or project development, so I sorted them out and published an article. Each knowledge point will not be very comprehensive, just for a certain aspect of a slightly in-depth record, or record from a different Angle. If you have any mistakes or other suggestions, please leave them in the comments section

1. Why does CSS parse from right to left? How should it be optimized?

Many of you have probably been asked why browsers parse CSS from right to left, rather than left to right. To put this in plain English: if CSS parses from left to right, browsers get more tired.

Why do you say that? The following code is presented first

<style>
	.demo p span{
		color:#09f;
	}
</style>

<div class="demo">
	<ul>
		<li>
			<a href="javascript:;">This is a</a>
		</li>
	</ul>
	<p>
		<span>This is span</span>
	</p>
</div>
Copy the code

According to the CSS code

Assuming that CSS is parsed from left to right, the process is as follows: starting at.demo, traverse child nodes ul and p, then traverse each child node. It first traverses the ul branch, then traverses li, and finally traverses the leaf node A, and finds that it does not meet the rules, so it needs to go back to ul node, and then traverses the next Li and the next A. If there are 1000 Li and 1000 A, there will be 1000 traversals and backtracking. All this traversal and backtracking is useless and can cause performance problems. Until.demo goes down to node P, then goes down to nodes below p, finds span, styles span, and completes the branch. This is the real deal.

Then look at the match from right to left: first find all the rightmost nodes span, for each span, look up node P, from p to look up node.demo, and finally find the root element HTML to end the branch traversal. So you don’t get a match from left to right, so you go through ul under.demo, you go through li under ul, you go through A under Li, you go through all those useless things.

Obviously, the performance of the two matching rules is very different. The reason for such a situation is that the right-to-left matching filters out a large number of unqualified right-most nodes (leaf nodes) in the first step; The performance of left-to-right matching rules is wasted on failed lookups (e.g., traversing ul under.demo, traversing li under ul, traversing A under li).

Knowing that CSS is rendered this way, any suggestions for optimization?

1.CSS can write as little as possible, such as taking advantage of inherited CSS properties or extracting common styles. Reduce the CSS code and keep the branches of the traversal search as few as possible

2. The CSS path should be as short as possible and should not exceed 4 layers. For example, the path can be written as.demo span. In this way, after finding the span, you can directly find.demo without going through p.

2. Flex is a shorthand for what properties? What does each attribute mean?

First, the Flex attribute sets or retrieves how space is allocated for the children of an elastic box model object. It is a shorthand for the Flex-grow, Flex-shrink, and Flex-basis attributes. The default value is 0. The last two attributes are optional.

If the element is not a child of the elastic box model object, the Flex attribute has no effect

As for what each attribute means, here are specific examples. To help you understand, start with Flex-basis

2-1.flex-basis

The flex-basis property is used to set the scaling base value of an elastic box. You can set the width or percentage. The default value is Auto.

<! DOCTYPEhtml>
<html>
<head>
<meta charset="utf-8"> 
<title>demo</title>
<style> 
.main
{
	width:240px;
	height:300px;
	border:1px solid black;
	display:flex;
}

.item
{
	flex:1 1 auto;
}	
</style>
</head>
<body>

<div class="main">
  <div style="background-color:coral;" class="item red">red</div>
  <div style="background-color:lightblue;" class="item blue">blue</div>  
  <div style="background-color:lightgreen;" class="item green">green</div>
</div>

</body>
</html>
Copy the code

For example, flex:1, 1 auto; So flex-basis is actually auto, and the width of each child element is actually the width of the parent/the number of children. Is 240/3. Each child element is 80px wide.

Flex-basis can be set to a specific width or a percentage. For example, set the red div to Flex-basis :40px;

It looks like this, but why red is 96px is explained below.

2-2.flex-grow

The “remaining space” used to “carve up” the parent element

If the total width of the children is less than the parent, it is divided up

The result above, why is red 96px? Start by setting flex-grow to 0 to see what the initial size of each element is.

As you can see, the red ones are set to flex-basis:40px; So it’s 40px. Blue and green have only one font width, 16px;

Since the width of the child element is 40+16+16=72, less than 240 of the parent element. If flex-grow is set to 1, the remaining width of the parent element (240-72=168) is evenly distributed among the children (168/3=56). So the final child element width is: red =40+56=96px Blue =16+56=72px green =16+56=72px. This explains why flex-basis is set to 40px in red; The resulting width is 96px;

If you set one element, such as the blue flex-grow, to 2, the blue child element, dividing up the remaining parent element, is twice as wide as the red or green one. (It can also be interpreted as dividing the remaining width of the parent element into four parts: 168/4=42, two of which are blue children, and one is red and one is green. Because the flex-grow of the red, blue and green child elements is 1:2:1. It adds up to 4. The resulting width is: blue =16+42*2=100, red =40+42=82, green 16+42=58

2-3.flex-shrink

To “digest” the excess space

Now that you know that flex-grow is used to divide up the remaining parent elements. If the total width of the child element is larger than that of the parent element, flex-shrink is required to shrink the child element accordingly

For example, change the child element’s flex-basis to 100px;

<! DOCTYPEhtml>
<html>
<head>
<meta charset="utf-8"> 
<title>demo</title>
<style> 
.main
{
	width:240px;
	height:300px;
	border:1px solid black;
	display:flex;
}

.item
{
	flex:1 1 100px;
}
</style>
</head>
<body>

<div class="main">
  <div style="background-color:coral;" class="item red">red</div>
  <div style="background-color:lightblue;" class="item blue">blue</div>  
  <div style="background-color:lightgreen;" class="item green">green</div>
</div>

</body>
</html>
Copy the code

But each child element ends up with a width of 80px, which is easy to calculate.

First, the flex-basis of the three children is 100, so the total width of the children is 300, which is 60 more than the width of the parent element (240). So the 60 needs to be “digested” by the child element, because flex:1 1 100px; Flex -shrink is actually always 1 for child elements. The default width (100) – “digested width” (20) = 80, so each child element is 80.

If you set one of the children, such as the green child flex-shrink, to 2. In fact, this is similar to flex-grow, where the extra 60 is divided into four “digested” sub-elements, each of which is 15. Then the green one is divided into two parts, and the red one is divided into one part, and the blue one is divided into two parts. It adds up to 4. So the final calculated width is: red =100-15=85, blue =100-15=85, green: 100-15*2=70

1. Is the width calculated according to flex-grow or flex-shrink? Just focus on the total width of the child element compared to the width of the parent element. If the parent element is wide enough: flex-grow is valid, flex-shrink is invalid. If the parent element is not wide enough: Flex-shrink is valid, flex-grow is invalid.

2. Note that with Flex layout, the float, clear, and vertical-align attributes of the child elements are invalidated.

3. What methods does Javascript use to detect data types?

If you want to break down the data types, there are currently eight data types defined. The basic data types are Number, String, Boolean, Null, undefined, Symbol, bigInt. The reference data type is Object. Object commonly includes Array, Function, Date, RegExp, Map, Set, WeakMap, WeakSet, etc.

With a brief overview of what data types are out there, what methods are currently available to detect data types

3-1.typeof

Specifically, the Typeof operator is suitable for determining whether a variable is string, number, function, Boolean, symbol, bigint, or undefined

However, object is returned if typeof is used to detect null and reference data types other than function

Use typeof to check whether a variable is string, number, function, Boolean, symbol, bigint, or undefined. Typeof is suitable. If it’s other data, Typeof doesn’t help much.

3-2.instanceof

Because Typeof is useful for detecting basic data types, except for NULL. Check for reference data types, function only. Other cases don’t help much.

Instanceof works by checking whether an object’s prototype is on the prototype chain of another object to check. In other words, it detects whether an object is an instance of another object

Like Sou instanceof Parent. For example, to determine whether Son is an instance of Parent.

let Parent =function(){}

let Sou=new Parent()

Sou instanceof Parent //true because Son is Parent
Copy the code

Now, as you probably know, instanceof is used to determine if two objects have an instance relationship. This principle is used for reference type detection.

Next, use instanceof to check if the Sou is an Object

Sou instanceof Object //true
Copy the code

Other reference types can also be detected

[] instanceof Array //true

function fn(){}
fn instanceof Function //true
Copy the code

If the above simple usage, it seems that there is no problem. However, Array and Function exist on the Object prototype chain, so detecting objects with Instanceof may be problematic

[] instanceof Object //true

function fn(){}
fn instanceof Object //true
Copy the code

Many times, we need to know not only whether a variable is a reference type, but also what reference type it is.

3-3.constructor

The constructor property returns the object’s constructor, and the return value is a reference to the function

"Waiting".constructor // Returns the function String
(3).constructor // Return the function Number
false.constructor  // Return function Boolean
Symbol(3).constructor  // Return the function Symbol
42n.constructor // Return the function BigInt
function fn(){}
fn.constructor // return Function
[1.2.3.4].constructor // Returns the function Array
{name:'wait'}.constructor // Return the function Object
new Date().constructor // Return the function Date
Copy the code

If you look at the Number, there’s a bracket around the 3. To keep the browser from confusing the function of. Such as 3. Constructor; It is difficult to distinguish between a decimal point and a dot operator

Constructor determines the data type, which is basically what you need. The null and undefined types cannot be judged because they have no constructor. Error if null or undefined is used.

Another problem is that constructor is lost if an instance of the constructor is created, so constructor is not normally used to detect the type of the constructor

let Parent =function(){}

let Sou=new Parent()

Sou.constructor===Object //false
Sou.constructor===Parent //true
Copy the code

One easy way to avoid this is to rewrite constructor. It just doesn’t work that way

Sou.constructor=Object
Sou.constructor===Object //true
Copy the code

3-4.Object.prototype.toString.call()

The above several methods, seemed more or less has a little defective, then use the Object. The prototype. ToString, call () the way to a solution can be said to be the best, can return the correct data type

Object. The prototype. ToString. Call now found a problem is unable to detect whether a Number is NaN, if is NaN, returns [Object Number]. To detect NaN, use the number.isnan method

4. What problems might async/await cause?

ES6+ introduces async functions to make asynchronous operations more convenient. But it does cause problems if abused like async/await hell. As for what async/await hell is. Let’s start with the following code

(async() = > {// Get user information and friends list based on user ID
  let userID=123
  let userInfo = await getUserInfo(userID)    // Get user information
  let friendList = await getFriendList(userID)    // Get the list of friends
  
  // Start rendering}) ()Copy the code

The above code is simple enough to get the user’s information and friends list based on the user’s ID. The wait time for the page to start rendering is the request time for getUserInfo plus the request time for getFriendList. There is no dependency between getFriendList and getUserInfo. GetFriendList does not need to wait for getUserInfo to return before it can execute the request.

Since getUserInfo and getFriendList have no dependencies. The way to optimize is simply to turn two sequential requests into concurrent requests. This will shorten the wait time to start rendering.

(async() = > {let userID=123
  // Initiate the request simultaneously
  let userInfo = getUserInfo(userID)
  let friendList = getFriendList(userID)
  
  // Wait for the request to return
  await userInfo
  await friendList
  // Start rendering}) ()Copy the code

For this scenario, promise.all is more recommended

(async() = > {let userID=123
  
  Promise.all([getUserInfo(userID),getFriendList(userID)]).then(res= >{
      // Start rendering
  })
})()
Copy the code

5. Check whether the default values of function parameters are the same.

Look at the code

/ / es5 writing
function fn1(userName) {
    let _userName=userName||'wait'
    console.log(_userName)
}

/ / es6 writing
function fn2(userName='wait') {
    let _userName=userName
    console.log(_userName)
}
Copy the code

Before es6, it was usually written as FN1. After support, it is generally converted to the fn2 notation. But they don’t agree.

1. Fn1 If userName is false (false, null, undefined, “empty string, 0, NaN), _userName will be set to” waiting”

2. Fn2 _userName is set to “waiting” only if the value of userName is undefined.

The above code is only a very simple illustration. In real development, the code might be complicated, such as using the replace method for userName. If you pass null to fn2, an error is reported

summary

So this time I’m sharing these five points, so that’s it for now. If I find another harvest later, I will write the article in the first time. If you have any suggestions, opinions, or mistakes or improvements, please leave a comment in the comments section.