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:

  1. Session state management (such as user login status, shopping cart, game score, or other information that needs to be logged)
  2. Personalization (such as user-defined Settings, themes, etc.)
  3. 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

  1. document.cookieThe value of the corresponding cookie can be obtained (nohttpOnly:trueInformation is available)
  2. 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(; | $)
  3. Returns the value of the second group matched by the key after decoding
  4. Returns null if not found

setCookie

  1. Sets an array arR to hold all the parameters to be set
  2. httpOnlySet to true, passdocument.cookieCould not get the cookie that set the corresponding key
  3. max-ageUsed to set the cookie expiration time, in seconds
  4. domainSet domain name, specify domain name can accept cookies, including sub-domain name (such as. Baidu.com set, the next face domain can accept cookies)
  5. pathSpecify a path to accept cookies (e.g. Path =/web, then /web/fe,/web/login subpaths are also acceptable)
  6. secureSpecifies that cookies can only be accepted in HTTPS
  7. sameSiteCookies may not be sent when crossing domains
  8. document.cookieDirectly 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

  1. Prototype chain inheritance
  2. Borrowing constructor
  3. Combination of inheritance
  4. Primary inheritance
  5. 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

  1. Create a new object
  2. Point the new object’s Prototype to the constructor’s prototype
  3. This points to the created instance
  4. 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