First, JavaScript basics

1. Write a Object. The create

Idea: Use the incoming object as a prototype

function create(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}
Copy the code

2. Handwriting instanceof method

The instanceof operator is used to determine whether the constructor’s Prototype property appears anywhere in the object’s prototype chain.

Implementation steps:

  1. First get the prototype of the type
  2. Then get the prototype of the object
  3. The loop then determines whether the prototype of the object is equal to the prototype of the type until the prototype of the object isnullBecause the prototype chain ends up beingnull

Concrete implementation:

Function myInstanceof(left, right) {let proto = object.getProtoTypeof (left); While (true) {if (! proto) return false; if (proto === prototype) return true; proto = Object.getPrototypeOf(proto); }}Copy the code

Write the new operator by hand

Four things happen during a call to new:

(1) First a new empty object is created

(2) Set the prototype. Set the prototype of the object to the prototype object of the function.

(3) Make the function this point to the object, execute the constructor code (add attributes to the new object)

(4) Determine the return value type of the function, if the value type, return the created object. If it is a reference type, an object of that reference type is returned.

function objectFactory() { let newObject = null; let constructor = Array.prototype.shift.call(arguments); let result = null; // Check whether the argument is a function. == "function") { console.error("type error"); return; } // create an empty Object whose prototype is object.create (constructor. Prototype); // point this to a newObject and call result = constructor.apply(newObject, arguments); / / judgment return objects let flag = result && (typeof result = = = "object" | | typeof result = = = "function"); Return flag? result : newObject; } // use the method objectFactory(constructor, initialization argument);Copy the code

4. Write a Promise

const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "rejected"; Function MyPromise(fn) {var self = this; This. state = PENDING; This. value = null; // This. ResolvedCallbacks = []; // This. ResolvedCallbacks = []; This. RejectedCallbacks = []; Resolve (value) {resolve(value) { If (value instanceof MyPromise) {return value. Then (resolve, reject); SetTimeout (() => {// Can only be changed if the state is pending, If (self. State === PENDING) {self. State = RESOLVED; // Set the value self.value = value; / / implement the callback function self. ResolvedCallbacks. ForEach (callback = > {callback (value); }); }}, 0); SetTimeout (() => {// Only if the state is pending can change if (self.state === PENDING) {// Modify state self.state = REJECTED; // Set the value self.value = value; / / implement the callback function self. RejectedCallbacks. ForEach (callback = > {callback (value); }); }}, 0); } // pass both methods into the function try {fn(resolve, reject); } catch (e) {reject(e) {reject(e); }} mypromise.prototype. Then = function(onResolved, onRejected) { Because these are optional onResolved = typeof onResolved === "function"? onResolved : function(value) { return value; }; onRejected = typeof onRejected === "function" ? onRejected : function(error) { throw error; }; / / if it is a wait state, then add the function corresponding to the list if (this. State = = = PENDING) {this. ResolvedCallbacks. Push (onResolved); this.rejectedCallbacks.push(onRejected); If (this.state === RESOLVED) {onResolved(this.value); } if (this.state === REJECTED) { onRejected(this.value); }};Copy the code

5. Write a Promise. Then

The then method returns a new PROMISE instance. To execute the then function when the promise state changes (resolve/Reject is called), we use a callbacks array to hold the function passed to then. Wait until the state changes.

How do I guarantee that the method in the next ** THEN ** will be executed after the (possibly asynchronous) end of the previous ** THEN **?

We can push the function passed to THEN into the callbacks array of the previous promise along with the resolve of the new promise:

  • Predecessor: the current onepromiseWhen done, call itresolveChange state, in thisresolveWill be called in turncallbacksThe callback is then executedthenIn the method of
  • After: In the previous step, whenthenIf the result is a simple value, call new directlypromiseresolve, let its state change, which in turn calls newpromisecallbacksArray method, loop over and over again. If the result returned is apromise, you need to wait for it to complete before triggering a newpromiseresolve, so can be in its resultsthenCall in the newpromiseresolve
Then (ondepressing, onReject){// This const self = this; return new MyPromise((resolve, () => {try{const result = ondepressing (self.value); Return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); }catch(err){reject(err)}} let rejected = () => {try{const result = onReject(self.reason); return result instanceof MyPromise? result.then(resolve, reject) : reject(result); }catch(err){ reject(err) } } switch(self.status){ case PENDING: self.onFulfilledCallbacks.push(fulfilled); self.onRejectedCallbacks.push(rejected); break; case FULFILLED: fulfilled(); break; case REJECT: rejected(); break; }})}Copy the code

Note:

  • Multiple consecutivethenThe callback methods are registered synchronously, but with different onescallbacksArray, because every timethenAll return newpromiseExamples (refer to the examples and diagrams above)
  • The async events in the constructor are executed after the registration is complete, and are called in sequence after the async is completecallbacksArray of preregistered callbacks

6. Write a Promise. All

1) Core ideas

  1. Take an array of Promise instances or an object with an Iterator interface as an argument
  2. This method returns a new Promise object,
  3. Iterate over the passed parameter and “wrap” the parameter with promise.resolve () to make it a Promise object
  4. All callbacks to arguments succeed, and the array of returned values is in the same order as the arguments
  5. If one of the parameters in the array fails, the failed state is triggered. The first failed Promise error message is used as the promise. all error message.

2) Implementation code

In general, Promise. All used to handle multiple concurrent requests, but also to the page data construction convenience, used a page on different interface of data request to come together, however, if one of the interface fails, the multiple requests will fail, what pages may also not to, it depends on the coupling degree of the current page

function promiseAll(promises) { return new Promise(function(resolve, reject) { if(! Array.isArray(promises)){ throw new TypeError(`argument must be a array`) } var resolvedCounter = 0; var promiseNum = promises.length; var resolvedResult = []; for (let i = 0; i < promiseNum; i++) { Promise.resolve(promises[i]).then(value=>{ resolvedCounter++; resolvedResult[i] = value; if (resolvedCounter == promiseNum) { return resolve(resolvedResult) } },error=>{ return reject(error) }) } }) } // test let p1 = new Promise(function (resolve, reject) { setTimeout(function () { resolve(1) }, 1000) }) let p2 = new Promise(function (resolve, reject) { setTimeout(function () { resolve(2) }, 2000) }) let p3 = new Promise(function (resolve, reject) { setTimeout(function () { resolve(3) }, 3000) }) promiseAll([p3, p1, p2]).then(res => { console.log(res) // [3, 1, 2] })Copy the code

7. Write a Promise. Race

The parameters of this method are an array of Promise instances, and the then registered callback method is fulfilled when the state of one of the promises in the array becomes depressing. Since the state of a Promise can only change once, all we need to do is inject the resolve method of the Promise object generated in promise.race into the callback function of each Promise instance in the array.

Promise.race = function (args) {
  return new Promise((resolve, reject) => {
    for (let i = 0, len = args.length; i < len; i++) {
      args[i].then(resolve, reject)
    }
  })
}
Copy the code

8. Handwriting anti-shake function

Function stabilization means that the callback is executed after the event is triggered for n seconds. If the event is triggered again within n seconds, the timer is reset. This can be used on some click-request events to avoid sending multiple requests to the back end because the user clicks multiple times.

Function debounce(fn, wait) {let timer = null; return function() { let context = this, args = arguments; If (timer) {clearTimeout(timer); if (timer) {clearTimeout(timer); timer = null; } // Set the timer so that the event interval specified after the timer = setTimeout(() => {fn.apply(context, args); }, wait); }; }Copy the code

9. Handwritten throttle function

Function throttling refers to the specified unit of time. Within this unit of time, only one callback function that triggers an event can be executed. If an event is triggered multiple times within the same unit of time, only one callback function can take effect. Throttling can be used to reduce the frequency of event calls through event throttling on scroll function event listeners.

// Function throttling implementation; function throttle(fn, delay) { let curTime = Date.now(); return function() { let context = this, args = arguments, nowTime = Date.now(); // If the interval exceeds the specified time, the function is executed. if (nowTime - curTime >= delay) { curTime = Date.now(); return fn.apply(context, args); }}; }Copy the code

10. Handwriting type judgment function

Function getType(value) {if (value === null) {return value + ""; } / / judge the data as a reference type if typeof (value = = = "object") {let valueClass = object. The prototype. The toString. Call (value), type = valueClass.split(" ")[1].split(""); type.pop(); return type.join("").toLowerCase(); Return typeof value;} else {return typeof value; }}Copy the code

11. Handwritten call function

Call function implementation steps:

  1. Determine whether the calling object is a function, even if we define it in the prototype of the function.
  2. Determines whether the incoming context object exists, and if not, sets it to Window.
  3. Process incoming arguments, intercepting all arguments after the first one.
  4. Treat the function as an attribute of the context object.
  5. Call this method with a context object and save the return result.
  6. Delete the newly added attribute.
  7. Returns the result.
/ / call Function realization of the Function. The prototype. MyCall = Function (context) {/ / judgment call object if (typeof this! == "function") { console.error("type error"); } let args = [...arguments]. Slice (1), result = null; / / whether the context into, if not the incoming window context = the context is set to | | window; // Set the calling function to the object's method context.fn = this; // Call the function result = context.fn(... args); // Delete the attribute delete context.fn; return result; };Copy the code

Write the Apply function by hand

The implementation steps of apply function:

  1. Determine whether the calling object is a function, even if we define it in the prototype of the function.
  2. Determines whether the incoming context object exists, and if not, sets it to Window.
  3. Treat the function as an attribute of the context object.
  4. Checks whether the parameter value is passed in
  5. Call this method with a context object and save the return result.
  6. Delete the newly added attribute
  7. Returns the result
/ / the apply Function realization of the Function. The prototype. MyApply = Function (context) {/ / determining if a call object Function if (typeof this! == "function") { throw new TypeError("Error"); } let result = null; / / whether the context exists, if it is not the incoming is window context = context | | window; // Set the function to the object's method context.fn = this; // Call the method if (arguments[1]) {result = context.fn(... arguments[1]); } else { result = context.fn(); } // Delete the property delete context.fn; return result; };Copy the code

13. Write bind by hand

Bind (bind)

  1. Determine whether the calling object is a function, even if we define it in the prototype of the function.
  2. Saves a reference to the current function and gets the remaining passed parameter values.
  3. Create a function return
  4. If apply is used internally to bind function calls, you need to determine if the function is used as a constructor. In this case, you need to pass the this of the current function to Apply. In all other cases, you pass the specified context object.
/ / bind Function realization of the Function. The prototype. MyBind = Function (context) {/ / determining if a call object Function the if (typeof this! == "function") { throw new TypeError("Error"); Var args = [...arguments].slice(1), fn = this; Return Fn. Apply (this instanceof Fn? this : context, args.concat(... arguments) ); }; };Copy the code

14. The realization of function Corrification

Function currification refers to the technique of converting a function that takes multiple arguments into a series of functions that take one argument.

Function curry(fn, args) {let length = fn.length; args = args || []; return function() { let subArgs = args.slice(0); For (let I = 0; i < arguments.length; i++) { subArgs.push(arguments[i]); } if (subArgs. Length >= length) {return fn.apply(this, subArgs); Return curry.call(this, fn, subArgs);} else {// If not, return curry.call(this, fn, subArgs); }}; Function curry(fn,... args) { return fn.length <= args.length ? fn(... args) : curry.bind(null, fn, ... args); }Copy the code

15. Implement AJAX requests

AJAX is an acronym for Asynchronous JavaScript and XML, which refers to the Asynchronous communication of JavaScript to fetch data from an XML document from a server and then update the corresponding portion of the current web page without refreshing the entire page.

Steps to create an AJAX request:

  • Create an XMLHttpRequest object.
  • An HTTP request is created on this object using the open method, which takes the parameters of the request method, the address of the request, whether it is asynchronous, and the authentication information of the user.
  • Before making the request, you can add some information and listener functions to this object. For example, the setRequestHeader method can be used to add header information to the request. You can also add a state listener to this object. An XMLHttpRequest object has five states. When its states change, onReadyStatechange is triggered. You can set up a listener function to handle the result of a successful request. When the readyState of the object changes to 4, it means that the data returned by the server has been received. At this time, we can determine the status of the request. If the status is 2XX or 304, it means that the return is normal. At this point, the page can be updated with the data in response.
  • When the properties and listener functions of the object are set, the sent method is finally called to make a request to the server, passing in parameters as the body of data to be sent.
const SERVER_URL = "/server"; let xhr = new XMLHttpRequest(); // Create the Http request xhr.open("GET", SERVER_URL, true); Xhr.onreadystatechange = function() {if (this.readyState! == 4) return; If (this.status === 200) {handle(this.response); } else { console.error(this.statusText); }}; Xhr.onerror = function() {console.error(this.statustext); }; // set the request header xhr.responseType = "json"; xhr.setRequestHeader("Accept", "application/json"); // Send the Http request xhr.send(null);Copy the code

16. Wrap AJAX requests with Promises

// Promise encapsulates the implementation: Function getJSON(url) {// create a promise object let promise = new promise (function(resolve, reject) { let xhr = new XMLHttpRequest(); // Create a new HTTP request xhr.open("GET", url, true); Xhr.onreadystatechange = function() {if (this.readyState! == 4) return; If (this.status === 200) {resolve(this.response); // If (this.status === 200) {resolve(this.response); } else { reject(new Error(this.statusText)); }}; Xhr.onerror = function() {reject(new Error(this.statustext)); }; // Set the data type of the response to xhr.responseType = "json"; Xhr. setRequestHeader("Accept", "application/json"); // Send the HTTP request xhr.send(null); }); return promise; }Copy the code

17. Implement shallow copy

Shallow copy means that a new object copies exactly the values of the attributes of the original object. If it copies the values of the primitive data type, it copies the memory addresses of the reference data type. If the reference memory address of one object changes, the other object also changes.

(1) the Object. The assign ()

Object.assign(target, source_1, ··· ·) is a copy method for ES6 objects. The first parameter is the target Object, and the other parameters are the source Object.

Note:

  • If the target object and the source object have an attribute with the same name, or if multiple source objects have an attribute with the same name, the later attribute overrides the previous one.
  • If the function has only one argument, the object is returned if the argument is an object. When the parameter is not an object, it is first converted to an object and then returned.
  • becausenullundefinedCannot be converted to an object, so the first argument cannot benullorundefined, an error will be reported.
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);  
console.log(target);  // {a: 1, b: 2, c: 3}
Copy the code

(2) Extended operators

The extension operator makes it possible to copy properties when constructing literal objects. Syntax: let cloneObj = {… obj };

let obj1 = {a:1,b:{c:1}} let obj2 = {... obj1}; obj1.a = 2; console.log(obj1); //{a:2,b:{c:1}} console.log(obj2); //{a:1,b:{c:1}} obj1.b.c = 2; console.log(obj1); //{a:2,b:{c:2}} console.log(obj2); //{a:1,b:{c:2}}Copy the code

(3) array method to achieve a shallow copy of the array

1) Array. The prototype. Slice
  • slice()Method is a JavaScript array method that returns the selected element from an existing array:array.slice(start, end)This method does not change the original array.
  • This method takes two arguments, both of which are optional. If neither is written, a shallow copy of the array can be implemented.
Let arr = [1, 2, 3, 4]; console.log(arr.slice()); // [1,2,3,4] console.log(arr.slice() === arr); //falseCopy the code
2) Array. The prototype. Concat
  • concat()The merge () method is used to merge two or more arrays. This method does not change an existing array, but returns a new array.
  • This method takes two arguments, both of which are optional. If neither is written, a shallow copy of the array can be implemented.
Let arr = [1, 2, 3, 4]; console.log(arr.concat()); // [1,2,3,4] console.log(arr.concat() === arr); //falseCopy the code

(4) handwritten shallow copy

// Shallow copy implementation; Function shallowCopy(object) {// Only copy object if (! object || typeof object ! == "object") return; Let newObject = array.isarray (object)? [] : {}; // iterate over object, For (let key in object) {if (object.hasownProperty (key)) {newObject[key] = object[key]; } } return newObject; }// Shallow copy implementation; Function shallowCopy(object) {// Only copy object if (! object || typeof object ! == "object") return; Let newObject = array.isarray (object)? [] : {}; // iterate over object, For (let key in object) {if (object.hasownProperty (key)) {newObject[key] = object[key]; } } return newObject; }// Shallow copy implementation; Function shallowCopy(object) {// Only copy object if (! object || typeof object ! == "object") return; Let newObject = array.isarray (object)? [] : {}; // iterate over object, For (let key in object) {if (object.hasownProperty (key)) {newObject[key] = object[key]; } } return newObject; }Copy the code

18. Implement deep copy

  • ** Shallow copy: ** Shallow copy refers to the copying of an attribute value from one object to another. If an attribute value is a reference type, the address of the reference is copied to the object, so that both objects have a reference of the same reference type. Shallow copies can be implemented using object. assign and expansion operators.
  • ** Deep copy: Compared to shallow copy, if an attribute value is of a reference type, it creates a new reference type and copies the corresponding value to it, so that the object gets a new reference type instead of a reference of the original type. Deep copy can be implemented using JSON’s two functions for some objects, but since JSON’s object format is more strict than JS’s, the conversion will fail if the attribute value contains a function or Symbol value

(1) JSON. Stringify ()

  • JSON.parse(JSON.stringify(obj))Is one of the more commonly used deep copy methods, its principle is to useJSON.stringifyjsObject serialization (JSON string), then useJSON.parseTo deserialize (restore)jsObject.
  • This method can be simple and crude to achieve deep copy, but there are problems, if the copied object has functions such as undefined, symbol, when usedJSON.stringify()After processing, they all disappear.
let obj1 = {  a: 0,
              b: {
                 c: 0
                 }
            };
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.a = 1;
obj1.b.c = 1;
console.log(obj1); // {a: 1, b: {c: 1}}
console.log(obj2); // {a: 0, b: {c: 0}}
Copy the code

(2) _. CloneDeep method of lodash library

The library also provides _. CloneDeep for Deep Copy

var _ = require('lodash'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = _.cloneDeep(obj1); console.log(obj1.b.f === obj2.b.f); // falseCopy the code

(3) Handwriting to achieve deep copy function

Function deepCopy(object) {if (! object || typeof object ! == "object") return; let newObject = Array.isArray(object) ? [] : {}; for (let key in object) { if (object.hasOwnProperty(key)) { newObject[key] = typeof object[key] === "object" ? deepCopy(object[key]) : object[key]; } } return newObject; }Copy the code

conclusion

  • Praise attention does not get lost
  • Finish these questions; Welcome to join the group chat 6am wake up club, study hard together!