Recently the interview is more, often asked handwriting realization, not only to write out, but also understand why, clear. Let me tidy it up here.
new
How to implement new?
new Object()
Create an empty objectobj
.- Get the constructor, which is
arguments
The first term of theta. - Link the prototype of the new object to the incoming object. Internal properties of new objects
__proto__
Point to the prototype of the constructorprototype
The new object can access the properties and methods in the constructor prototype. - use
apply
, will construct the functionthis
Pointing to the new object gives the new object access to the constructor’s properties and methods. - Executes the function to get the return value. If the return value is an object, that object is returned. Otherwise returns
obj
.
function mynew() {
let obj = new Object(a);let Con = [].shift.call(arguments);
obj.__proto__ = Con.prototype;
let res = Con.apply(obj, arguments)
return typeof res == 'object' ? res : obj;
}
Copy the code
Note:
[].shift.call(arguments) is the first item to delete and get arguments.
When [].shift.call() passes arguments, call changes the shift method’s this pointer to point to arguments, so shift removes and gets arguments’ first item.
The same is true for an array-like object. []. Slice. The call (the arguments) is equivalent to an Array. The prototype. Slice. The call (the arguments).
Slice () is used to create a new array containing one or more elements of the original array, without affecting the original array.
call,apply,bind
The first argument to call,apply, and bind is all function context this.
The common denominator is the ability to change the context in which a function is executed, passing a method from one object to another, and executing it immediately. Changing the execution context means that object A has A method, and object B also needs the same method. In this case, we let B borrow the method of object A, which not only completes the requirements, but also reduces the memory consumption.
So, B wants to do the same thing that A did
function B( ) {
A.call(this)}Copy the code
The difference between Apply and call is that the call method takes a list of arguments as its second argument, whereas Apply takes an array of arguments. Apply and call are performed immediately, while bind creates a new function that must be called manually.
To realize the call
Note that they are all methods on function prototypes
- Take the object context that’s passed in. (The this argument can be passed as null; when null, it refers to the window.)
- Sets the function as a property method of the object. So you set the call method to be a property of the context object.
- Process the parameters passed in.
- Pass in the parameters and execute the method.
- Delete the method.
- Returns the result.
Function.prototype.myCall = function (context) {
var context = context || window;
context.fn = this;
let args = [...arguments].slice(1);
letresult = context.fn(... args);delete context.fn;
return result;
}
Copy the code
To realize the apply
The second argument to apply is passed in an array, so you need to check if it exists and expand the array if it does.
Function.prototype.defineApply = function (context, arr) {
var context = context || window;
context.fn = this;
let result;
// Need to check if there is a second argument
// Expand the second argument if it exists
if (arguments[1]) { result = context.fn(... arguments[1]);
} else {
result = context.fn();
}
delete context.fn;
return result;
}
Copy the code
To realize the bind
Bind can also change the execution context of an object; unlike Call and apply, the return value is a function that needs to be called later before it is executed.
// Bind with call and apply
Function.prototype.mybind = function (context) {
let self = this; // Save a reference to the function
return function () { // Return a new function
// return self.apply(context, arguments);
return self.call(context, arguments); }};Copy the code
Function.prototype.myBind = function (context) {
if (typeof this! = ='function') {
throw new TypeError('Error')}var _this = this
var args = [...arguments].slice(1)
// Return a function
return function F() {
// Since we return a function, we can new F(), so we need to determine
if (this instanceof F) {
return new_this(... args, ... arguments) }return_this.apply(context, args.concat(... arguments)) } }Copy the code
If the throttle
Image stabilization
Although you trigger the event, I will execute it n seconds after the event is triggered, subject to the latest trigger event.
Maintain a timer to record the current state. If a timer exists, it is deleted, because the latest trigger event prevails. Reset the timer and execute it.
I’m using the closure here, and I’m also saving the timer. If the closure is not used, a new timer is set in each return and the previous deletion cannot be found.
Application scenario: Search for Association, resize the window, and keep clicking during login
function debounce(fn,wait) {
let timer = null;
return () = > {
clearTimeout(timer);
timer = setTimeout(() = > {
fn.apply(this.arguments); }, wait); }}Copy the code
The throttle
Events are continuously fired, executed only once in a period of time.
Time stamp: set the initial value to 0. If the current time minus the previous timestamp is greater than the set wait time, the function is executed. Update the current timestamp.
Application scenario: The scroll event is triggered when the mouse is repeatedly clicked
function throttle(func,wait) {
let pre = 0;
return () = > {
let cur = Date.now();
// If the interval exceeds the specified time, the function is executed.
if (cur - pre > wait) {
func.apply(this.arguments);
pre = Date.now(); }}}Copy the code
Deep copy and shallow copy
Shallow copy
Shallow copy refers to the creation of new data that has an exact copy of the original data attribute values. If the property is of a primitive type, the value of the primitive type is copied. If the attribute is a reference type, the memory address is copied. That is, shallow copies copy a layer, and deep reference types share memory addresses.
Shallow copy mode:
- Object.assign
- Array.prototype.slice()
- Array.prototype.concat()
- Extended operator
function slowclone(obj) {
let cloneobj = {};
for (let k in obj) {
if (obj.hasOwnProperty(k)) {
cloneobj[k]=obj[k]
}
}
return cloneobj;
}
Copy the code
Note: For in traverses the properties in the prototype chain, so use hasOwnProperty to exclude the prototype chain.
Deep copy
Deep copy opens a new stack, two object properties complete the same, but corresponding to two different addresses, modify the properties of one object, does not change the properties of the other object.
Recursively deep copy: iterate through sets of objects until they are full of primitive data types, and then copy.
- If it is not an object or null, it is returned without copying.
- If it is a Date or re, return a new instance of new.
Note: Objects have the problem of circular references. Objects’ properties refer to the object itself. Therefore, you can create an additional storage space to store the current object and the relationship between the stored objects. To copy the current object, go to the storage space and check whether the object has been copied. If yes, return to the object in the storage space. If no, continue copying.
function deepclone(obj, hash = new Map(a)) {
if(! obj ||typeofobj ! = ="object") return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
let cloneobj = obj.constructor();
if (hash.get(obj)) return hash.get(obj);
hash.set(obj, cloneobj);
for (let k in obj) {
if(obj.hasOwnProperty(k)) { cloneobj[k] = deepclone(obj[k], hash); }}return cloneobj;
}
Copy the code
instanceof
Determine if B is on the prototype chain of A. Keep looking for A’s __proto__ until it’s B.prototype or null.
function myinstanceof(A, B) {
let protoA = A.__proto__;
let prototypeB = B.prototype;
while (true) {
if (protoA == null) {
return false;
}
if (protoA == prototypeB) {
return true; } protoA = protoA.__proto__; }}Copy the code
Object.create()
Used to create a new object that inherits the prototype of another object (O). So f.prototype = o;
function createObj(o) {
// The argument o is passed to return the instance's __porto__, which is the explicit prototype of the instance constructor
function F() {} // constructor
F.prototype = o;
return new F(); // Return the instance
}
Copy the code
map
What a Map does is it creates a new array, iterates through the original array, takes each element out and does some transformation and appends it into the new array.
Array.prototype.newMap = function (fn) {
let newArr = [];
for (let i = 0; i < this.length; i++) {
newArr.push(fn(this[i], i, this)); // This refers to the array that calls the newMap method
}
return newArr;
};
let arr = [1.2.3];
let res = arr.newMap((a) = > a + 1);
console.log(res);
Copy the code
Reduce parameters are as follows
arr.reduce((previousValue, currentValue, currentIndex, array) => {}, initialValue)
Copy the code
Reduce implementation map
Array.prototype.newMap = function (fn, Arg) {
var res = [];
this.reduce((prev, curr, index, array) = > {
res.push(fn.call(Arg, curr, index, array));
}, 0); // Specify initialValue=0, so start with currentIndex=0, the first one
return res;
};
Copy the code
forEach
The forEach() method performs the given function once on each element of the array.
arr.forEach(function(currentValue, currentIndex, arr) {}, thisArg)
/ / currentValue required. The current element
/ / currentIndex optional. The index of the current element
/ / arr is optional. The array object to which the current element belongs.
ThisArg This parameter is optional. Used as the value of this when the callback function is executed.
Copy the code
Array.prototype._forEach = function(fn, thisArg) {
if (typeoffn ! = ='function') throw "Parameters must be functions.";
if(!Array.isArray(this)) throw "You can only use forEach on arrays.";
let arr = this;
for(let i=0; i<arr.length; i++) {
fn.call(thisArg, arr[i], i, arr)
}
}
Copy the code
Promise
• A Promise is an object that represents and passes the end result of an asynchronous operation.
Solve the callback hell problem caused by nested callback functions.
Promise
function myPromise(executor) {
let self = this; // keep this. Prevent this from pointing unclearly to later methods
self.status = 'pending';// The default state of promise is pending
self.value = undefined;// Save the value passed by the successful callback
self.reason = undefined;// Save the value passed by the failed callback
self.successCB = [];// Stores the callback function corresponding to the depressing state
self.failCB = [];// Stores the callback function corresponding to the Rejected state
function resolve(value) {
if (self.status === 'pending') { // This can only be fulfilled by a pending state.
self.status = 'resolved';// The success function changes its status to Resolved
self.value = value;// Save the successful values
self.successCB.forEach(fn= >fn()); }}function reject(reason) {
if (self.status === 'pending') { // Only the pending state => Rejected state
self.status = 'rejected';// The failed function modifies its function to Rejected
self.reason = reason;// Save the failed value
self.failCB.forEach(fn= >fn()); }}// Catch an exception thrown in the excutor executor
try {
executor(resolve,reject)
} catch (err) {
reject(err)
}
}
Copy the code
Promise.prototype.then
Then methods are methods on the prototype chain
myPromise.prototype.then = function (onResolved, onRejected) {
let self = this;
if (self.status === 'pending') {
self.successCB.push(() = > {
onResolved(self.value);// Pass the success value reserved for resolve as an argument
})
self.failCB.push(() = > {
onRejected(self.reason);// Pass the reject value reserved by the reject function as an argument})}if (self.status === 'resolved') {
onResolved(self.value);// Pass the success value reserved for resolve as an argument
}
if (self.status === 'rejected') {
onRejected(self.reason);// Pass the reject value reserved by the reject function as an argument}}Copy the code
Promise.all
Promise.all takes an array of Promise objects as arguments, and calls the. Then method when all of the Promise objects in the array are resolved or reject, which are executed concurrently.
The promise.all () method wraps multiple Promise instances into a single Promise object (p), which takes an array (P1, P2,p3) as an argument. The array does not have to be full of Promise objects, but it must have an Iterator interface. Resolve converts it to a Promise object before processing.
The state of the Promise object (p) generated with promise.all () is determined by the Promise objects (P1, P2,p3) in the array;
1. If all Promise objects (P1, P2,p3) become fullfilled, the generated Promise object (P) will also become fullfilled. The results from p1, P2,p3 Promise objects will form an array and be returned to the callback function passed to P.
If p1, P2, and P3 have a Promise object in the Rejected state,p will change to the Rejected state, and the return value of the first rejected object will be passed to p’s callback function.
function myall(promises) {
return new Promise((resolve, reject) = > {// Return a new Promise
let ret = [];// Define an empty array to hold the results
let count = 0;
let done = (i, data) = > {// Handle data functions
ret[i] = data;
count++;
if (count === promises.length) {// When I is equal to the length of the array passed
resolve(ret); // Execute resolve and place the result in}}for (let i = 0; i < promises.length; i++){
promises[i].then((data) = > done(i, data), reject); // Pass the result and index to the done function}})}Copy the code
Promise.race
The promise.race () method again wraps multiple Promise instances into a new Promise instance. const p = Promise.race([p1, p2, p3]);
In the above code, the state of P changes as long as one of the first instances of P1, P2, and P3 changes state. The return value of the first changed Promise instance is passed to p’s callback.
In promise.race(), the promise state can only change once, that is, resolve and reject can only be executed once.
function myrace(promises) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < promises.length; i++) { promises[i].then(resolve, reject); }}); }Copy the code
Currie,
Step by step, passing some arguments at a time, and returning a more concrete function that accepts the rest of the arguments. There may be multiple layers of such functions that take partial arguments until the result is returned.
function curry(fn, args) {
var length = fn.length;// Get the number of fn parameters
var args = args || [];// Get the last argument
return function(){// Return a function
// Get the parameters and convert them to an array
var newArgs = Array.prototype.slice.call(arguments);
newArgs=args.concat(newArgs);// Merge this parameter with the last parameter
if (newArgs.length < length) {// If the number of parameters is smaller than the number of parameters, continue collecting
return curry.call(this,fn,newArgs);
}else{
return fn.apply(this,newArgs);// Otherwise return the result of the function execution}}}Copy the code
The Cremation is also important!
Object. The prototype. The toString () method returns a string, said the Object when the Object is represented as text value or when to expect a string reference Object, this method is called automatically.
When an operation or operation requires a String and the object is not a String, a String conversion is triggered, automatically converting non-string attempts to String.
function curyAdd(){
var args = Array.prototype.slice.call(arguments);
var adder = function () { args.push(... arguments);return adder;
}
adder.toString = function () {
return args.reduce((pre, cur) = > {
return pre+cur;
},0)}return adder;
}
console.log(cury(1.2) (3));
Copy the code
Ajax
Ajax simply puts an intermediate layer (the Ajax engine) between the user and the server, makes an asynchronous request to the server via an XmlHttpRequest object, gets data from the server, and then updates the page by manipulating the DOM with javascript. Asynchronize user actions and server responses. One of the most critical steps is getting the request data from the server.
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.error(xhr.statusText); }}}// The type of request, the URL of the request, and whether the request is sent asynchronously
xhr.open("get", url, true);
// Pass in the requested data
xhr.send(null);
Copy the code
I am the dividing line ~~~~
Follow up to meet other supplement!