What conditions can lead to memory leaks
1,Unexpected global variable: due to use of undeclared variable,and accidentally created a global variable,And keep this variable in memory and cannot be recycled 2,Forgotten timer or callback function: set setInterval Timer, and forget to cancel it, if the loop function has a reference to an external variable, then this variable will remain in memory and cannot be recycled. 3,break away DOM citations: get a DOM The reference to the element, and the latter element is deleted, since the reference to this element has been retained, it cannot be recycled. 4,Closures: Unreasonable use of closures results in some variables being kept in memory.
----Problem knowledge point dividing line----
How to get properties on object non-prototype chain?
Use the post hasOwnProperty() method to determine whether a property belongs to the prototype chain:
function iterate(obj){ var res=[]; for(var key in obj){ if(obj.hasOwnProperty(key)) res.push(key+': '+obj[key]); } return res; }
----Problem knowledge point dividing line----
What is the difference and role of pseudo-elements and pseudo-classes?
- Pseudo-elements: Insert extra elements or styles before and after content elements, but these elements are not actually generated in the document. They are only visible externally, but they are not found in the source code of the document, hence the name "pseudo" elements. E.g:
p::before {content:"Chapter One:";} p::after {content:"Hot!";} p::first-line {background:red;} p::first-letter {font-size:30px;}
- Pseudo-classes: Add special effects to specific selectors. It adds categories to existing elements and does not create new elements. E.g:
a:hover {color: #FF00FF} p:first-child {color: red}
Summary: Pseudo-classes change the state of elements by adding pseudo-classes to element selectors, while pseudo-elements change elements by operating on elements.
----Problem knowledge point dividing line----
What does the head tag do, and which tags are essential?
The tag is used to define the head of the document and it is the container for all head elements. Elements in can reference scripts, instruct the browser where to find stylesheets, provide meta information, and more.
The header of a document describes various properties and information about the document, including the title of the document, its location on the Web, and its relationship with other documents. The vast majority of document headers contain data that is never actually displayed to the reader as content.
The following tags can be used in the head section: <base>, <link>, <meta>, <script>, <style>, <title>.
where <title> defines the title of the document and is the only required element in the head section.
----Problem knowledge point dividing line----
deep copy
Implementation 1: Do not consider Symbol
function deepClone(obj) { if(!isObject(obj)) return obj; let newObj = Array.isArray(obj) ? [] : {}; // for...in will only traverse the object's own and inherited enumerable properties (excluding Symbol properties) for(let key in obj) { // The obj.hasOwnProperty() method only considers the properties of the object itself if(obj.hasOwnProperty(key)) { newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]; } } return newObj; }
Implementation 2: Consider Symbol
// hash acts as a checker to avoid circular references in deep copies of objects, resulting in stack explosion function deepClone(obj, hash = new WeakMap()) { if(!isObject(obj)) return obj; // Check if there is the same object that has been copied before, and return the object stored in the hash after copying before if(hash.has(obj)) return hash.get(obj); let newObj = Array.isArray(obj) ? [] : {}; // The backup is stored in the hash, and newObj is currently an empty object or array. The attribute will be appended later, and the value stored here is the stack of the object hash.set(obj, newObj); // Reflect.ownKeys returns an array containing all the key names of the object itself (excluding inherited), whether the key name is a Symbol or a string, or whether it is enumerable or not. Reflect.ownKeys(obj).forEach(key => { // If the attribute value is an object, perform a recursive deep copy, otherwise copy directly newObj[key] = isObject(obj[key]) ? deepClone(obj[key], hash) : obj[key]; }); return newObj; }
----Problem knowledge point dividing line----
Understanding of sticky positioning
Sticky literally means paste in English, so it can be called sticky positioning. Syntax: position: sticky; Position based on the user's scroll position.
Sticky positioned elements are dependent on the user's scrolling, switching between position:relative and position:fixed positioning. It behaves like position:relative; and when the page scrolls beyond the target area, it behaves like position:fixed; and it stays fixed at the target position. Element positioning behaves as a relative positioning until a certain threshold is crossed, and a fixed positioning thereafter. This specific threshold refers to one of top, right, bottom or left, in other words, specify one of the top, right, bottom or left thresholds for sticky positioning to take effect. Otherwise it behaves the same as relative positioning.
----Problem knowledge point dividing line----
inherit
prototypal inheritance
Core idea: the prototype of the subclass becomes the instance of the superclass
accomplish:
function SuperType() { this.colors = ['red', 'green']; } function SubType() {} // Prototypal inheritance key: the prototype of the subclass becomes an instance of the superclass SubType.prototype = new SuperType(); // test let instance1 = new SubType(); instance1.colors.push('blue'); let instance2 = new SubType(); console.log(instance2.colors); // ['red', 'green', 'blue']
Problems with prototypal inheritance:
- Reference type properties contained in the prototype will be shared by all instance objects
- Subclasses cannot pass parameters to the superclass constructor when instantiating
Constructor Inheritance
Core idea: call the parent class constructor in the subclass constructor
accomplish:
function SuperType(name) { this.name = name; this.colors = ['red', 'green']; this.getName = function() { return this.name; } } function SubType(name) { // Inherit SuperType and pass parameters SuperType.call(this, name); } // test let instance1 = new SubType('instance1'); instance1.colors.push('blue'); console.log(instance1.colors); // ['red','green','blue'] let instance2 = new SubType('instance2'); console.log(instance2.colors); // ['red', 'green']
The emergence of constructor inheritance is to solve the reference value sharing problem of prototypal inheritance. The advantage is that you can pass parameters to the parent class constructor in the subclass constructor. The problems with it are: 1) Since the method must be defined in the constructor, the method cannot be reused. 2) Subclasses also cannot access methods defined on the prototype of the superclass.
composition inheritance
Core idea: The prototype chain and the constructor are integrated, that is, the prototype chain is used to inherit the methods on the prototype, and the instance properties are inherited through the constructor.
accomplish:
function SuperType(name) { this.name = name; this.colors = ['red', 'green']; } Super.prototype.sayName = function() { console.log(this.name); } function SubType(name, age) { // Inherited properties SuperType.call(this, name); // instance properties this.age = age; } // inherited method SubType.prototype = new SuperType(); // test let instance1 = new SubType('instance1', 1); instance1.sayName(); // "instance1" instance1.colors.push("blue"); console.log(instance1.colors); // ['red','green','blue'] let instance2 = new SubType('instance2', 2); instance2.sayName(); // "instance2" console.log(instance2.colors); // ['red','green']
The problem with compositional inheritance is that the parent class constructor is always called twice: once when new SuperType() is called when the subclass prototype is created, and once when SuperType.call() is called in the subclass constructor.
Parasitic composition inheritance (best)
Core idea: Inherit properties through constructors, but use a hybrid prototypal inheritance method, that is, instead of assigning values to the subclass prototype by calling the parent class constructor, a copy of the parent class prototype is obtained.
accomplish:
function SuperType(name) { this.name = name; this.colors = ['red', 'green']; } Super.prototype.sayName = function() { console.log(this.name); } function SubType(name, age) { // Inherited properties SuperType.call(this, name); this.age = age; } // inherited method SubType.prototype = Object.create(SuperType.prototype); // Overriding the prototype causes the default constructor to be lost, manually point the constructor back to the SubType SubType.prototype.constructor = SubType;
class implements inheritance (ES6)
Core idea: Implement class inheritance through extends (equivalent to ES5 prototypal inheritance). Call the constructor of the parent class through super (equivalent to ES5 constructor inheritance).
accomplish:
class SuperType { constructor(name) { this.name = name; } sayName() { console.log(this.name); } } class SubType extends SuperType { constructor(name, age) { super(name); // Inherited properties this.age = age; } } // test let instance = new SubType('instance', 0); instance.sayName(); // "instance"
Although class inheritance uses a new syntax, the prototype chain is still used behind it.
----Problem knowledge point dividing line----
Why sometimes use translate to change position instead of positioning?
translate is a value of the transform property. Changing transform or opacity does not trigger browser reflow or repaint, only compositions. And changing absolute positioning triggers a re-layout, which in turn triggers a repaint and compositing. transform causes the browser to create a GPU layer for the element, but changing absolute positioning uses the CPU. Therefore translate() is more efficient and can reduce the draw time for smooth animations. When translate changes position, the element still occupies its original space, which doesn't happen with absolute positioning.
----Problem knowledge point dividing line----
What does the New operator do?
1,First a new object is created 2,Set the prototype, set the prototype of the object to the function's prototype prototype object 3,let the function this Point to this object, execute the code of the constructor (add properties to this new object) 4,Determine the return value type of the function, if it is a value type, return the created object. If it is a reference type, return the object of this reference type
----Problem knowledge point dividing line----
understanding of browsers
The main function of the browser is to render the web resource selected by the user. It needs to request the resource from the server and display it in the browser window. The format of the resource is usually HTML, but also includes PDF, image and other formats. The user uses a URI (Uniform Resource Identifier) to specify the location of the requested resource.
The HTML and CSS specifications specify how browsers interpret html documents, and these specifications are maintained by the W3C organization, the organization responsible for developing web standards. However, browser manufacturers have developed their own extensions, and the compliance with the specification is not perfect, which brings serious compatibility problems for web developers.
The browser can be divided into two parts, the shell and the kernel. Among them, there are relatively more types of shell s, and fewer kernels. There are also some browsers that do not distinguish between shell and kernel. After Gecko was separated from Mozilla, there was a clear division of shell and kernel.
- shell refers to the shell of the browser: e.g. menus, toolbars, etc. It is mainly provided for user interface operations, parameter settings and so on. It calls the kernel to implement various functions.
- The kernel is the heart of the browser. A kernel is a program or module that displays content based on a markup language.
----Problem knowledge point dividing line----
How to extract specified properties in highly nested objects?
Sometimes very deeply nested objects are encountered:
const school = { classes: { stu: { name: 'Bob', age: 24, } } }
Like the name variable here, it is nested four levels, and if you still try the old method to extract it:
const { name } = school
Obviously it doesn't work, because the school object itself does not have a name attribute, and the name is located in the "son's son" object of the school object. To extract the name, a relatively stupid way is to destructure layer by layer:
const { classes } = school const { stu } = classes const { name } = stu name // 'Bob'
But there is a more standard way of doing this, which can be solved with a single line of code:
const { classes: { stu: { name } }} = school console.log(name) // 'Bob'
You can further deconstruct it in the form of colon + {target attribute name} on the right side of the deconstructed variable name, until the target data is obtained.
----Problem knowledge point dividing line----
Usage scenarios for the difference between Promise.all and Promise.race
(1) Promise.all Promise.all can wrap multiple Promise instances into a new Promise instance. At the same time, the return values of success and failure are different. When it succeeds, it returns an array of results, and when it fails, it returns the value of the first reject ed failure state.
In Promise.all, an array is passed in, and the return is also an array, and it will be mapped. The values returned by the incoming promise object are arranged in the array in order, but note that the order of their execution is not in accordance with Sequential, unless the iterable is empty.
It should be noted that the order of the data in the array of the successful result obtained by Promise.all is the same as the order of the array received by Promise.all, so that when multiple requests are sent and the data is obtained and used according to the order of the requests, you can Use Promise.all to resolve.
(2)Promise.race
As the name suggests, Promse.race means running, which means that whichever result in Promise.race([p1, p2, p3]) gets the fastest result will be returned, regardless of whether the result itself is a success state or a failure state. When you want to do something, you can't do it for a long time, you can use this method to solve it:
Promise.race([promise1,timeOutPromise(5000)]).then(res=>{})
----Problem knowledge point dividing line----
Implement JSONP cross-domain
The core principle of JSONP: The script tag is not constrained by the same-origin policy, so it can be used for cross-domain requests. The advantage is that it has good compatibility, but it can only be used for GET requests;
accomplish:
const jsonp = (url, params, callbackName) => { const generateUrl = () => { let dataSrc = ""; for(let key in params) { if(params.hasOwnProperty(key)) { dataSrc += `${key}=${params[key]}&` } } dataSrc += `callback=${callbackName}`; return `${url}?${dataSrc}`; } return new Promise((resolve, reject) => { const scriptEle = document.createElement('script'); scriptEle.src = generateUrl(); document.body.appendChild(scriptEle); window[callbackName] = data => { resolve(data); document.removeChild(scriptEle); } }); }
----Problem knowledge point dividing line----
Understanding of event delegation
(1) The concept of event delegation
Event delegation essentially exploits the mechanism of browser event bubbling. Because the event will be uploaded to the parent node during the bubbling process, and the parent node can obtain the target node through the event object, so the listener function of the child node can be defined on the parent node, and the listener function of the parent node can uniformly process multiple child elements. Events, this way is called event delegation (event delegation).
Using event delegation eliminates the need to bind a listener event for each child element, which reduces memory consumption. And the use of event proxy can also realize dynamic binding of events. For example, if a child node is added, there is no need to add a listener event for it separately. The event bound to it will be handed over to the listener function in the parent element for processing. .
(2) Features of event delegation
- Reduce memory consumption
If you have a list with a large number of list items, you need to respond to an event when the list item is clicked:
<ul id="list"> <li>item 1</li> <li>item 2</li> <li>item 3</li> ...... <li>item n</li> </ul>
If you bind a function to each list item, it will consume a lot of memory and consume a lot of performance in terms of efficiency. Therefore, a better way is to bind this click event to its parent layer, that is, ul, and then match and judge the target element when executing the event, so event delegation can reduce a lot of memory consumption and save efficiency.
- Dynamically bind events
In the example above, each list item is bound to events. In many cases, list item elements need to be dynamically added or removed through AJAX or user action. Then, at each change, new elements need to be bound to events, unbind the event to the element to be deleted. If you use event delegation, there is no such trouble, because the event is bound to the parent layer, and has nothing to do with the increase or decrease of the target element, the execution to the target element is matched in the process of actual response to the execution of the event function, So the use of events in the case of dynamic binding events can reduce a lot of repetitive work.
// To implement the event delegation of the li element under #list to its parent element, which is #list: // Bind events to parent elements document.getElementById('list').addEventListener('click', function (e) { // Compatibility Handling var event = e || window.event; var target = event.target || event.srcElement; // Determine whether the target element is matched if (target.nodeName.toLocaleLowerCase === 'li') { console.log('the content is: ', target.innerHTML); } });
In the above code, the target element is the specific element clicked under the #list element, and then some attributes of the target (such as nodeName, id, and so on) can be more accurately matched to a class of #list li element above;
(3) Limitations
Of course, event delegation also has limitations. Events such as focus,blur, etc. do not have an event bubble mechanism, so event delegation cannot be implemented. Events like mousemove,mouseout, although there are event bubbles, can only continuously calculate Positioning has high performance consumption by location.
Of course, event delegation not only has advantages, it also has disadvantages. Event delegation will affect page performance. The main influencing factors are:
- In the element, the number of times the event delegate is bound;
- The number of DOM layers between the bottommost element of the click and the element bound to the event;
Where event delegation must be used, the following processing can be done:
- Use event delegation only where necessary, such as: local refresh area of ajax
- Minimize the level of binding, not on the body element, bind
- Reduce the number of bindings. If possible, combine the bindings of multiple events into an event delegation, and distribute them by the callback of this event delegation.
----Problem knowledge point dividing line----
How to deal with JS files encountered during rendering?
The loading, parsing and execution of JavaScript can block the parsing of documents, that is, when the HTML parser encounters JavaScript while building the DOM, it pauses the parsing of documents, transfers control to the JavaScript engine, and waits until the JavaScript engine runs After that, the browser resumes parsing the document from where it left off. That is to say, if you want to render the first screen fast, You should not load the JS file at the first screen, which is why it is recommended to put the script tag at the bottom of the body tag. Of course, at the moment, it's not that script tags have to be at the bottom, because you can add defer or async attributes to script tags.
----Problem knowledge point dividing line----
The difference between link and @import
Both are ways of externally referencing CSS, and they differ as follows:
- link is an XHTML tag, in addition to loading CSS, it can also define other affairs such as RSS; @import belongs to the CSS category and can only load CSS.
- When link refers to CSS, it is loaded at the same time when the page is loaded; @import requires the page to be loaded after the page is fully loaded.
- link is an XHTML tag, and there is no compatibility problem; @import is proposed in CSS2.1, which is not supported by lower version browsers.
- link supports using Javascript to control the DOM to change styles; @import does not.
----Problem knowledge point dividing line----
How to use webpack to optimize front-end performance?
Using webpack to optimize front-end performance refers to optimizing the output of webpack so that the final result of the package runs quickly and efficiently in the browser.
- Compress code: delete redundant code, comments, simplify code writing, etc. You can use webpack's UglifyJsPlugin and ParallelUglifyPlugin to compress JS files, and use cssnano (css-loader?minimize) to compress css
- Accelerate with CDN: During the build process, modify the referenced static resource path to the corresponding path on the CDN. You can use webpack for the output parameter and the publicPath parameter of each loader to modify the resource path
- Tree Shaking: Remove sections of code that will never be reached. This can be achieved by appending the parameter --optimize-minimize when starting webpack
- Code Splitting: Divide the code into chunks by routing dimensions or components, so that they can be loaded on demand, while making full use of browser caching
- Extract public third-party libraries: SplitChunksPlugin plug-in to extract public modules, and use browser cache to cache these public codes that do not require frequent changes for a long time