Recently, I found that many times in the interview, I was always asked some handwritten questions, and then I did a boring search about what such questions are available
The results were so strikingly similar that I decided to rank my “old friends” in order of merit
Nothing else, just for everyone to be familiar with the code at the same time, really to understand why involved in the relevant issues, and take this as an opportunity to work hard, go strong, ha ha ha
So, let’s start today’s top10!!
10th
Write a cookie
Appear index: ★☆☆☆ investigate index: ★☆☆☆ comprehensive evaluation: ★☆☆☆ overall score: 1.0
It is a small piece of data that the server sends to the user’s browser and saves locally. The data will be carried when the browser sends a request to the same server next time
A small and powerful effect:
- Session state management (such as user login status, shopping cart, game score, or other information that needs to be logged)
- Personalization (such as user-defined Settings, themes, etc.)
- Browser behavior tracking (e.g. tracking and analyzing user behavior, etc.)
Name =jay_chou; name=jay_chou; name=jay_chou; age=41; uid=19790118175; , add key=value; Format to write
Because the work needs to get and set the cookie situation is more, so need to know how to implement such a method
const Cookie = { getCookie(key) { let match = document.cookie.match(new RegExp('(^| )' + key + '=([^;] (*). | $) ')); if (match && match.length) { return decodeURIComponent(match[2]); } return null; }, setCookie(key, value, opts = {}) { let arr = []; if (opts.httpOnly) { arr.push('httpOnly=true'); } if (opts.maxAge) { arr.push(`max-age=${opts.maxAge}`); } if (opts.domain) { arr.push(`domain=${opts.domain}`); } if (opts.path) { arr.push(`path=${opts.path}`); } / / secure | sameSite omitted document. Such as cookies = ` ${key} = ${encodeURIComponent (value)}; ${arr.join('; ')} `; }};Copy the code
Simple analysis:
getCookie
document.cookie
The value of the corresponding cookie can be obtained (nohttpOnly:true
Information is available)- Match matches a regular match.
- For example, age=41, it may be preceded by a space or a character starting with age
(^| )
- Key is followed by
=
No.,=
“Is followed by” except”;
Any character outside the number([^;] *)
([^;] *)
the*
Indicates 0 to multiple times, because there may be a key but no value- The resulting
;
End or value end, corresponding to(; | $)
- For example, age=41, it may be preceded by a space or a character starting with age
- Returns the value of the second group matched by the key after decoding
- Returns null if not found
setCookie
- Sets an array arR to hold all the parameters to be set
httpOnly
Set to true, passdocument.cookie
Could not get the cookie that set the corresponding keymax-age
Used to set the cookie expiration time, in secondsdomain
Set domain name, specify domain name can accept cookies, including sub-domain name (such as. Baidu.com set, the next face domain can accept cookies)path
Specify a path to accept cookies (e.g. Path =/web, then /web/fe,/web/login subpaths are also acceptable)secure
Specifies that cookies can only be accepted in HTTPSsameSite
Cookies may not be sent when crossing domainsdocument.cookie
Directly set the corresponding key and value and configuration parameters
What parameters can be set for cookies and what each parameter is used for
The ninth
Handwriting number group flat
Appear index: ★★☆☆ investigate index: ★★☆☆ comprehensive evaluation: ★★☆☆ overall score: 2.0
[1, 2, 3, 4, [5, [6, [7, [8, [9]]]]]]]] encounter this kind of abnormal condition of the multi-dimensional array structure is drunk, though rarely appears in the work, but it is a test
So let’s just do the first implementation, which is all in, flattened into a one-dimensional array
Const mathematical 1 = arr => {return arr.reduce((res, cur) => {// If the current field is an array, Return [...res,...flatten1(cur)]; if (array.isarray (cur)) {// return a new Array that includes expanded elements and a flattened Array element. Return [...res, cur];} else {// Return a new array containing the expanded elements and the current item. }} []); };Copy the code
The above code will flatten the multidimensional array directly to a one-dimensional array, and you will have completed the task of flattening the array
But, sometimes you need to flatten a certain depth, not all flatten into one dimension, and then you need to add parameters to deal with that
Let’s look at the second implementation
const flatten2 = (arr, depth = 1, res = []) => { let i = -1, len = arr.length; While (++ I < len) {let cur = arr[I]; If (depth > 0 && array.isarray (cur)) {// If (depth > 0 && array.isarray (cur)) {// If (depth > 1), continue recursively. Dept. 1 if (depth > 1) {flatten1 (cur, dept. 1, RES); } else { res.push(cur); [res.length] = cur; }} // Return the result array. };Copy the code
Number group flattening, in fact, is to determine the object type (array), whether the recursion will continue to flatten the problem
Handwritten array reduce
Appear index: ★★☆☆ investigate index: ★★☆☆ comprehensive evaluation: ★★☆☆ overall score: 2.0
Reduce method is used in the first realization of number group flattening in the above problem. It is known that reduce contains two parameters, the first parameter is the function fn passed, and the second parameter is the initialized value val
Fn has two common arguments: 1 is the total returned by the accumulator, and 2 is the cur element being processed in the current array
3 is the index value of the current array element, and 4 is the original array
Okay, that’s it, so let’s implement it
Array.prototype.reduce = function(fn, val) {array.prototype. reduce = function(fn, val) { i < this.length; Typeof val === 'undefined') {val = this[I]; if (typeof val === 'undefined') {val = this[I]; } else {val = fn(val, this[I], I, this); } } return val; };Copy the code
Tip: Do not abbreviate the function to arrow function (fn, val) => {} otherwise you will not find this
This is to test the proficiency of reduce, and whether you understand the parameters contained in the first parameter fn and their meanings
Write a sleep
Appear index: ★★☆☆ investigate index: ★★☆☆ comprehensive evaluation: ★★☆☆ overall score: 2.0
Since there is no sleep syntax in JS, you need to deal with the need to do something after a certain amount of time
Just go to the code and you’ll understand
function sleep(fn, time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(fn); }, time); }); } // test case let index = 0; Function fn() {console.log(' I'm ready to eat ', index++); } async function play() { let a = await sleep(fn, 1000); a(); let b = await sleep(fn, 2000); b() let c = await sleep(fn, 3000); c() } play();Copy the code
1. Promise and async/await are both used in this case
eighth
Handwritten inheritance
Appear index: ★★ ★☆☆ investigate index: ★★☆☆ comprehensive evaluation: ★★☆☆☆ overall score: 3.0
Inheritance will still be examined today, and there are many ways of inheritance
- Prototype chain inheritance
- Borrowing constructor
- Combination of inheritance
- Primary inheritance
- Parasitic combinatorial inheritance
There are many ways to inheritance, and even composite inheritance has some disadvantages (the constructor of the parent class is called twice, once when creating the prototype of the new parent class, and once in the constructor of the child class), but there are still some improvements to be made for more complete inheritance
Let’s go straight to the case of parasitic combinatorial inheritance
- To address the drawback of composite inheritance is that the parent class constructor is called twice
- Create a prototype copy of the parent class and assign it to the prototype of the child class (this is called parasitic inheritance).
- Composition also calls the superclass constructor in the subclass constructor
Function inherit(subs, supers) {let proto = object.create (supers. Prototype); // Proto.constructor = subs; // constructor points to subclass subs. Prototype = proto; Function Super(name) {this.name = name; This. colors = [' love, easy ', 'lonely season ']; } Super.prototype.sayName = function() { console.log(this.name); }; // Subclass function Sub(name, age) {// subclass super. call(this,... The args constructor inherits the properties and methods super. call(this, name) on the instance; this.age = age; } // inherit(Sub, Super); Sub.prototype.sayAge = function() { console.log(this.age); } // test case let sub = new sub (' tao ', 18); Sub.colors. Push (' I love you '); sub.sayName(); sub.sayAge(); console.log(sub.colors); let super1 = new Super('JJ'); console.log(super1.colors);Copy the code
The topic of inheritance mainly focuses on the familiarity and corresponding disadvantages of various inheritance methods, and comes up with a set of relatively perfect inheritance methods
seventh
Handwritten Coriolization functions
Appear index: ★★ ★☆☆ investigate index: ★★☆☆ comprehensive evaluation: ★★☆☆ overall score: 4.0
Currization is the technique of transforming a function that takes multiple arguments into a function that takes a single argument and returns the result that takes the remaining arguments
In short, you can fill a function with several arguments, return a new function, and evaluate it
Nothing is as simple as a few lines of code
function sum(a, b, c, d) { return a + b + c + d; } // function curry(fn,... If (args. Length < fn.length) {return (...) {if (args. Length < fn.length) {return (... newArgs) => curry(fn, ... args, ... newArgs); } else { return fn(... args); Let add = curry(sum); console.log(add(1)(2)(3)(4)); console.log(add(1, 2, 3)(4)); console.log(add(1, 2)(3, 4)); console.log(add(1)(2, 3)(4));Copy the code
Currization is a partial evaluation of higher-order functions
6
EventEmitter
Appear index: ★★ ★☆☆ investigate index: ★★☆☆ comprehensive evaluation: ★★☆☆ overall score: 5.0
Once upon a time, someone asked you if you knew about publishing and subscribing, and when you said yes and sputtered an explanation, the person smiled and wrote me an EventEmitter
Don’t panic, it is only on, emit, off, once method
Ask and write
Class EventEmitter {constructor() {this.events = object.create (null); this.Events = object.create (null); } on(type, cb) { let events = this.events; If (events[type]) {events[type].push(cb); if (events[type]) {events[type]. } else {// create an array space and store the callback cb event[type] = [cb]; } }, emit(type, ... If (this.events[type]) {this.events[type]. ForEach (listener => {listener.call(this,... args); }); } } off(type, cb) { let events = this.events; If (events[type]) {events[type] = events[type]. Filter (listener => {cb return listener! == cb && listener.listen ! == cb; }); } } once(type, cb) { function wrap() { cb(... arguments); this.off(type, wrap); } // wrap. Listen = cb; // Call the on method this.on(type, wrap); }}Copy the code
Create an array, add a callback to an array, and run through the array in order to execute it
fifth
Handwritten promise. all and race
★★★★ ★★★★ ★★★★ ★★★★ ★★★★ ★★★★ ★★★★ overall score: 6.0
If Promise is mentioned, more often than not the brothers will be in the same place
Promise.all passes in an array of Promise instances, and the all methods are executed in the order they are passed in until resolve, which takes the longest, returns. If one of the intermediate links appears reject, it is cut off
Promise.race, as its name implies, passes the same argument as all, which terminates execution by deciding who first returns resolve and returns the first successful one
Application Scenarios:
- all
- Concurrent requests are executed sequentially; Multiple asynchronous results are merged together
- race
- Check whether the interface times out
All = function(arr) {return new Promise((resolve, Reject) => {// Record the data passed by each promise instance with the result array let res = []; // let index = 0; for (let i = 0; i < arr.length; I ++) {// p for each promise instance, call the then method let p = arr[I]; [I] = data; [I] = data; [I] = data; If (++index === arr.length) {// Resolve (res); } }, reject); }}); }; Promise.race = function(arr) { return new Promise(() => { for (let i = 0; i < arr.length; i++) { arr[i].then(resolve, reject); }}); }; // test case let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(1)}, 2000); }); let p2 = new Promise((resolve) => { resolve(2); }); let p3 = new Promise((resolve) => { setTimeout(() => { resolve(3); }); }); Promise.all([p3, P1, p2]).then(data => {// Print console.log(data) in the order in which the array was passed; // [3, 1, 2]}); Promise.race([p1, p2, p3]).then(data => {console.log(data); / / 2})Copy the code
What is the difference between ALL and Race, and what are the scenarios in which they are used
4,
Handwritten instanceOf
★★★ ★★★ ★★★ ★★★ ★★★ ★★★ ★★★ ★★★ ★★★ ★ overall rating: 7.0
InstanceOf is what we use to determine if an instance belongs to a class. This must be an understanding of stereotypes and stereotype chains, so let’s just look at the code
function instanceOf(A, B) { B = B.prototype; A = A.__proto__; while(true) { if (A === null) { return false } if (A === B) { return true; } A = A.__proto__; }}Copy the code
The prototype chain of an instance is the prototype of its class. The prototype chain of an instance is the prototype of its class
Write a json
★★★ ★★★ ★★★ ★★★ ★★★ ★★★ ★★★ ★★★ ★★★ ★ overall rating: 7.0
When it comes to cross-domain, the famous is JSONP. Although CORS is very convenient to solve now, it is mostly the background students to configure the matter. When the front end meets cross-domain situation, JSONP is also used more
I believe many students know the implementation principle of JSONP, in fact, it is easy to solve the problem by using the SRC attribute of script. Of course, the back-end students use the callback parameter we pass to wrap the data and finally return it to us
- Jsonp data returned from the back end
app.get('/jsonp', (req, res) => { const {callback, wd, from} = req.query; Let data = {referer: from, data: [1, 2, 3]}; data = JSON.stringify(data); Res.end (callback + '(' + data + ')'); });Copy the code
So now you can see how jSONP is processed and returned from the back end, so now we go inside and start writing, okay
Const jsonp = (opts = {}) => {// Write a callback to opts.url = '${opts.url}? callback=${opts.callback}`; // When you need to pass other parameters, For (let key in opts.data) {if (opts.data. HasOwnProperty (key)) {opts.url += '&${key}=${opts.data[key]}'; for (let key in opts.data) {if (opts.data. Const script = document.createElement('script'); // Const script = document.createElement('script'); script.src = opts.url; / / in the script after the script execution, and then delete this script script. The onload () = = > {document. Body. RemoveChild (script). } / / to create a good script script to add to the document in the body. The body. The appendChild (script). }; / / test cases to the json ({url: 'http://localhost:8888/cors' data: {wd:' the NBA ', the from: 'home'}, / / receiving data function callback: 'getData' }); Function getData(data) {console.log(data); function getData(data) {console.log(data); }Copy the code
< span style = “box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; word-wrap: inherit! Important;
Third,
Handwritten deep copy
★★★★ ★★★★ ★★★★ ★★★★ overall rating: 8.0
Deep copy can also be called deep clone, whatever is called, but this is a classic problem in preventing data corruption caused by shared memory addresses
And so on, because most of the data types used in the work are objects and arrays, so it will not deal with such as re, date and so on. If you are interested in it, you can study it privately
Let o = {a: 1, b: 2, c: [1,2,3], d:{age:18}}; o.o = o; Const deepClone = (obj, map = new map ()) => { Only object types ({}, []) need to handle deep copy if (typeof obj === 'object' &&obj! If (map.has(obj)) {return map.get(obj); if (map.has(obj)) {return map.get(obj); } // Create a new object or Array let data = array.isarray (obj)? [] : {}; // Set data to prevent cyclic references to map.set(obj, data); For (let key in obj) {if (obj. HasOwnProperty (key)) {// Data [key] = deepClone(obj[key], map); // return data; // return data; // Return data; } // Return obj between base types; } // Let o2 = deepClone(o); o2.c.pop(); o2.a = 110; O2.d.name = 'little white '; console.log(o, o2);Copy the code
First of all, it’s important to know why deep copies exist, and second, what data types need to be deep copied and understand what recursion does
Write a new
★★★★ ★★★★ ★★★★ ★★★★ overall rating: 8.0
We know exactly how to create an instance, we just new it, if we don’t have an object, we just new an object, haha, are you kidding
Let’s review the process of new
- Create a new object
- Point the new object’s Prototype to the constructor’s prototype
- This points to the created instance
- If no other object is returned, the new object is returned
Sometimes words don’t work, so use code to explain why
function Dog(name) { this.name = name; // return function() {// name, // age: 5; // } } Dog.prototype.say = function() { console.log(this.name); return this.name; }; New function new (Super,... Args) {// create an Object that inherits the constructor prototype let obj = object.create (super.prototype); Let res = super.call (obj,... args); // The second condition returns the function if ((res! == null && typeof res === 'object') || typeof res === 'function') { return res; } // return obj; } // Test case let dog = New(dog, 'small white '); dog.say(); // console.log(dog.name, dog.age); // console.log(dog());Copy the code
When a new instance is created, the corresponding class will attach many attributes and methods to this, but sometimes we will look at what happens when the constructor of the class returns an object or function directly. But also through the process of new to better think, what does it do
second
Write call and apply by hand
★★★★ ★★★★ ★★★★ ★★★★ ★★ overall rating: 9.0
Call and Apply ask more about the differences between them. Besides, occasionally someone will ask which one is better than the other. You might think about it a little bit, but with this code, you can easily see that Call is faster than Apply
- Call and apply
Prototype. Call = Function (context,... Args) {/ / execution context that is Object type, if not the window context = Object (context) | | window; // Create an extra variable as the context property const fn = Symbol(); Context [fn] = this; context[fn] = this; // Execute the function... Args passed const result = context[fn](... args); Delete context[fn]; Return result; }; // Test case -call let o = {a: 1}; function fn(b) { console.log(this.a, b); } fn. Call (o, 'hello '); / / the apply to realize the Function. The prototype. The apply = Function (context, arrArgs) {context = Object (context) | | window; const fn = Symbol(); context[fn] = this; Const result = context[fn](const result = context[fn](... arrArgs); delete context[fn]; return result; } // let o = {a: 1}; function fn(... b) {console.log(this.a, ... b)} fn.apply(o, [2, 3, 4]);Copy the code
Apply must be an array. Call can be of any type and can pass multiple arguments.
In addition, setting a private property for the execution context and getting the result of the function’s execution, and eventually removing the used private property and returning the result is another place to look
Write a bind
★★★★ ★★★★ ★★★★ ★★★★ ★★ overall rating: 9.0
The bind method is a practical application of higher-order functions. The difference between bind and call and apply is that it does not execute a function immediately. Instead, it executes a delayed operation, which generates a new function
So, let’s look at the code and make it easier to understand
Function.prototype.bind = function(context, ... Args) {// context is the execution context to be changed //... Args for the rest of the arguments passed into bind return (... NewArgs) => {// This returns a new function // change this by calling the call method and passing the old parameter and the new parameter to return this.call(context,... args, ... newArgs); }}; // test case let o = {name: 'CHD '}; function f(... args) { console.log(this.name, ... args); } let o2 = f.b ind (o, 1, '222', null, [1, 2, 3]. {age: 5}); o2();Copy the code
You should know the difference between call and apply. You should also know the difference between call and apply
First place
Handwriting throttling and anti – shake
★★★★ overall rating: 10.0
There is a kind of optimization method called experience optimization, and the most frequently used is throttling and anti-shaking
Throttling is the execution of a function once in a certain period of time, used for scroll events
Stabilization is a function that executes the last time in a certain amount of time. It is used for input operations
Now, let’s see how our Top1 is written
// throttle function throttle(fn, time) {// let pre = 0; // Return a new function return (... Args) => {let now = date.now (); If (now - pre > time) {fn. Call (this,... args); Pre = now; }} function debounce(fn, time, isNow) { return (... Fn if (isNow) {fn. Call (this,... args); isNow = false; return; } // If the last timer is still running, return if (timer) return; Timer = setTimeout(() => {fn.call(this,... args); // Clear timer clearTimeout(timer); timer = null; }, time); }}Copy the code
Throttling and anti-shaking are definitely cliche topics, and through these two optimization methods, we can greatly improve the user experience. Use setTimeout to set the time, within the specified time to execute the function fn, and to know when the first trigger of the anti-shake
The end of the
Thank you very much for taking the trouble to see here, although it is Top10, but the front-end knowledge points to be inspected in the interview process is also very large, to ensure systematic learning and more thinking about a why are very meaningful things
So, I’ll stop there this time. 886