Still afraid of handwritten questions, this article can help you expand and consolidate their JS foundation, by the way, 90% of the handwritten questions. In my work, I can also implement common requirements by hand, such as deep copy, anti-shake throttling, which can be directly used in future projects to improve the efficiency of project development. No more nonsense, let’s go straight to the code.
1. The realization of the call
- When the first argument is null or undefined, this refers to the global object window, and the autowrap object with the original value, such as String, Number, or Boolean, refers to that original value
- To avoid conflicts between function names and context attributes, use the Symbol type as the unique value
- Execute the function as the context property passed in
- Delete the property after the function completes
- Return execution result
Function.prototype.myCall = function(context,... args){
let cxt = context || window;
// Define the currently invoked method on cxt.func (in order to bind this as an object call)
// Create a unique Symbol variable to avoid duplication
let func = Symbol()
cxt[func] = this;
args = args ? args : []
// Call func as an object call, where this refers to CXT, which is passed in to bind to this
const res = args.length > 0? cxt[func](... args) : cxt[func]();// Delete this method, otherwise it will contaminate the object passed in (add this method)
delete cxt[func];
return res;
}
Copy the code
2. The realization of the apply
- The previous part is the same as call
- The second argument may not be passed, but it must be of type array or array-like
Function.prototype.myApply = function(context,args = []){
let cxt = context || window;
// Define the currently invoked method on cxt.func (in order to bind this as an object call)
// Create a unique Symbol variable to avoid duplication
let func = Symbol()
cxt[func] = this;
// Call func as an object call, where this refers to CXT, which is passed in to bind to this
const res = args.length > 0? cxt[func](... args) : cxt[func]();delete cxt[func];
return res;
}
Copy the code
3. The realization of the bind
To consider:
- Bind () can pass multiple arguments in addition to changing the point to this;
- A new function created by bind may pass in multiple arguments;
- New functions may be called as constructors;
- Functions may return values;
Implementation method:
- The bind method does not execute immediately and returns a function to be executed. (closures)
- Implement scoped binding (APPLY)
- Parameter passing (array passing for apply)
- When used as a constructor, prototype inheritance is performed
Function.prototype.myBind = function (context, ... args) {
// Create a new variable and assign the value this to the current function
const fn = this
// Determine whether or not an argument has been passed, and assign a value if it is null []
args = args ? args : []
// Return a newFn function in which fn is called
return function newFn(. newFnArgs) {
if (this instanceof newFn) {
return newfn(... args, ... newFnArgs) }return fn.apply(context, [...args,...newFnArgs])
}
}
Copy the code
- test
let name = 'wang',age =17;
let obj = {
name:'zhang'.age: this.age,
myFun: function(from,to){
console.log(this.name + 'age' + this.age+'from'+from+'去往'+ to)
}
}
let db = {
name: 'DE m'.age: 99
}
/ / the result
obj.myFun.myCall(db,'chengdu'.'Shanghai');// Dema is 99 years old. She comes from Chengdu and is going to Shanghai
obj.myFun.myApply(db,['chengdu'.'Shanghai']); // Dema is 99 years old. She comes from Chengdu and is going to Shanghai
obj.myFun.myBind(db,'chengdu'.'Shanghai') ();// Dema is 99 years old. She comes from Chengdu and is going to Shanghai
obj.myFun.myBind(db,['chengdu'.'Shanghai') ();// Dema is 99 years old. She comes from Chengdu and goes to Undefined from Shanghai
Copy the code
Parasitic combination inheritance
function Person(obj) {
this.name = obj.name
this.age = obj.age
}
Person.prototype.add = function(value){
console.log(value)
}
var p1 = new Person({name:"Tomato".age: 18})
function Person1(obj) {
Person.call(this, obj)
this.sex = obj.sex
}
// This step is the key to inheritance
Person1.prototype = Object.create(Person.prototype);
Person1.prototype.constructor = Person1;
Person1.prototype.play = function(value){
console.log(value)
}
var p2 = new Person1({name:"Eggs".age: 118.sex: "Male"})
Copy the code
5. ES6 inheritance
// Class is equivalent to the es5 constructor
// When you define a method in a class, do not add function before or after it. Define all methods in the protopyte attribute of the class
// All methods defined in class are not enumerable
// Only methods can be defined in a class, not objects, variables, etc
// Strict mode is the default for both class and method
// Constructor is an implicit property in ES5
class People{
constructor(name='wang',age='27'){
this.name = name;
this.age = age;
}
eat(){
console.log(`The ${this.name} The ${this.age} eat food`)}}// Inherit from the parent class
class Woman extends People{
constructor(name = 'ren',age = '27'){
// Inherit the properties of the parent class
super(name, age);
}
eat(){
// Inherit the superclass method
super.eat()
}
}
let wonmanObj=new Woman('xiaoxiami');
wonmanObj.eat();
// Es5 inheritance creates the instance object of the subclass, and then adds the method of the Parent class to this (parent-.apply (this)).
// Es6 inheritance is to create an instance object of the parent class using the keyword super, and then modify this in the subclass class.
Copy the code
6. The new implementation
- A new object inherited from foo. prototype is created.
- Calls the constructor Foo with the specified arguments and binds this to the newly created object. New Foo is the same as new Foo(), that is, when no argument list is specified and Foo is called with no arguments.
- The object returned by the constructor is the result of the new expression. If the constructor does not explicitly return an object, the object created in Step 1 is used.
- Normally, constructors do not return values, but users can choose to actively return objects to override the normal object creation steps
function Ctor(){... }function myNew(ctor,... args){
if(typeofctor ! = ='function') {throw 'myNew function the first param must be a function';
}
var newObj = Object.create(ctor.prototype); // Create a new object inherited from ctor.prototype
var ctorReturnResult = ctor.apply(newObj, args); // Bind constructor ctor's this to newObj
var isObject = typeof ctorReturnResult === 'object'&& ctorReturnResult ! = =null;
var isFunction = typeof ctorReturnResult === 'function';
if(isObject || isFunction){
return ctorReturnResult;
}
return newObj;
}
let c = myNew(Ctor);
Copy the code
7. Instanceof implementation
- Instanceof is used to determine whether A is an instanceof b. the expression is: A instanceof B, return true if A is an instanceof B, false otherwise.
- The instanceof operator tests whether an object has a constructor’s prototype property in its prototype chain.
- Cannot detect the basic data type, the results on the prototype chain may not be accurate, cannot detect null,undefined
- Implementation: iterates through the left-hand variable’s prototype chain until it finds the right-hand variable’s prototype, returning false if none is found
function myInstanceOf(a,b){
let left = a.__proto__;
let right = b.prototype;
while(true) {if(left == null) {return false
}
if(left == right){
return true
}
left = left.__proto__
}
}
// The instanceof operator is used to determine whether the constructor's prototype property appears anywhere in the object's prototype chain.
function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left), // Get the prototype of the object
prototype = right.prototype; // Get the constructor's prototype object
// Determine whether the constructor's prototype object is on the prototype chain of the object
while (true) {
if(! proto)return false;
if (proto === prototype) return true;
proto = Object.getPrototypeOf(proto); }}Copy the code
8. The Object. The create () implementation
- MDN document
- Object.create() takes the argument Object as a prototype for a newly created empty Object and returns the empty Object
/ / a brief version
function myCreate(obj){
// Declare a function
function C(){};
// Point the function prototype to obj
C.prototype = obj;
// Return the functionalized object
return new C()
}
// Official Polyfill
if (typeof Object.create ! = ="function") {
Object.create = function (proto, propertiesObject) {
if (typeofproto ! = ='object' && typeofproto ! = ='function') {
throw new TypeError('Object prototype may only be an Object: ' + proto);
} else if (proto === null) {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
}
if (typeofpropertiesObject ! = ='undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
function F() {}
F.prototype = proto;
return new F();
};
}
Copy the code
9. The achieve Object. Assign
Object.assign2 = function(target, ... source) {
if (target == null) {
throw new TypeError('Cannot convert undefined or null to object')}let ret = Object(target)
source.forEach(function(obj) {
if(obj ! =null) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
ret[key] = obj[key]
}
}
}
})
return ret
}
Copy the code
10. The realization of the Promise
Implementing A Promise requires A thorough understanding of the Promise A+ specification, but there are A few points to consider in terms of the overall implementation:
- A Promise is a state machine and can only be in the following three states: This is very depressing. The change of the state is one-way. The change of the state can only be changed from Pending -> Fulfilled or Pending -> Rejected
- Then needs to support chained calls
class Promise {
callbacks = [];
state = 'pending';// Add the state
value = null;// Save the result
constructor(fn) {
fn(this._resolve.bind(this), this._reject.bind(this));
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) = > {
this._handle({
onFulfilled: onFulfilled || null.onRejected: onRejected || null.resolve: resolve,
reject: reject
});
});
}
_handle(callback) {
if (this.state === 'pending') {
this.callbacks.push(callback);
return;
}
let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;
if(! cb) {// If nothing is passed in the then
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
cb(this.value);
return;
}
let ret = cb(this.value);
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
cb(ret);
}
_resolve(value) {
if (value && (typeof value === 'object' || typeof value === 'function')) {
var then = value.then;
if (typeof then === 'function') {
then.call(value, this._resolve.bind(this), this._reject.bind(this));
return; }}this.state = 'fulfilled';// Change the state
this.value = value;// Save the result
this.callbacks.forEach(callback= > this._handle(callback));
}
_reject(error) {
this.state = 'rejected';
this.value = error;
this.callbacks.forEach(callback= > this._handle(callback)); }}Copy the code
Promise.resolve
- Promsie.resolve(value) can turn any value to a value whose state is value, but if the value passed in is itself a Promise it will be returned as is.
Promise.resolve(value) {
if (value && value instanceof Promise) {
return value;
} else if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise(resolve= > {
then(resolve);
});
} else if (value) {
return new Promise(resolve= > resolve(value));
} else {
return new Promise(resolve= >resolve()); }}Copy the code
Promise.reject
- Like promise.resolve (), promise.reject () instantiates a Promise in the rejected state. But unlike promise.resolve (), if you pass a Promise object to Promise.reject(), that object becomes the value of the new Promise.
Promise.reject = function(reason) {
return new Promise((resolve, reject) = > reject(reason))
}
Copy the code
Promise.all
- This will be fulfilled if all Promsie passed in are fulfilled, and the new Promise consisting of their values is returned.
- As long as any Promise is rejected, a new Promsie in the rejected state is returned, and its value is the value of the first Promise rejected;
- As long as any Promise is pending, a new Promise in the pending state is returned.
Promise.all = function(promiseArr) {
let index = 0, result = []
return new Promise((resolve, reject) = > {
promiseArr.forEach((p, i) = > {
Promise.resolve(p).then(val= > {
index++
result[i] = val
if (index === promiseArr.length) {
resolve(result)
}
}, err= > {
reject(err)
})
})
})
}
Copy the code
Promise.race
- Promises. Race returns a new instance wrapped by the first instance of all the iterable instances fulfilled or rejected.
Promise.race = function(promiseArr) {
return new Promise((resolve, reject) = > {
promiseArr.forEach(p= > {
Promise.resolve(p).then(val= > {
resolve(val)
}, err= > {
rejecte(err)
})
})
})
}
Copy the code
11. The realization of Ajax
function ajax(url,method,body,headers){
return new Promise((resolve,reject) = >{
let req = new XMLHttpRequest();
req.open(methods,url);
for(let key in headers){
req.setRequestHeader(key,headers[key])
}
req.onreadystatechange(() = >{
if(req.readystate == 4) {if(req.status >= '200' && req.status <= 300){
resolve(req.responeText)
}else{
reject(req)
}
}
})
req.send(body)
})
}
Copy the code
12. Implement anti-skid function (debounce)
- Successive trigger on last execution method, scenario: input box match
let debounce = (fn,time = 1000) = > {
let timeLock = null
return function (. args){
clearTimeout(timeLock)
timeLock = setTimeout(() = >{ fn(... args) },time) } }Copy the code
13. Implement throttling functions
- Triggers only once in a certain period of time, scenario: long list scrolling throttling
let throttle = (fn,time = 1000) = > {
let flag = true;
return function (. args){
if(flag){
flag = false;
setTimeout(() = >{
flag = true; fn(... args) },time) } } }Copy the code
14. Deepclone
- Determine the type, re, and date and return the new object directly
- Null or non-object type, return the original value
- Consider circular references and determine if the hash contains the value directly returned from the hash
- Create a corresponding new obj.constructor to add the hash
- Iterating over object recursion (normal key and key are symbol cases)
function deepClone(obj,hash = new WeakMap(a)){
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return new Date(obj);
if(obj === null || typeofobj ! = ='object') return obj;
// The case of circular references
if(hash.has(obj)){
return hash.get(obj)
}
//new a corresponding object
//obj为Array,相当于new Array()
//obj = new Object();
let constr = new obj.constructor();
hash.set(obj,constr);
for(let key in obj){
if(obj.hasOwnProperty(key)){
constr[key] = deepClone(obj[key],hash)
}
}
// Consider the symbol case
let symbolObj = Object.getOwnPropertySymbols(obj)
for(let i=0; i<symbolObj.length; i++){if(obj.hasOwnProperty(symbolObj[i])){
constr[symbolObj[i]] = deepClone(obj[symbolObj[i]],hash)
}
}
return constr
}
Copy the code
15. Implementation of array flat
let arr = [1.2[3.4[5[6]]]]
console.log(arr.flat(Infinity))// The flat argument specifies the structure depth to extract the nested array. The default value is 1
Copy the code
// Reduce
function fn(arr){
return arr.reduce((prev,cur) = >{
return prev.concat(Array.isArray(cur)? fn(cur):cur) },[]) }Copy the code
16. Function currying
function sumFn(a,b,c){return a+ b + c};
let sum = curry(sumFn);
sum(2) (3) (5)/ / 10
sum(2.3) (5)/ / 10
Copy the code
function curry(fn,... args){
let fnLen = fn.length,
argsLen = args.length;
// Compare the parameters of the function to the parameters currently passed
// Return curry recursively if there are not enough parameters
// If there are enough arguments, call the function to return the corresponding value
if(fnLen > argsLen){
return function(. arg2s){
returncurry(fn,... args,... arg2s) } }else{
returnfn(... args) } }Copy the code
17. Print 1,2,3,4 every second using closures
for (var i=1; i<=5; i++) {
(function (i) {
setTimeout(() = > console.log(i), 1000*i)
})(i)
}
Copy the code
18. Write a jSONP by hand
const jsonp = function (url, data) {
return new Promise((resolve, reject) = > {
// Initialize the URL
let dataString = url.indexOf('? ') = = = -1 ? '? ' : ' '
let callbackName = `jsonpCB_The ${Date.now()}`
url += `${dataString}callback=${callbackName}`
if (data) {
// Have the request parameters, which are added to the URL in turn
for (let k in data) {
url += `${k}=${data[k]}`}}let jsNode = document.createElement('script')
jsNode.src = url
// Trigger the callback, which removes the js tag and the callback bound to the window
window[callbackName] = result= > {
delete window[callbackName]
document.body.removeChild(jsNode)
if (result) {
resolve(result)
} else {
reject('No data returned')}}// js load exception
jsNode.addEventListener('error'.() = > {
delete window[callbackName]
document.body.removeChild(jsNode)
reject('JavaScript resource failed to load ')},false)
// When the js node is added to the document, the request begins
document.body.appendChild(jsNode)
})
}
jsonp('http://192.168.0.103:8081/jsonp', {
a: 1.b: 'heiheihei'
})
.then(result= > {
console.log(result)
})
.catch(err= > {
console.error(err)
})
Copy the code
19. Hand write an observer pattern
class Subject{
constructor(name){
this.name = name
this.observers = []
this.state = 'XXXX'
}
// The observed should provide a method for receiving the observer
attach(observer){
this.observers.push(observer)
}
// Change the state of being observed
setState(newState){
this.state = newState
this.observers.forEach(o= >{
o.update(newState)
})
}
}
class Observer{
constructor(name){
this.name = name
}
update(newState){
console.log(`The ${this.name}say:${newState}`)}}// The observed lamp
let sub = new Subject('light')
let mm = new Observer('Ming')
let jj = new Observer('kin')
// Subscribe to the observer
sub.attach(mm)
sub.attach(jj)
sub.setState('The light is on, the power is on.')
Copy the code
20.EventEmitter implementation
class EventEmitter {
constructor() {
this.events = {};
}
on(event, callback) {
let callbacks = this.events[event] || [];
callbacks.push(callback);
this.events[event] = callbacks;
return this;
}
off(event, callback) {
let callbacks = this.events[event];
this.events[event] = callbacks && callbacks.filter(fn= >fn ! == callback);return this;
}
emit(event, ... args) {
let callbacks = this.events[event];
callbacks.forEach(fn= >{ fn(... args); });return this;
}
once(event, callback) {
let wrapFun = function (. args) { callback(... args);this.off(event, wrapFun);
};
this.on(event, wrapFun);
return this; }}Copy the code
21.Various ways to generate random numbers?
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
Copy the code
22. How to implement random array sort?
let arr = [2.3.454.34.324.32]
arr.sort(randomSort)
function randomSort(a, b) {
return Math.random() > 0.5 ? -1 : 1;
}
Copy the code
23. Write a generic event listener function.
const EventUtils = {
/ / sight, respectively dom0 | | dom2 | | IE way to bind the event
// Add events
addEvent: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on"+ type] = handler; }},// Remove events
removeEvent: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null; }},// Get the event target
getTarget: function(event) {
return event.target || event.srcElement;
},
// Get a reference to the event object, fetching all the information about the event, ensuring that the event can be used at any time
getEvent: function(event) {
return event || window.event;
},
// Prevent events (mainly event bubble, because IE does not support event capture)
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true; }},// Cancel the default behavior of the event
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false; }}};Copy the code
24. Implement the flatten function iteratively.
var arr = [1.2.3[4.5], [6[7[8]]]]
Ret * returns a recursive function **/
function wrap() {
var ret = [];
return function flat(a) {
for (var item of
a) {
if (item.constructor === Array) {
ret.concat(flat(item))
} else {
ret.push(item)
}
}
return ret
}
}
console.log(wrap()(arr));
Copy the code
25.How to implement a sleep
- The sleep function tells the thread to sleep until it is reawakened at the specified time.
function sleep(delay) {
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < delay) {
continue; }}function test() {
console.log('111');
sleep(2000);
console.log('222');
}
test()
Copy the code
26.Achieve regular thousandths (10000 => 10000)
// No decimal point
let num1 = '1321434322222'
num1.replace(/(\d)(? =(\d{3})+$)/g.'$1')
// There is a decimal point
let num2 = '342243242322.3432423'
num2.replace(/(\d)(? =(\d{3})+\.) /g.'$1')
Copy the code
27.Object array deduplicate
Input: [{2, a: 1, b: c: 3}, {2, b: c: 3, a: 1}, {2, d: c: 2}] output: [{2, a: 1, b: c: 3}, {d: 2, c: 2}]Copy the code
- First write a function to sort the key in the object, and then turn it into a string
- The traversal group uses the Set to de-iterate the objects that have been converted to strings
function objSort(obj){
let newObj = {}
// Iterate over the object and sort the keys
Object.keys(obj).sort().map(key= > {
newObj[key] = obj[key]
})
// Turn the sorted array into a string
return JSON.stringify(newObj)
}
function unique(arr){
let set = new Set(a);for(let i=0; i<arr.length; i++){let str = objSort(arr[i])
set.add(str)
}
// Turn the string from the array back to the object
arr = [...set].map(item= > {
return JSON.parse(item)
})
return arr
}
Copy the code
28. Parse URL Params as objects
let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled'; {user: 'name ', id: [123, 456]; // select * from' name 'where' name '=' name 'and' name '=' name '; 'Beijing ', // Chinese must be decoded enabled: true, // not specified value key convention to true} */Copy the code
function parseParam(url) {
const paramsStr = /. + \? (. +) $/.exec(url)[1]; / / will be? I'm going to take the strings that follow
const paramsArr = paramsStr.split('&'); // Store the string in an array, split by &
let paramsObj = {};
// Save params to an object
paramsArr.forEach(param= > {
if (/ = /.test(param)) { // Process parameters with value
let [key, val] = param.split('='); // Separate key and value
val = decodeURIComponent(val); / / decoding
val = /^\d+$/.test(val) ? parseFloat(val) : val; // Determine whether to convert to a number
if (paramsObj.hasOwnProperty(key)) { // Add a value if the object has a key
paramsObj[key] = [].concat(paramsObj[key], val);
} else { // If the object does not have this key, create the key and set the valueparamsObj[key] = val; }}else { // Process parameters without value
paramsObj[param] = true; }})return paramsObj;
}
Copy the code
29. Template engine implementation
Let template = 'I'm {{name}}, age {{age}}, sex {{sex}}'; Let data = {name: 'name ', age: 18} render(template, data); // My name is name, age 18, gender undefinedCopy the code
function render(template, data) {
const reg = /\{\{(\w+)\}\}/; // The template string is regular
if (reg.test(template)) { // Check whether there is a template string in the template
const name = reg.exec(template)[1]; // Find the field of the first string in the current template
template = template.replace(reg, data[name]); // Render the first template string
return render(template, data); // Render recursively and return the rendered structure
}
return template; // If the template does not have a template string, return it directly
}
Copy the code
30. Convert to hump naming
Var s1 = "get-element-by-id" // Convert to getElementByIdCopy the code
var f = function(s) {
return s.replace(/-\w/g.function(x) {
return x.slice(1).toUpperCase(); })}Copy the code
31. Find the character and number that appear most in the string
- Example: abbcccDDDDD -> the most common character is d, which occurs 5 times
let str = "abcabcabcbbccccc";
let num = 0;
let char = ' ';
// Arrange them in a certain order
str = str.split(' ').sort().join(' ');
// "aaabbbbbcccccccc"
// Define the regular expression
let re = /(\w)\1+/g;
str.replace(re,($0, $1) = > {
if(num < $0.length){
num = $0.length;
char = $1; }});console.log(The most 'characters are${char}Appeared,${num}Time `);
Copy the code
32. Images are loading lazily
let imgList = [...document.querySelectorAll('img')]
let length = imgList.length
const imgLazyLoad = function() {
let count = 0
return (function() {
let deleteIndexList = []
imgList.forEach((img, index) = > {
let rect = img.getBoundingClientRect()
if (rect.top < window.innerHeight) {
img.src = img.dataset.src
deleteIndexList.push(index)
count++
if (count === length) {
document.removeEventListener('scroll', imgLazyLoad)
}
}
})
imgList = imgList.filter((img, index) = >! deleteIndexList.includes(index)) })() }// It is better to add anti-shake treatment here
document.addEventListener('scroll', imgLazyLoad)
Copy the code
The resources
- High-frequency JavaScript handwriting
- Early, intermediate front-end should be to master the handwritten code implementation
- 22 high-frequency JavaScript handwriting
- Dead knock 36 JS handwritten problem (understand, promote really big)