Are you still afraid of handwritten questions? This article can help you expand and consolidate your JS foundation, and handle 90% of handwritten questions by the way. In the work, common requirements can also be realized by handwriting, such as deep copy, anti shake and throttling, which can be directly used in future projects to improve project development efficiency. No more nonsense, let's go directly to the code.
1.call implementation
-
When the first parameter is null or undefined, this points to the global object window. If the value is the original value, it points to the automatic wrapping object of the original value, such as String, Number and Boolean
-
In order to avoid the conflict between the function name and the attribute of the context, the Symbol type is used as the unique value
-
Execute the function as an incoming context attribute
-
Delete the property after the function is executed
-
Return execution result
"I am an old programmer who has been engaged in Web front-end development for 6 years. At the beginning of this year, I spent a month sorting out a full set of Web front-end training course (Video + source code + Notes + project practice) which is most suitable for self-study in 2021 Buddy buddy, from the most basic HTML+CSS+JS to mobile HTML5, and various frameworks and new technologies, have been packaged and packaged for every front end partner. This is the front end learning place. Welcome to beginners and advanced partners (all front-end courses are concerned about my WeChat official account: web front end learning circle, and then receive web after receiving the reply).
Function.prototype.myCall = function(context,...args){ let cxt = context || window; //Define the currently called method in 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 in the form of object call. At this time, this points to cxt#, that is, the incoming this point that needs to be bound const res = args.length > 0 ? cxt[func](...args) : cxt[func](); //Delete this method, otherwise it will pollute the incoming object (add this method) delete cxt[func]; return res; }
2. Implementation of apply
-
The first part is the same as call
-
The second parameter can not be passed, but the type must be array or class array
Function.prototype.myApply = function(context,args = []){ let cxt = context || window; //Define the currently called method in 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 in the form of object call. At this time, this points to cxt#, that is, the incoming this point that needs to be bound const res = args.length > 0 ? cxt[func](...args) : cxt[func](); delete cxt[func]; return res; }
3. Implementation of bind
Consider:
-
bind() can pass in multiple parameters besides this;
-
The new function created by bind may pass in multiple parameters;
-
The new function may be called as a constructor;
-
Function may have a return value;
Implementation method:
-
The bind method will not be executed immediately and needs to return a function to be executed; (closure)
-
Implement scope binding (apply)
-
Parameter passing (array parameter passing of apply)
-
When used as a constructor, prototype inheritance is performed
Function.prototype.myBind = function (context, ...args) { //Create a new variable with the value this, indicating the current function const fn = this //Judge whether the parameter is passed in. If it is empty, assign [] args = args ? args : [] //Returns a newFn function in which fn is called return function newFn(...newFnArgs) { if (this instanceof newFn) { return new fn(...args, ...newFnArgs) } return fn.apply(context, [...args,...newFnArgs]) } }
-
test
let name = 'Xiao Wang',age =17; let obj = { name:'Xiao Zhang', age: this.age, myFun: function(from,to){ console.log(this.name + ' Age ' + this.age+'come from '+from+'Go to'+ to) } } let db = { name: 'Dema', age: 99 } //result obj.myFun.myCall(db,'Chengdu','Shanghai'); //Dema, aged 99, from Chengdu to Shanghai obj.myFun.myApply(db,['Chengdu','Shanghai']); //Dema, aged 99, from Chengdu to Shanghai obj.myFun.myBind(db,'Chengdu','Shanghai')(); //Dema, aged 99, from Chengdu to Shanghai obj.myFun.myBind(db,['Chengdu','Shanghai'])(); //Dema, aged , 99, from Chengdu, Shanghai to , undefined
4. Parasitic combinatorial 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:"egg", age: 118, sex: "male"})
5.6 succession
//class is equivalent to the constructor in es5 //When defining methods in class, you cannot add function before and after them. They are all defined in the protocol attribute of class //All methods defined in class are not enumerable //class can only define methods, not objects, variables, etc //Strict mode is the default in class and method //constructor in es5 is an implicit property class People{ constructor(name='wang',age='27'){ this.name = name; this.age = age; } eat(){ console.log(`${this.name} ${this.age} eat food`) } } //Inherit parent class class Woman extends People{ constructor(name = 'ren',age = '27'){ //Inherit parent class properties super(name, age); } eat(){ //Inherit parent method super.eat() } } let wonmanObj=new Woman('xiaoxiami'); wonmanObj.eat(); //es5 inheritance first creates the instance object of the subclass, and then adds the method of the parent class to this (Parent.apply(this)). //es6 inheritance uses the keyword super to first create the instance object this of the parent class, and then modify this in the child class.
6. Implementation of new
-
One inherited from foo A new object of prototype is created.
-
Call the constructor Foo with the specified parameters and bind this to the newly created object. New Foo is equivalent to new Foo(), that is, Foo is called without any parameters without specifying a parameter list.
-
The object returned by the constructor is the result of the new expression. If the constructor does not explicitly return an object, use the object created in step 1.
-
Generally, the constructor does not return a value, but the user can choose to actively return the object to override the normal object creation steps
function Ctor(){ .... } function myNew(ctor,...args){ if(typeof ctor !== 'function'){ throw 'myNew function the first param must be a function'; } var newObj = Object.create(ctor.prototype); //Create one that inherits from ctor New object for prototype var ctorReturnResult = ctor.apply(newObj, args); //Bind this of constructor ctor 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);
7. Implementation of instanceof
-
Instanceof is used to judge whether A is an instance of B. the expression is: A instanceof B. If A is an instance of B, it returns true; otherwise, it returns false.
-
The instanceof operator is used to test whether an object has the prototype attribute of a constructor in its prototype chain.
-
The basic data type cannot be detected. The results on the prototype chain may not be accurate. Null and undefined cannot be detected
-
Implementation: traverse the prototype chain of the variable on the left until the prototype of the variable on the right is found. If it is not found, it returns false
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 prototype attribute of the constructor appears anywhere in the prototype chain of the object. function myInstanceof(left, right) { let proto = Object.getPrototypeOf(left), //Gets the prototype of the object prototype = right.prototype; //Gets the {prototype} object of the constructor //Judge whether the {prototype} object of the constructor is on the prototype chain of the object while (true) { if (!proto) return false; if (proto === prototype) return true; proto = Object.getPrototypeOf(proto); } }
8.Object. Implementation of create()
-
MDN document
-
Object.create() takes the parameter object as the prototype of a newly created empty object and returns the empty object
//Abbreviated Edition function myCreate(obj){ //New declaration of a function function C(){}; //Point the prototype of the function to obj C.prototype = obj; //Returns the strength object of this function return new C() } //Official Polyfill if (typeof Object.create !== "function") { Object.create = function (proto, propertiesObject) { if (typeof proto !== 'object' && typeof proto !== '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 (typeof propertiesObject !== '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(); }; }
9. Implement 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 }
10. Implementation of promise
To realize Promise, you need to fully understand Promise A + specification. However, from the perspective of overall implementation, the following points need to be considered:
-
Promise is essentially a state machine, and the state can only be the following three: Pending, completed and Rejected. The change of state is one-way, and can only be from Pending - > completed or Pending - > Rejected. The change of state is irreversible
-
then needs to support chained calls
class Promise { callbacks = []; state = 'pending';//Increase status value = null;//Save results 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 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 state this.value = value;//Save results this.callbacks.forEach(callback => this._handle(callback)); } _reject(error) { this.state = 'rejected'; this.value = error; this.callbacks.forEach(callback => this._handle(callback)); } }
Promise.resolve
-
Promsie.resolve(value) can convert any value to value. The status is Promise with full Promise, but if the passed in value itself is Promise, it will be returned as it 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()); } }
Promise.reject
-
And Promise Resolve() is similar to Promise Reject () instantiates a Promise in the rejected state. But with Promise The difference between resolve () and Promise Reject() passes a Promise object, which will become the value of the new Promise.
Promise.reject = function(reason) { return new Promise((resolve, reject) => reject(reason)) }
Promise.all
-
If all incoming promsies are full, a new Promise in the status of full is returned, which is composed of their values;
-
As long as one Promise is rejected, a new Promsie in the rejected state is returned, and its value is the value of the first rejected Promise;
-
As long as one Promise is pending, a new Promise in pending status 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) }) }) }) }
Promise.race
-
Promise.race returns a new instance wrapped by the first fully or rejected instance of all iteratable instances.
Promise.race = function(promiseArr) { return new Promise((resolve, reject) => { promiseArr.forEach(p => { Promise.resolve(p).then(val => { resolve(val) }, err => { rejecte(err) }) }) }) }
11. Implementation 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) }) }
12. Implement anti shake function (debounce)
-
Continuously trigger the method at the last execution, scene: input box matching
let debounce = (fn,time = 1000) => { let timeLock = null return function (...args){ clearTimeout(timeLock) timeLock = setTimeout(()=>{ fn(...args) },time) } }
13. Implement the throttle function
-
Trigger 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) } } }
14. Deep clone
-
Judge the type, regular and date, and return the new object directly
-
Null or non object type, return the original value directly
-
Consider the circular reference, and judge if the hash contains the value directly returned from the hash
-
Create a new obj Add hash to constructor
-
Traversal object recursion (normal key and key are symbol)
function deepClone(obj,hash = new WeakMap()){ if(obj instanceof RegExp) return new RegExp(obj); if(obj instanceof Date) return new Date(obj); if(obj === null || typeof obj !== 'object') return obj; //Circular reference if(hash.has(obj)){ return hash.get(obj) } //new , a corresponding object //obj is Array, which is equivalent to new Array() //obj is Object, which is equivalent to 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 case of symbol 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 }
15. Implementation of array flattening (flat)
let arr = [1,2,[3,4,[5,[6]]]] console.log(arr.flat(Infinity))//The flat parameter specifies the structure depth of the nested array to be extracted. The default value is 1
//Implement with reduce function fn(arr){ return arr.reduce((prev,cur)=>{ return prev.concat(Array.isArray(cur)?fn(cur):cur) },[]) }
16. Function coritization
function sumFn(a,b,c){return a+ b + c}; let sum = curry(sumFn); sum(2)(3)(5)//10 sum(2,3)(5)//10
function curry(fn,...args){ let fnLen = fn.length, argsLen = args.length; //Compare the parameters of the function with the current passed in parameters //If the parameters are not enough, continue to recursively return curry //If the parameters are enough, call the function to return the corresponding value if(fnLen > argsLen){ return function(...arg2s){ return curry(fn,...args,...arg2s) } }else{ return fn(...args) } }
17. Use closures to print 1,2,3,4 every second
for (var i=1; i<=5; i++) { (function (i) { setTimeout(() => console.log(i), 1000*i) })(i) }
18. Write a jsonp
const jsonp = function (url, data) { return new Promise((resolve, reject) => { //Initialize url let dataString = url.indexOf('?') === -1 ? '?' : '' let callbackName = `jsonpCB_${Date.now()}` url += `${dataString}callback=${callbackName}` if (data) { //There are 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 a callback. After triggering, delete 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 loading exception jsNode.addEventListener('error', () => { delete window[callbackName] document.body.removeChild(jsNode) reject('JavaScript Resource loading failed') }, false) //When adding a js node to the document, start the request 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) })
19. Handwriting an observer mode
class Subject{ constructor(name){ this.name = name this.observers = [] this.state = 'XXXX' } //The observer should provide a way to accept 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(`${this.name}say:${newState}`) } } //Observer light let sub = new Subject('lamp') let mm = new Observer('Xiao Ming') let jj = new Observer('Xiao Jian') //Subscribe to # observers sub.attach(mm) sub.attach(jj) sub.setState('The light is on. There's a call')
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; } }
21. Various methods of generating random numbers?
function getRandom(min, max) { return Math.floor(Math.random() * (max - min)) + min }
22. How to realize random sorting of arrays?
let arr = [2,3,454,34,324,32] arr.sort(randomSort) function randomSort(a, b) { return Math.random() > 0.5 ? -1 : 1; }
23. Write a general event listener function.
const EventUtils = { //The visual ability uses dom0 | dom2 | ie to bind events respectively //Add event 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 event 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 event target getTarget: function(event) { return event.target || event.srcElement; }, //Get the reference of the event object, get all the information of the event, and ensure that the event can be used at any time getEvent: function(event) { return event || window.event; }, //Block events (mainly event bubbling, because IE} does not support event capture) stopPropagation: function(event) { if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } }, //Cancels the default behavior for events preventDefault: function(event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } } };
24. Implement the flatten function in an iterative manner.
var arr = [1, 2, 3, [4, 5], [6, [7, [8]]]] /** * Use recursion to handle * wrap # internal protection Save the result, * 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));
25. How to implement a sleep
-
The sleep function is used to make the thread sleep and wake up again at a 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()
26. Realize regular segmentation of the thousandth (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,')
27. Object array de duplication
input: [{a:1,b:2,c:3},{b:2,c:3,a:1},{d:2,c:2}] output: [{a:1,b:2,c:3},{d:2,c:2}]
-
First, write a function to sort the key s in the object, and then turn them into strings
-
Traversing the array, use Set to de duplicate the object converted into a string
function objSort(obj){ let newObj = {} //Traverse the object and sort the key s Object.keys(obj).sort().map(key => { newObj[key] = obj[key] }) //Convert the sorted array to a string return JSON.stringify(newObj) } function unique(arr){ let set = new Set(); for(let i=0;i<arr.length;i++){ let str = objSort(arr[i]) set.add(str) } //Returns a string from an array to an object arr = [...set].map(item => { return JSON.parse(item) }) return arr }
28. Resolve URL Params as object
let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled'; parseParam(url) /* result { user: 'anonymous', id: [ 123, 456 ], // The repeated {key s} should be assembled into an array, and those that can be converted into numbers will be converted into number types city: 'Beijing ', / / Chinese needs decoding enabled: true, // The value of {key} is not specified, and the Convention is} true } */
function parseParam(url) { const paramsStr = /.+\?(.+)$/.exec(url)[1]; //Will? Take out the following string const paramsArr = paramsStr.split('&'); //Split the string with & and save it in the array let paramsObj = {}; //Save params to object paramsArr.forEach(param => { if (/=/.test(param)) { //Handle parameters with {value} let [key, val] = param.split('='); //Split # key # and # value val = decodeURIComponent(val); //Decode val = /^\d+$/.test(val) ? parseFloat(val) : val; //Determine whether to convert to number if (paramsObj.hasOwnProperty(key)) { //If the object has a key, add a value paramsObj[key] = [].concat(paramsObj[key], val); } else { //If the object does not have this key, create a key and set the value paramsObj[key] = val; } } else { //Processing parameters without {value} paramsObj[param] = true; } }) return paramsObj; }
29. Implementation of template engine
let template = 'I am{{name}},Age{{age}},Gender{{sex}}'; let data = { name: 'full name', age: 18 } render(template, data); //My name is, age 18, gender undefined
function render(template, data) { const reg = /\{\{(\w+)\}\}/; //Template string regular if (reg.test(template)) { //Determine whether there is a template string in the template const name = reg.exec(template)[1]; //Find the field of the first template 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 has no template string, it is returned directly }
30. Convert to hump naming
var s1 = "get-element-by-id" //Convert to getElementById
var f = function(s) { return s.replace(/-\w/g, function(x) { return x.slice(1).toUpperCase(); }) }
31. Find the most characters and number in the string
-
Example: abbcccddddd - > d has the largest number of characters and appears 5 times
let str = "abcabcabcbbccccc"; let num = 0; let char = ''; //Arrange them in a certain order str = str.split('').sort().join(''); // "aaabbbbbcccccccc" //Define regular expressions let re = /(\w)\1+/g; str.replace(re,($0,$1) => { if(num < $0.length){ num = $0.length; char = $1; } }); console.log(`The largest number of characters is ${char},There it is ${num}second`);
32. Picture loading
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's best to add anti shake treatment here document.addEventListener('scroll', imgLazyLoad)