preface
Handwriting is essential in the front end of the interview process, because handwriting is the most impressive test of your knowledge of a certain principle. Here are some of the handwritten questions I encountered during the interview review process. I will realize the idea to write out with you to share, and the realization is just a reference, interested can click on the reference answer, there is a question please correct.
Principle of implementation
Implement a new operator
First we need to understand what the new operator does
- The new operator returns an object.
- Object that points to the prototype of the constructor
- If the constructor has a return, we need to check the return, if it is an object, then return the newly created object, if it is not an object
Refer to the answer
function myNew(fn, ... args) {
let obj = Object.create(fn.prototype);
let res = fn.apply(obj, args);
return res instanceof Object ? res : obj;
}
Copy the code
Implement an instanceof operator
The first thing we need to know is that Instanceof is judged by the prototype chain
Refer to the answer
The instanceof operator works by judging the prototype chain, so as long as you compare _proto_ on the left to prototype on the rightCopy the code
function myInstance(left, right) {
Return false if left is a base type
if(typeofleft ! = ='object' || left === null) return false;
let proto = Object.getPrototypeOf(left);
while(true) {
if(proto === null) return false;
if(proto === right.prototype) return true;
proto = Object.getPrototypeOf(proto); }}Copy the code
Implement an Apply
The following aspects should be paid attention to in implementing Apply:
1. Do not take the first parameter because the first parameter is the context.
2. Methods assigned to objects need to be deleted without affecting the original object.
3. Use undefined to point the context to the window object
Refer to the answer
Function.prototype.myApply = function(context, [...args]) {
// Check if the context is empty, if it is empty, it points to the window object
context = context || window;
context.fn = this; context.fn(... args);delete context.fn;
}
Copy the code
Implementing a Call
Call’s implementation is similar to apply’s, but the level of parameter handling is slightly different.
Refer to the answer
Function.prototype.myCall = function(context) {
// Check if the context is empty, if it is empty, it points to the window object
context = context || window;
let args = [...arguments].slice(1);
context.fn = this;
context.fn(args);
delete context.fn;
}
Copy the code
Implement a bind
The implementation of bind needs to be aware of the currization of the function.
Refer to the answer
Function.prototype.myBind = function(context) {
const self = this;
let args = [...arguments].slice(1);
return function() {
// Consider the curryization of the function
let newArgs = [...arguments];
this.apply(context, newArgs.concat(args))
}
}
Copy the code
Fulfill a promise
The realization of promise is necessary to focus on, I divide a few steps to see:
1. Deal with the synchronization logic first, such as the state value changes, will not change, and which attribute values, etc.
2. Reprocess the asynchronous logic in the form of callbacks and stored lists.
3. Redeal with the logic of chain call, chain call is more complex, pay more attention to the object of Thenable.
4. Other ways to deal with promises.
Finally, HERE I recommend an article to you, write very good! Promise the article
Refer to the answer
class Promise(exector) {
constructor() {
this.value = undefined;
this.reason = ' ';
this.state = 'pending';
this.onResolveList = [];
this.onRejectList = [];
const resolve = (value) = > {
if(this.state === 'fulfilled') {
this.value = value
this.state = 'fulfilled';
this.onResolveList.forEach((fn) = >{ fn(); })}};const reject = (reason) = > {
if(this.state === 'rejected') {
this.reason = reason
this.state = 'rejected';
this.onRejectList.forEach((fn) = >{ fn(); }}})try {
exector(resolve, reject);
} catch(err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
const promise2 = new Promise((reslove, reject) = > {
if(this.state === 'fulfilled') {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, reslove, reject);
}
if(this.state === 'rejected') {
onRejected(this.reason);
resolvePromise(promise2, x, reslove, reject);
}
if(this.state === 'pending') {
onResolveList.push((a)= > {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, reslove, reject);
});
onRejectList.push((a)= > {
let x = onRejected(this.reason); resolvePromise(promise2, x, reslove, reject); }); }});return promise2;
}
race(promises) {
return new Promise((resolve, reject) = > {
for(let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
})
}
all(promises) {
let arr = [];
let i = 0;
function processData(index, data) {
arr[index] = data;
i++;
if(i === promises.length) { resolve(data); }}return new Promise((resolve, reject) = > {
for(let i = 0; i < promises.length; i++) {
promises[i].then((val) = > {
processData(i, val);
}, reject)
}
})
}
resolve(val) {
return new Promise((resovle, reject) = > {
resovle(val);
})
}
reject(val) {
return new Promise((resovle, reject) = >{ reject(val); }}})// Loop references, thenable objects, promise objects
resolvePromise(promise2, x, reslove, reject) {
if(promise2 === x) {
reject('Circular reference');
return;
}
// Prevent multiple calls
let called;
// Check the type of the value of x, if not an object or function, return resolve
if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {
// Then errors can also enter a catch
try {
if(called) return;
let then = x.then;
if(typeof then === 'function') {
then.call(x, (y) => {
if(called) return;
called = true;
resolvePromise(promise2, y ,reslove, reject)
}, (err) => {
if(called) return;
reject(err);
called = true; })}else{ resolve(x); }}catch(err) {
if(called) return;
reject(err);
called = true; }}else{ resolve(x); }}Copy the code
Implement a parasitic composite inheritance
The main concern for parasitic combinatorial inheritance is the orientation of the constructor child. And the inherited drawback: super assembly calls twice.
Refer to the answer
function Super() {}
function Sub() {
Super.call(this)
}
Sub.prototype = new Super();
Sub.constructor = Sub;
Copy the code
Business problem realization
How to implement an anti – shake function
The understanding of anti-shake is best based on the memory of service scenarios: Anti-shake is generally used in the input box scenario. So there are two aspects to the implementation:
1. When the event is triggered again within a certain period of time, the timer should be reset.
2. Reset the timer after the execution.
Refer to the answer
function debounce(cb, delay, ... args) {
let time = null;
return function() {
if(time) {
clearTimeout(time);
}
time = setTimeout((a)= > {
cb.apply(this. args); clearTimeout(time); }, delay); }}Copy the code
How to implement a throttling function
For throttling functions, you also need to remember them in context. Generally used in rolling events, will only be triggered once in a certain period of time. There are also two points to note at the implementation level:
1. Use a lock variable to ensure that it fires only once in a certain period of time.
2. After the execution, unlock the lock
Refer to the answer
function tr(fn, time, ... args) {
let lock = false;
return function() {
if(lock) return;
lock = true;
setTimeout((a)= > {
fn.apply(this. args); lock =false;
}, time)
}
}
Copy the code
Realize a line and hump conversion
This is a test of the regular and replace methods.
Refer to the answer
function camelize(str) {
return (str + ' ').replace(/-\D/g.function(match) {
return match.charAt(1).toUpperCase()
})
}
Copy the code
function hyphenate(str) {
return (str + ' ').replace(/[A-Z]/g.function(match) {
return The '-'+ match.toLowerCase(); })}Copy the code
Implement a sleep function
Sleep can be implemented in many ways, promise, async/await, etc. Here are some of the most common ones.
Refer to the answer
function sleep(time) {
return new Promise((resolve, reject) = > {
setTimeout((a)= > {
resolve(true);
}, time)
})
}
Copy the code
Implement a Currie function
To implement currification is to call multiple arguments with different lengths. The advantage is that you can observe an intermediate procedure, or intermediate variable, when you call a parameter. Add (1)(2)(3
Refer to the answer
function curry(fn) {
const finalLen = fn.length
let args = [].slice.call(this.1)
return function currying () {
args = args.concat(Array.from(arguments))
const len = args.length
return len >= fn.length ? fn.apply(this, args) : currying
}
}
Copy the code
Implementing an Ajax
Implementing an Ajax is essentially a matter of using the XMLHttpRequest object and its API methods. Here, I suggest that it be packaged in the form of promise as far as possible for easy use.
Refer to the answer
function ajax({url, methods, body, headers}) {
return new Promise((resolve, reject) = > {
let request = new XMLHttpRequest();
request.open(url, methods);
for(let key in headers) {
let value = headers[key]
request.setRequestHeader(key, value);
}
request.onreadystatechange = (a)= > {
if(request.readyState === 4) {
if(request.status >= '200' && request.status < 300) {
resolve(request.responeText);
} else {
reject(request)
}
}
}
request.send(body)
})
}
Copy the code
Implement a deep copy
Deep copy is a common method of serialization and deserialization, but there are two drawbacks to this method:
Values of the type undefined, NULL, and symbol are deleted
2. An error occurs when a circular reference is encountered.
We need to keep a close eye on circular references when implementing deep copy.
In the following methods, I mainly solve the problem of circular references in the form of arrays. So why have two arrays?
Basically an array maintains references to old objects, and an array maintains references to new objects.
Refer to the answer
function deepClone(obj) {
const parents = [];
const children = [];
function helper(obj) {
if(obj === null) return null;
if(typeofobj ! = ='object') return obj;
let child, proto;
if(Array.isArray(obj)) {
child = [];
} else {
proto = Object.getPrototypeOf(obj);
child = Object.create(proto);
}
// Handle circular references
let index = parents.indexOf(obj)
if(index === - 1) {
parents.push(obj);
children.push(child)
} else {
return children[index];
}
// for in iteration
for(let i inobj) { child[i] = helper(obj[i]); }}}Copy the code
push
In the current epidemic situation, only entering large companies, graduates can have a good guarantee. Small companies will be forced to recruit passively if they are unable to survive, lay off workers or become permanent employees.
The writer works for Alibaba Retail Link. If you want to tweet in, you can email [email protected]. Massive HC!! You can also add the q group: 912253914. Edit your resume in your spare time.