JS handwriting topic summary
Summarize the common handwritten JavaScript questions in the interview, such as call, apply, bind, promise, etc. Only if you can skillfully master the common handwritten JavaScript questions in the interview, you can make the interviewer’s eyes shine without saying much and directly answer the questions.
1. Implement call, apply and bind
1. Implement Call
Function: calls a function with the specified this value and one or more arguments;
- The first parameter is zero
null
orundefined
When,this
Pointing to a global objectwindow
, an auto-wrapped object that points to the original value, such asString, Number, Boolean
; - To avoid function names and context (
context
) attribute conflict, useSymbol
Type as unique value; - Function as the context passed in (
context
) property execution; - After the function completes, delete the attribute;
- Returns the execution result;
// ES5
Function.prototype.call2 = function(context) {
if (typeof this! = ='function') {
throw new TypeError('Type Error');
}
var context = context || window;
// Bind this to a method on an object
context.fn = this;
var args = [];
// Store function variable parameters
for (var i=1; i<arguments.length; i++) {
args.push('arguments[' + i + '] ');
}
// Execute the method just bound on the context
var result = eval('context.fn(' + args + ') ');
// Delete the method you just created
delete context.fn;
// Returns the return value of the function call
return result;
}
// ES6 (recommended)
// Pass parameters from an array to one by one instead of... Arguments can also be used instead of extension operators
Function.prototype.call2 = function (context, ... args) {
// You can also use ES6 to set default parameters for parameters
context = context || window;
args = args ? args : [];
// Add a unique attribute to the context to avoid overwriting the original attribute
const key = Symbol(a); context[key] =this;
// Call the function with an implicit binding
constresult = context[key](... args);// Delete the added attribute
delete context[key];
// Returns the return value of the function call
return result;
}
// Test it
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
console.log(bar.call2(null)); / / 2
console.log(bar.call2(obj, 'kevin'.18)); / / 1
Copy the code
2. Implement Apply
Just like call, the only difference is that call passes in an unlimited number of arguments, while apply passes in an array.
- Former part and
call
The same; - The second argument may not be passed, but the type must be array or array-like.
// ES5
Function.prototype.apply2 = function(context,arr) {
if (typeof this! = ='function') {
throw new TypeError('Type Error');
}
var context = context || window;
context.fn = this;
if(! arr) {var result = context.fn();
} else {
var args = [];
for (var i=0; i<arr.length; i++) {
args.push('arr[' + i + '] ');
}
var result = eval('context.fn(' + args + ') ');
}
delete context.fn;
return result;
}
// ES6 (recommended)
Function.prototype.apply2 = function (context, args) {
// You can also use ES6 to set default parameters for parameters
context = context || window;
args = args ? args : [];
// Add a unique attribute to the context to avoid overwriting the original attribute
const key = Symbol(a); context[key] =this;
// Call the function with an implicit binding
constresult = context[key](... args);// Delete the added attribute
delete context[key];
// Returns the return value of the function call
return result;
}
// Test it
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
console.log(bar.apply2(null)); / / 2
console.log(bar.apply2(obj, 'kevin'.18)); / / 1
Copy the code
3. Bind
The bind method creates a new function. When bind() is called, this of the new function is specified as the first argument to bind(), and the remaining arguments are used as arguments to the new function.
Need to consider:
bind()
In addition tothis
More than one parameter can be passed;bind
A new function created may pass in multiple arguments;- New functions may be called as constructors;
- A function may have a return value;
Implementation method:
bind
Method does not execute immediately and needs to return a function to be executed; (closures)- Implementing scoped binding (
apply
); - Parameter passing (
apply
Array pass parameter); - When the as
The constructor
When carrying onPrototype inheritance
;
// ES5
Function.prototype.bind = function (oThis) {
var aArgs = Array.prototype.slice.call(arguments.1);
var fToBind = this;
var fNOP = function () {};
var fBound = function () {
fBound.prototype = this instanceof fNOP ? new fNOP() : fBound.prototype;
return fToBind.apply(this instanceof fNOP ? this : oThis || this, aArgs )
}
if( this.prototype ) {
fNOP.prototype = this.prototype;
}
return fBound;
}
// ES6 (recommended)
Function.prototype.bind2 = function (context, ... args) {
const fn = this;
args = args ? args : [];
return function newFn(. newFnArgs) {
// determine if it is used as a constructor
if (this instanceof newFn) {
return newfn(... args, ... newFnArgs) }// When executed as a normal function, use apply to execute the function
return fn.apply(context, [...args,...newFnArgs])
}
}
// Test it
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
const b = bar.bind2(null.'kevin'); / / 2
b(18) / / 2
const b_ = bar.bind2(obj, 'kevin');
b_(18); / / 1
Copy the code
2. Implement new
The new operator is used to create instances of user-defined object types or built-in objects with constructors.
- Create a new object;
- Sets the prototype of the object to function
prototype
Object; - Let the function of the
this
Point to the object and execute the constructor code (add attributes to the new object); - Determine the return value type of the function. If it is a value type, return the created object. If it is a reference type, return the object of the reference type.
// ES5 (recommended)
function newFunc() {
// Create a new object
var obj = new Object(a);// Extract the first argument, the constructor
var Constructor = [].shift.call(arguments);
// Set the prototype of the object to the function's 'prototype' object.
obj.__proto__ = Constructor.prototype;
// Make the function 'this' point to the object and execute the constructor code (add attributes to the new object)
var ret = Constructor.apply(obj, arguments);
// Determine the return type of the function, if it is a value type, return the newly created object. If it is a reference type, an object of that reference type is returned.
return typeof ret === 'object' ? ret : obj;
}
// ES6 (recommended)
function newFunc(. args) {
const obj = Object.create({});
const Constructor = [].shift.call(args);
obj.__proto__ = Constructor.prototype;
const result = Constructor.apply(obj, args);
return typeof result === 'object' ? result : obj;
}
function F(name, age) {
this.name = name;
this.age = age
}
const newF = newFunc(F, 'dell'.18);
console.log(newF.name, newF.age); // dell 18
Copy the code
3. Seven inheritance modes
1. Prototype chain inheritance
Advantages:
- The ability to inherit attributes and methods from the parent class;
Disadvantages:
- Problem 1: Included in the prototype
Reference type attribute
Will be shared by all instances (cannot be implementedMultiple inheritance
); - Question 2:
Subclass instantiation
Cannot pass an argument to the parent constructor. - Problem 3: Unable to obtain properties and methods on the prototype of a subclass after instantiation;
function Parent() {
this.name = 'parent1';
this.play = [1.2.3];
this.add = function() {
return {
name: this.name,
play: [1.2.3]
}
}
}
Parent.prototype.getName = function () {
return this.name;
}
function Child() {
this.type = 'child2';
this.add2 = function() {
return this.type;
}
}
Child.prototype.add1 = function() {
return this.type;
}
Child.prototype.dell = 'dell';
// Prototype chain inheritance
Child.prototype = new Parent();
// Create an instance
var c = new Child();
console.log(c.name, c.type, c.add(), c.add2(), c.getName()); // All of them are available
// Cannot read properties and methods on its own prototype
console.log(c.add1()); // Cannot read
console.log(c.dell);
// Multiple inheritance cannot be used. You can modify attributes on the parent stereotype, but if the attribute is a reference attribute, it will share the same instance, as follows:
var child1 = new Child();
var child2 = new Child();
child1.name = 'dell';
child1.play[2] = 56;
console.log(child1.name); // dell
console.log(child2.name); // parent1
console.log(child1.play); / /,2,56 [1]
console.log(child2.play); / /,2,56 [1]
Copy the code
Constructor inheritance
Advantages:
- Solve the problem of prototype chain inheritance (1) can not achieve multiple inheritance; Class instantiation does not take arguments to the constructor.
Disadvantages:
- Only the attributes and methods of the parent class can be inherited, but not the attributes and methods of the parent class prototype.
- Because methods are defined in constructors, they are created each time a subclass is instantiated;
function Parent(name) {
this.name = name;
this.age = '18';
this.play = [1.2.3];
this.getAge = function() {
return this.age;
}
}
Parent.prototype.lee = 'lee';
Parent.prototype.getName = function () {
return this.name;
}
function Child(name) {
/ / the refs
Parent.call(this, name); // Inherits the parent class
this.type = 'child2';
this.getDell_ = function() {
return this.age;
}
}
Child.prototype.getDell = function() {
return this.age;
}
// Create an instance
var c1 = new Child('name');
var c2 = new Child('name');
// Get subclass prototype attributes and methods
console.log(c1.name, c1.age, c1.play, c1.getAge(), c1.getDell_(), c1.getDell()) // parent1 18 18 18 18
// Multiple inheritance can be implemented, i.e. no longer sharing the same instance
c1.play[1] = 99
console.log(c1.play) / / [1, 99, 3]
console.log(c2.play) / / [1, 2, 3]
// Can't get properties and methods on the superclass prototype
console.log(c1.lee) // undefined
console.log(c1.getName()) / / an error
Copy the code
3. Combinatorial inheritance
Advantages:
- It solves the problem of using prototype chain inheritance or constructor inheritance alone.
Disadvantages:
- Because composite inheritance is a combination of stereotype chain inheritance and constructor inheritance, the parent class is called once in both stereotype chain inheritance and constructor inheritance, so the parent class is called twice.
function Parent() {
console.log('Two calls')
this.name = 'parent1';
this.age = '18';
this.play = [1.2.3];
this.getAge = function() {
return this.age
}
}
Parent.prototype.lee = 'lee'
Parent.prototype.getName = function () {
return this.name;
}
function Child() {
Parent.call(this); // Call Parent a second time
this.type = 'child2';
}
Child.prototype.getDell = function() {
return this.age
}
Child.prototype = new Parent(); // Call Parent for the first time
Child.prototype.constructor = Child; // Manually hang constructor to avoid losing access to Parent
var c = new Child();
console.log(c.name, c.age, c.getAge()) // parent1 18 18
console.log(c.lee) // lee
console.log(c.getName()) // parent1
Copy the code
4. Original type inheritance
Advantages:
- The ability to inherit attributes and methods from the parent class;
Disadvantages:
- Does not solve the reference type sharing problem (multiple inheritance cannot be implemented);
var Parent = {
name: 'dell'.arr: [18.19.20].getName: function() {
return this.name
}
}
let p1 = Object.create(Parent);
p1.name = 'tom'
p1.arr.push('lee')
let p2 = Object.create(Parent);
p2.name = 'lee';
p2.arr.push('dell')
console.log(p1.name, p1.arr, p1.getName())// tom [18, 19, 20, "lee", "dell"] tom
console.log(p2.name, p2.arr, p2.getName()) // lee [18, 19, 20, "lee", "dell"] lee
// Advantages: Can inherit properties and methods Disadvantages: does not solve the reference problem, create the same reference
Copy the code
Parasitic inheritance
Advantages:
- The ability to inherit attributes and methods from the parent class;
Disadvantages:
- Does not solve the reference type sharing problem (multiple inheritance cannot be implemented);
var Parent = {
name: 'dell'.arr: [18.19.20].getName: function() {
return this.name
}
}
let p1 = Object.create(Parent);
p1.getArr = function() {
return this.name
}
console.log(p1.name, p1.arr, p1.getName(), p1.getArr()) // dell [18, 19, 20] dell dell
Copy the code
6. Combinatorial parasitic inheritance
Advantages:
- Object. Create (Parent. Prototype); Object. Create (Parent. Prototype)
Disadvantages:
- ES6 class inheritance is recommended.
function Parent() {
console.log('Executed once, not twice')
this.name = 'dell'
this.age = 18
this.getName = function() {
return this.name
}
}
Parent.prototype.getAge = function() {
return this.age;
}
function Child() {
Parent.call(this);
this.type = 'type'
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
// Create an instance
var p = new Child();
console.log(p.name, p.age, p.getName()) // dell 18 dell
console.log(p.getAge()) / / 18
console.log(p.type) // type
// console.log(c.getdell ()) // why can't access the methods on the subclass prototype
Copy the code
7. ES6 inheritance mode
// class is equivalent to the ES5 constructor;
// use the protopyte property of the class to define a method.
// All methods defined in class are not enumerable;
// only methods can be defined in class.
// Strict mode is the default in both class and method;
// ES5 constructor = implicit;
class People {
constructor(name='dai',age='27') {
this.name = name;
this.age = age;
}
eat() {
console.log(`The ${this.name} The ${this.age} eat food`); }}// Inherits the parent class
class Woman extends People {
constructor(name = 'dai',age = '27') {
// Inherits the superclass attributes
super(name, age);
}
eat() {
// Inherits the parent method
super.eat()
}
}
let wonmanObj = new Woman('dai');
wonmanObj.eat();
// ES5 inherits the instance object of the subclass and then adds the methods of the Parent class to this (parent.apply (this));
// ES6 inheritance uses the keyword super to create an instance object of the parent class this, and finally to modify this in the subclass class;
Copy the code
4. Throttling and anti-shaking
1. The image stabilization (debounce)
- If a high-frequency event is triggered, the event is executed once after n seconds. If the event is triggered again within n seconds, the time is recalculated.
- Scenario: Input Search box searches for input;
<input oninput="debounceInput(event)" />
function debounce(fn, delay) {
var timeout = null;
return function() {
// Clear timer and recalculate time
clearTimeout(timeout);
// Execute the function when the time is up
timeout = setTimeout(() = > {
fn.apply(this.arguments)
}, delay)
}
}
function onInput(event) {
if (event.target.value) {
console.log(event.target.value); }}let debounceInput = debounce(onInput, 300)
// Purpose: Search for input boxes
Copy the code
2. The throttle
- After the high-frequency event is triggered, it is executed only once within n seconds. Throttling is the execution frequency of dilution function.
- Scenario: long list scrollthrottling, resize;
2.1 the timestamp
- First throttle, the first time to execute immediately, but after stopping the start, can not execute again;
// Timestamp implementation
function throttle(fn, delay) {
var last = 0;
return function () {
var now = Date.now();
if (now - last >= delay) {
last = now;
fn.apply(this.arguments)}}}Copy the code
2.2 setTimeout
- Tail throttling does not execute the function immediately, but after delay;
// The timer is implemented
// The delay timer will be executed for the last time after the last stop.
function throttle(fn, delay) {
var timer = null;
return function() {
if(! timer) { timer =setTimeout(() = > {
fn.apply(this.arguments);
timer = null;
}, delay)
}
}
}
Copy the code
2.3 Timestamp + setTimeout
- The first and tail throttling method is realized
// Time stamp + timer implementation
function throttle(fn, delay){
let timer = null;
let startTime = 0;
return function() {
let curTime = Date.now();
let remaining = delay - (curTime - startTime);
clearTimeout(timer);
if (remaining <= 0) {
fn.aplly(this.arguments);
startTime = Date.now();
} else {
timer = setTimeout(() = > {
fn.aplly(this.arguments);
startTime = Date.now();
}, remaining)
}
}
}
Copy the code
5, The Promise series handwritten
1. Write basic Promises by hand
class Prom {
static resolve (value) {
if (value && value.then) {
return value
}
return new Prom(resolve= > resolve(value))
}
constructor (fn) {
this.value = undefined
this.reason = undefined
this.status = 'PENDING'
// Maintain a resolve/pending function queue
this.resolveFns = []
this.rejectFns = []
const resolve = (value) = > {
// Notice the setTimeout here
setTimeout(() = > {
this.status = 'RESOLVED'
this.value = value
this.resolveFns.forEach(({ fn, resolve: res, reject: rej }) = > res(fn(value)))
})
}
const reject = (e) = > {
setTimeout(() = > {
this.status = 'REJECTED'
this.reason = e
this.rejectFns.forEach(({ fn, resolve: res, reject: rej }) = > rej(fn(e)))
})
}
fn(resolve, reject)
}
then (fn) {
if (this.status === 'RESOLVED') {
const result = fn(this.value)
// Return a Promise
// If resolved, execute
return Prom.resolve(result)
}
if (this.status === 'PENDING') {
// Return a Promise
return new Prom((resolve, reject) = > {
// In the queue, resolved
this.resolveFns.push({ fn, resolve, reject })
})
}
}
catch (fn) {
if (this.status === 'REJECTED') {
const result = fn(this.value)
return Prom.resolve(result)
}
if (this.status === 'PENDING') {
return new Prom((resolve, reject) = > {
this.rejectFns.push({ fn, resolve, reject })
})
}
}
}
Prom.resolve(10).then(o= > o * 10).then(o= > o + 10).then(o= > {
console.log(o)
})
return new Prom((resolve, reject) = > {
reject('Error')
}).catch(e= > {
console.log('Error', e)
})
Copy the code
2. Promise.resolve
Promise.resolve(value)
Any value can be converted to a value ofvalue
The state isfulfilled
的Promise
, but if the passed value itself isPromise
It is returned as is;
Promise.resolve = (param) = > {
if(param instanceof Promise) return param;
return new Promise((resolve, reject) = > {
if(param && param.then && typeof param.then === 'function') {
// A successful param state calls resolve, which changes the state of the new Promise to successful and vice versa
param.then(resolve, reject);
} else{ resolve(param); }})}Copy the code
3. Promise.reject
- and
Promise.resolve()
A similar,Promise.reject()
It instantiates onerejected
The state of thePromise
. But with thePromise.resolve()
The difference is, if you givePromise.reject()
Pass aPromise
Object, the object becomes newPromise
The value of the;
Promise.reject = function(reason) {
return new Promise((resolve, reject) = > reject(reason))
}
Copy the code
4. Promise.prototype.finally
- Whether you succeed or fail, you will get there
finally
, andfinally
After that, you can continuethen
. And it passes the value exactly as it wasthen
;
Promise.prototype.finally = function (callback) {
return this.then((value) = > {
return Promise.resolve(callback()).then(() = > {
return value;
});
}, (err) = > {
return Promise.resolve(callback()).then(() = > {
throw err;
});
});
}
Copy the code
5. Promise.all
- Incoming all
Promsie
Are allfulfilled
, returns the values of the values in the statefulfilled
The newPromise
; - As long as there is one
Promise
是rejected
, the returnrejected
State of the newPromsie
, and its value is the firstrejected
的Promise
The value of the; - As long as there is one
Promise
是pending
, returns onepending
State of the newPromise
;
function PromiseAll(promiseArray) {
return new Promise((resolve, reject) = > {
if (!Array.isArray(promiseArray)) {
return reject(new Error('The argument passed must be an array! '));
}
let arr = [];
const len = promiseArray.length;
let counter = 0;
for (let i=0; i<len; i++) {
Promise.resolve(promiseArray[i]).then((res) = > {
// arr.push(res);
counter++;
arr[i] = res;
if (counter === len) {
resolve(arr);
}
}).catch(err= > reject(err))
}
})
}
const pro1 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('1')},1000)})const pro2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('2')},2000)})const pro3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('3')},3000)})const promise = PromiseAll([pro1, pro2, pro3]).then((res) = > {
console.log(res)
}).catch(err= > console.log(err))
Copy the code
6. Promise.race
Promise.race
Returns the first of all iterable instancesfulfilled
或rejected
The new instance is wrapped after the instance.
Promise.race = function(promiseArr) {
return new Promise((resolve, reject) = > {
for (let i=0; i<promiseArr.length; i++) {
Promise.resolve(promiseArr[i]).then(res= > {
resolve(res)
}).catch(err= > reject(err))
}
})
}
Copy the code
7. Promise.allSettled
Promise.allSettled()
Method returns apromise
thepromise
In all givenpromise
Parsed or rejected, and each object describes eachpromise
Results.
// The format is as follows
Promise.allSettled([
Promise.resolve('a'),
Promise.reject('b'),
])
.then(arr= > {
console.log(res);
/ / /
// { status: 'fulfilled', value: 'a' },
// { status: 'rejected', reason: 'b' },
// ]
});
Copy the code
function PromiseAllSettled(arr) {
return new Promise((resolve, reject) = > {
if (!Array.isArray(arr)) {
throw new Error('Must be an array')}let count = 0;
let len = arr.length;
let array = [];
for (let i=0; i<len; i++) {
Promise.resolve(arr[i]).then((item) = > {
count++;
array[i] = {status: 'fulfilled'.value: item};
if (count >= len) {
resolve(array)
}
}).catch((reason) = > {
count++;
array[i] = {status: 'rejected'.value: reason};
if (count >= len) {
resolve(array)
}
})
}
})
}
const pro1 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('1')},1000)})const pro2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('2')},2000)})const pro3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('3')},3000)})const promise = PromiseAllSettled([pro1, pro2, pro3]).then((res) = > {
console.log(res)
}).catch(err= > console.log(err))
Copy the code
8. Promise.any
-
The method takes a set of Promise instances as parameters and returns them wrapped as a new Promise instance. As long as one parameter instance becomes a depressing state, the packaging instance will become a depressing state. If all parameter instances become the Rejected state, the wrapper instance becomes the Rejected state.
-
Promise.any() is like the promise.race () method, except that promise.any () does not end when a Promise changes to the Rejected state. You must wait until all the parameters Promise become rejected.
// Promise.any
function PromiseAny(arr) {
return new Promise((resolve, reject) = > {
if (!Array.isArray(arr)) {
throw new Error('Must pass in an array')}let len = arr.length;
let count = 0;
let result = [];
for (let i=0; i<len; i++) {
Promise.resolve(arr[i]).then(res= > {
resolve(res);
}).catch(err= > {
result[i] = err;
count++;
if (count === len) {
reject(`AggregateError: All promises were rejected`}})}})}/ / test
const pro1 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('1')},1000)})const pro2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('2')},2000)})const pro3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('3')},3000)})const promise = PromiseAny([pro1, pro2, pro3]).then((res) = > {
console.log(res)
}).catch(err= > console.log(err))
Copy the code
6. Ajax implementation
- use
Promise
encapsulationAjax
;
function ajax(method, url, body, headers) {
// Return a Promise
return new Promise((resolve, reject) = > {
// Initialize an XMLHttpRequest() object
let xhr = new XMLHttpRequest();
// Call the open method and pass in three parameters: request method, URL, synchronous asynchrony
xhr.open(methods, url, true);
// Loop through the request header and set the request header setRequestHeader()
for(let key in headers) {
if (headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, headers[key])
}
}
// Listen for onreadyStatechange () and return responseText if readyState === 4
xhr.onreadystatechange(() = > {
if(xhr.readyState == 4) {
if(xhr.status >= '200' && xhr.status <= 300){
resolve(xhr.responeText)
} else {
reject(xhr)
}
}
})
// Call the send() method to pass the parameters
xhr.send(body)
})
}
Copy the code
Async/await
function asyncToGenerator(generatorFunc) {
// Returns a new function
return function() {
// Call generator to generate iterators
Var gen = testG()
const gen = generatorFunc.apply(this.arguments)
// Return a promise because the outside is using the return value of this function either as.then or await
// var test = asyncToGenerator(testG)
// test().then(res => console.log(res))
return new Promise((resolve, reject) = > {
// Internally define a step function to override the yield barrier step by step
// Key has two values, next and throw, corresponding to gen's next and throw methods respectively
The arg argument is used to yield the promise resolve value to the next yield
function step(key, arg) {
let generatorResult
// This method needs to be wrapped in a try catch
// If an error occurs, discard the promise, reject the error, and catch the error
try {
generatorResult = gen[key](arg)
} catch (error) {
return reject(error)
}
// gen.next() results in a {value, done} structure
const { value, done } = generatorResult
if (done) {
// If this is already done, resolve the promise
// This done will not be true until the last call to next
{done: true, value: 'success'}
// This value is the return value of the generator function
return resolve(value)
} else {
// Call gen.next() every time except at the end
{value: Promise, done: false}
Resolve accepts a Promise as an argument
// Then will only be called when the promise argument is resolved
return Promise.resolve(
// This value corresponds to the promise after yield
value
).then(
// When the value promise is resove, next is executed
// And whenever done is not true, the promise is recursively unwrapped
// Next ().value.then(value => {
// gen.next(value).value.then(value2 => {
// gen.next()
//
// // now done is true and the entire promise is resolved
// // the most external test().then(res => console.log(res)) then starts execution
/ /})
// })
function onResolve(val) {
step("next", val);
},
// If promise is rejected, enter step again
// The difference is that this try catch calls Gen. throw(err).
// Then you catch the promise, reject it
function onReject(err) {
step("throw", err);
},
)
}
}
step("next"); }}})Copy the code
8. Array flattening
1. Ordinary recursion
var arr = [1.2.3.4[4.5[5.6.7]]]
function flatten(arr) {
let array = [];
for (let i=0; i<arr.length; i++) {
if (Array.isArray(arr[i])) {
array = array.concat(flatten(arr[i]));
} else{ array.push(arr[i]); }}return array;
}
const result = flatten(arr);
console.log(result);
Copy the code
2. reduce
var arr = [1.2.3.4[4.5[5.6.7]]];
function flatten(arr) {
return arr.reduce((prev, cur) = > {
return prev.concat(Array.isArray(cur) ? flatten(cur) : cur); }}, [])const result = flatten(arr);
console.log(result);
Copy the code
3.toString + split
var arr = [1.2.3.4[4.5[5.6.7]]];
function flatten(arr) {
return arr.toString().split(', ').map((res) = >{
return Number(res); })}const result = flatten(arr);
console.log(result);
Copy the code
4. Invoke Flat in ES6
var arr = [1.2.3.4[4.5[5.6.7]]];
function flatten(arr) {
return arr.flat(Infinity);
}
const result = flatten(arr);
console.log(result);
Copy the code
5. Regex and JSON methods are processed together
let arr = [1[2[3[4.5]]].6];
function flatten(arr) {
let str = JSON.stringify(arr);
str = str.replace(/(\[|\])/g.' ');
str = '[' + str + '] ';
return JSON.parse(str);
}
console.log(flatten(arr)); // [1, 2, 3, 4,5]
Copy the code
6. Flatten with the second argument — remember
// Array flattening
const arr = [1.2.3.4[4[5.6[7.8.9]]]];
function flatten(arr, index) {
return index > 0 ? arr.reduce((prev, curr) = > {
return prev.concat(Array.isArray(curr) ? flatten(curr, index - 1) : curr);
}, []) : arr.slice();
}
console.log(arr.flat(2));
console.log(flatten(arr, 2));
Copy the code
Deformation of 7.
// Array flattening
const arr = [1.2.3.4[4[5.6[7.8.9]]]];
function flatten(arr, index) {
let array = [];
if (index > 0) {
for (let i=0; i<arr.length; i++) {
if (Array.isArray(arr[i])) {
array = array.concat(flatten(arr[i], index - 1))}else {
array.push(arr[i])
}
}
} else {
array = arr.slice();
}
return array;
}
console.log(arr.flat(3));
console.log(flatten(arr, 3));
Copy the code
8. 2 – forEach deformation
// Array flattening
const arr = [1.2.3.4[4[5.6[7.8.9]]]];
function flatten(arr, index) {
let array = [];
if (index > 0) {
arr.forEach(item= > {
if (Array.isArray(item)) {
array = array.concat(flatten(item, index - 1))}else{ array.push(item); }})}else {
array = arr.slice();
}
return array;
}
console.log(arr.flat(2));
console.log(flatten(arr, 2));
Copy the code
9. Instanceof function
instanceof
Is to judgeA
Whether it isB
, the expression is:A instanceof B
If theA
是B
Is returnedtrue
Otherwise returnfalse
;instanceof
The operator tests whether an object has a constructor in its stereotype chainprototype
Properties;- Cannot detect basic data types, results on the prototype chain may not be accurate, cannot detect
null,undefined
; - Implementation: Iterate through the prototype chain for the left variable until it finds the one for the right variable
prototype
If not found, returnfalse
;
function instanceOf(left, right) {
// Get the prototype of the object
var proto = left.__proto__;
// Get the prototype of the type
var prototype = right.prototype;
while(true) {
if (proto === null) return false;
if (proto === prototype) return true; proto = proto.__proto__; }}function a() {
this.name = 'dell';
this.age = 18;
}
var newA = new a();
console.log(instanceOf(newA, a))
Copy the code
10. Various sorts of arrays
1. Bubble sort
var a = [1.3.6.3.23.76.1.34.222.6.456.221];
function bubbleSort(array) {
if (array.length < 2) return array;
for (let i=0; i<array.length; i++) {
for (let j=i+1; j<array.length; j++) {
if (array[j]<array[i]) {
letnum = array[i]; array[i] = array[j]; array[j] = num; }}}return array;
}
let arr = bubbleSort(a);
console.log(arr);
Copy the code
2. Quicksort
var a = [1.3.6.3.23.76.1.34.222.6.456.221];
function quickSort(array) {
if (array.length <= 1) return array;
const len = array.length;
const index = Math.floor(len >> 1);
const pivot = array.splice(index, 1) [0]; // Using splice returns the deleted form array
const left = [];
const right = [];
for (let i=0; i<len; i++) {
if (array[i] <= pivot) {
left.push(array[i]);
} else if (array[i] > pivot) { If {} else {} else {}right.push(array[i]); }}return quickSort(left).concat([pivot], quickSort(right));
}
const arr = quickSort(a);
console.log(arr);
Copy the code
3. Insert sort
var a = [1.3.6.3.23.76.1.34.222.6.456.221];
function insertSort(array) {
const len = array.length;
let current;
let prev;
for (let i=1; i<len; i++) {
current = array[i];
prev = i - 1;
while (prev >= 0 && array[prev] > current) {
array[prev + 1] = array[prev];
prev--;
}
array[prev + 1] = current;
}
return array
}
const arr = insertSort(a);
console.log(arr);
Copy the code
4. Select sort
var a = [1, 3, 6, 3, 23, 76, 1, 34, 222, 6, 456, 221];
function selectSort(array) {
const len = array.length
let temp
let minIndex
for (let i = 0; i < len - 1; i++) {
minIndex = i;
for (let j = i + 1; j < len; j++) {
if (array[j] <= array[minIndex]) {
minIndex = j;
}
}
temp = array[i];
array[i] = array[minIndex];
array[minIndex] = temp;
}
return array;
}
selectSort(a); // [1, 1, 3, 3, 6, 6, 23, 34, 76, 221, 222, 456]
Copy the code
5. Heap sort
var a = [1.3.6.3.23.76.1.34.222.6.456.221];
function heap_sort(arr) {
var len = arr.length;
var k = 0;
function swap(i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function max_heapify(start, end) {
var dad = start;
var son = dad * 2 + 1;
if (son >= end) return;
if (son + 1 < end && arr[son] < arr[son + 1]) {
son++;
}
if(arr[dad] <= arr[son]) { swap(dad, son); max_heapify(son, end); }}for (var i = Math.floor(len / 2) - 1; i >= 0; i--) {
max_heapify(i, len)
}
for (var j = len - 1; j > k; j--) {
swap(0, j);
max_heapify(0, j);
}
return arr;
}
heap_sort(a); // [1, 1, 3, 3, 6, 6, 23, 34, 76, 221, 222, 456]
Copy the code
6. Merge sort
var a = [1.3.6.3.23.76.1.34.222.6.456.221];
function mergeSort(array) {
const merge = (right, left) = > {
const result = [];
let il = 0;
let ir = 0;
while (il < left.length && ir < right.length) {
if (left[il] < right[ir]) {
result.push(left[il++]);
} else{ result.push(right[ir++]); }}while (il < left.length) {
result.push(left[il++]);
}
while (ir < right.length) {
result.push(right[ir++]);
}
return result;
}
const mergeSort = array= > {
if (array.length === 1) { return array }
const mid = Math.floor(array.length / 2);
const left = array.slice(0, mid);
const right = array.slice(mid, array.length);
return merge(mergeSort(left), mergeSort(right));
}
return mergeSort(array);
}
mergeSort(a); // [1, 1, 3, 3, 6, 6, 23, 34, 76, 221, 222, 456]
Copy the code
11. Currization functions
// recursive traversal
function curry(fn, ... args) {
var len = fn.length;
var args = args || [];
return function() {
var newArgs = args.concat(Array.prototype.slice.call(arguments));
if (newArgs.length < len) {
return curry.call(this, fn, ... newArgs) }else {
return fn.apply(this, newArgs); }}}function add(a, b, c) {
return a + b + c;
}
var a = curry(add);
console.log(a(1.2.3));
Copy the code
// ES6
function curry(fn, ... args) {
if (args.length < fn.length) return (. args1) = >curry(fn, ... args, ... args1);else returnfn(... args); }function add(a, b, c) {
return a + b + c;
}
var a = curry(add);
var b = a(1.2.3);
console.log(b);
Copy the code
Closure JS Basic Programming questions (bytes)
var foo = function(. args) {
// Implement the function body
}
var f1 = foo(1.2.3);
f1.getValue(); // 6 Output is the sum of parameters
var f2 = foo(1) (2.3);
f2.getValue(); / / 6
var f3 = foo(1) (2) (3) (4);
f3.getValue(); / / 10
Copy the code
answer
var foo = function(. args) {
const target = (. args2) = >foo(... args, ... args2); target.getValue =() = > args.reduce((p, q) = > p + q, 0)
return target
}
var f1 = foo(1.2.3);
console.log(f1.getValue()) // 6 Output is the sum of parameters
var f2 = foo(1) (2.3);
console.log(f2.getValue()); / / 6
var f3 = foo(1) (2) (3) (4);
console.log(f3.getValue()) / / 10
Copy the code
Currie transformation programming problem
Complete the combo function. It takes any number of single-parameter functions (functions that take only one argument) as arguments and returns a function. Function calls such as f(g(h(a)) can be abbreviated as combo(f, g, h)(a).
// ES6 -- reduce
const combo = (. args) = > {
args.length && args.reverse()
return prop= >
args.reduce((acc, cur) = > {
return cur(acc);
}, prop)
}
// ES5 -- for
function combo () {
const cbs = [...arguments].reverse();
return function () {
var res = cbs[0] (... arguments);for (let i = 1; i < cbs.length; i++) {
res = cbs[i](res);
}
returnres; }}/* Here is the test code */
const addOne = (a) = > a + 1
const multiTwo = (a) = > a * 2
const divThree = (a) = > a / 3
const toString = (a) = > a + ' '
const split = (a) = > a.split(' ')
split(toString(addOne(multiTwo(divThree(Awesome!)))))
// => ["4", "4", "5"]
const testForCombo = combo(split, toString, addOne, multiTwo, divThree)
testForCombo(Awesome!)
// => ["4", "4", "5"]
Copy the code
12, array deduplication
1. Set
let arr = [1.2.3.4.4.5.6.7];
[...new Set(arr)]
Copy the code
2. Set + Array.from
let arr = [1.2.3.4.4.5.6.7];
function unique(arr) {
return Array.from(new Set(arr));
}
Copy the code
3. reduce + includes
let arr = [1.2.3.4.4.5.6.7];
function unique(arr) {
return arr.reduce((prev, cur) = > prev.includes(cur) ? prev : [...prev, cur], []);
}
const uniqueArr = unique(arr);
console.log(uniqueArr);
Copy the code
4. filter + indexOf
let arr = [1.2.3.4.4.5.6.7];
function unique(arr) {
return arr.filter((item, index, arr) = > {
returnarr.indexOf(item) === index; })}const uniqueArr = unique(arr);
console.log(uniqueArr);
Copy the code
5. for + indexOf
let arr = [1.2.3.4.4.5.6.7];
function unique(arr) {
let array = []
for (let i=0; i<arr.length; i++) {
if(arr.indexOf(arr[i]) === i) { array.push(arr[i]); }}return array;
}
const uniqueArr = unique(arr);
console.log(uniqueArr)
Copy the code
6. for + indexOf
let arr = [1.2.3.4.4.5.6.7];
function unique(arr) {
let array = [];
for (let i=0; i<arr.length; i++) {
if (array.indexOf(arr[i]) === -1) { array.push(arr[i]); }}return array;
}
const uniqueArr = unique(arr);
console.log(uniqueArr);
Copy the code
7. for + includes
let arr = [1.2.3.4.4.5.6.7];
function unique(arr) {
let array = [];
for (let i=0; i<arr.length; i++) {
if(! array.includes(arr[i])) { array.push(arr[i]) } }return array
}
const uniqueArr = unique(arr);
console.log(uniqueArr);
Copy the code
Publish and subscribe
// We write it as ES6 class
class EventEmitter {
constructor() {
// The event object that stores the subscription type
this.events = Object.create(null);
}
/** * Register event listener *@param {String} Type Indicates the event type *@param {Function} Cb callback function */
on(type, cb) {
// If the type is present, continue adding the callback cb to the array
if (this.events[type]) {
this.events[type].push(cb);
} else {
// The first time type is stored, an array space is created and stored to callback cb
this.events[type] = [cb]; }}/** * Release event *@param {String} Type Indicates the event type *@param {... any} Args argument list, which assigns the arguments passed by emit to the callback function */
emit(type, ... args) {
// Run through the array of type subscriptions
if (this.events[type]) {
this.events[type].forEach(listener= > {
listener.call(this. args); }); }}/** * Removes one (same) listener * for an event@param {String} Type Indicates the event type *@param {Function} Cb callback function */
off(type, cb) {
if (this.events[type]) {
this.events[type] = this.events[type].filter(listener= > {
// Filter the unused callback cb
returnlistener ! == cb && listener.listen ! == cb; }); }if (this.events[type].length === 0) {
delete this.events[type]; }}/** * Removes all listeners * for an event@param {String} Type Indicates the event type */
offAll(type) {
if (this.events[type]) {
delete this.events[type]; }}/** * Only triggers publication once *@param {String} Type Indicates the event type *@param {Function} Cb callback function */
once(type, cb) {
function wrap() { cb(... arguments);this.off(type, wrap);
}
// Bind first, call then delete
wrap.listen = cb;
Call the on method directly
this.on(type, wrap); }}/ / test
// Create an event manager instance
const ee = new EventEmitter();
// Register a chifan event listener
ee.on('chifan'.function() { console.log('Dinner, let's go! ')})// Publish the event chifan
ee.emit('chifan');
// Emit can also pass arguments
ee.on('chifan'.function(address, food) { console.log('Dinner, let's go${address}eat${food}! `)}); ee.emit('chifan'.'Three Canteen'.'Iron plate rice'); // Two messages are printed because two listeners for chifan events were registered
// Test removing event listening
const toBeRemovedListener = function() { console.log('I'm a listener that can be removed.')}; ee.on('testoff', toBeRemovedListener);
ee.emit('testoff');
ee.off('testoff', toBeRemovedListener);
ee.emit('testoff'); // Now the event listener has been removed and no more console.log will be printed
// Test to remove all event listening for chifan
ee.offAll('chifan');
console.log(ee); // Notice that the ee.listeners have become empty objects, and the listeners will not respond to sending chifan events
Copy the code
14, depth copy
1. The shallow copy
var obj = {a: 1.b: 2.c: { d: 1.e: 5 }}
function shallowClone(target) {
if (typeof target === 'object'&& target ! = =null) {
var obj = Array.isArray(target) ? [] : {};
for (var key in target) {
if (target.hasOwnProperty(key)) {
obj[key] = target[key]
}
}
return obj;
}
// The first deep copy is followed by the shallow copy
var o = shallowClone(obj);
obj.c.d = 2;
console.log(obj); // {a: 1, b: 2, c: {d:2, e:5}}
console.log(o); // {a: 1, b: 2, c: {d:2, e:5}}
Copy the code
2. Deep copy
- Determine the type, re, and date to return the new object directly
- An empty or non-object type that returns the original value
- Consider circular references and determine if
hash
Contains a direct returnhash
The values in the - Create a new corresponding
new obj.constructor
joinhash
- Traversal object recursion (common
key
和key
是symbol
Situation)
/ / basic version
var obj = {a: 1.b: 2.c: { d: 1.e: 5 }}
function deepClone(target) {
if (typeoftarget ! = ='object'&& target ! = =null) {
throw new Error('Please enter an object/array');
}
let obj = Array.isArray(target) ? [] : {};
for (const key in target) {
if (target.hasOwnProperty(key)) {
if (typeof target[key] === 'object') {
obj[key] = deepClone(target[key]);
} else{ obj[key] = target[key]; }}}return obj;
}
var o = deepClone(obj);
obj.c.d = 2;
console.log(obj); // {a: 1, b: 2, c: {d: 2, e: 5}}
console.log(o); // {a: 1, b: 2, c: {d: 1, e: 5}}
Copy the code
/ / premium
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;
// Loop references;
if(hash.has(obj)) {
return hash.get(obj)
}
// new a corresponding object;
// obj = Array, equivalent to new Array();
// obj = Object, 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 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
Implement the sleep method
1. The callback
function sleep(callback, time) {
setTimeout(callback, time);
}
function sayHi() {
console.log('satHi');
}
sleep(sayHi, 1000);
Copy the code
2. promise
/ / a simple version
function sleep(time) {
return new Promise((resolve, reject) = > setTimeout(resolve, time));
}
sleep(1000).then(() = > { console.log('sayHi')});Copy the code
/ / premium
function sleep(fn, time, ... args) {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
// reslove(fn(... args))
Promise.resolve(fn(... args)).then(resolve).catch(reject); }, time) }) }Copy the code
3. Generator
function* sleep(time) {
yield new Promise(function(resolve, reject) {
setTimeout(resolve, time);
})
}
sleep(1000).next().value.then(() = >{console.log('sayHi')});
Copy the code
4. async / await
function sleep(time) {
return new Promise((resolve, reject) = > {
setTimeout(resolve, time);
})
}
aysnc function output(time) {
const result = await sleep(time);
console.log('sayHi');
return result;
}
output(1000)
Copy the code
Implement object.create ()
MDN
Document;Object.create()
Takes the parameter object as a prototype of a newly created empty object and returns it;
/ / a simple version
function myCreate(obj) {
// declare a new function
function C() {};
// Point the function's prototype to obj
C.prototype = obj;
// Return the power object of this function
return new C();
}
// Official version of 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
17, implement Object.assign
Object.assign2 = function(target, ... source) {
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object')}let ret = Object(target);
source.forEach(function(obj) {
if(obj ! = =null|| obj ! = =undefined) {
for (let key in obj) {
if(obj.hasOwnProperty(key)) { ret[key] = obj[key]; }}}})return ret;
}
Copy the code
18. Print every second (closure)
for (var i=1; i<=5; i++) {
(function (i) {
setTimeout(() = > console.log(i), 1000*i);
})(i)
}
for (var i=1; i<=5; i++) {
setTimeout(function(i) {
console.log(i);
}.bind(null, i), 1000*i)
}
Copy the code
Write a JSONP by hand
let jsonp = function (url, data = {}, callback='callback') {
// Convert data to a URL string
let dataStr = url.indexOf('? ') = = = -1 ? '? ' : '&'
for(let key in data) {
dataStr += `${key}=${data[key]}& `;
}
// Handle callback functions in the URL
dataStr += 'callback=' + callback;
// Create the srcipt tag and add the SRC attribute value
let scriptBody = document.createElement('script')
scriptBody.src = url + dataStr
// Append to the page to initiate the request immediately
document.body.appendChild(scriptBody);
// Return a promise
return new Promise((resolve, reject) = > {
window[callback] = (data) = > {
try {
resolve(data)
} catch(e) {
reject(e)
} finally {
// Remove the script element
scriptBody.parentNode.removeChild(scriptBody);
console.log(scriptBody);
}
}
})
}
jsonp('https://photo.sina.cn/aj/index', {page:1.cate:'recommend'}).then(res= >{console.log(res)})
Copy the code
20. Handwritten observer mode
In the Observer mode, there are only two subjects, the target object Subject and the Observer Observer.
- Observers need to be
Observer
In order to achieveupdate
Method to be called by the target object.update
Method to execute custom business code. - The target object
Subject
Also known as the observed or the subject, it has a very simple function, it can be understood as managing only one kind of event.Subject
You need to maintain your own array of observersobserverList
When itself changes, by calling itsnotify
Method, telling each observer in turn to executeupdate
Methods.
/ / observer
class Observer {
/** * constructor *@param {Function} Cb callback function that executes */ when receiving a notification from the target object
constructor(cb){
if (typeof cb === 'function') {
this.cb = cb;
} else {
throw new Error('Observer constructor must pass function type! '); }}/** * execute */ when notified by the target object
update() {
this.cb(); }}// Target object
class Subject {
constructor() {
// Maintain a list of observers
this.observerList = [];
}
/** * Add an observer *@param {Observer} Observer Observer instance */
addObserver(observer) {
this.observerList.push(observer);
}
/** * notify all observers */
notify() {
this.observerList.forEach(observer= >{ observer.update(); }}})const observerCallback = function() {
console.log('I've been informed.');
}
const observer = new Observer(observerCallback);
const subject = new Subject();
subject.addObserver(observer);
subject.notify();
Copy the code
21. Get the object content
Complete the deepGet function and pass it an object and a string. The string represents the path to the object’s deep properties.
const deepGet = (obj, prop) = > {
const keyArr = prop.split('. ').map(key= > key);
const reducer = (acc, cur) = > {
const objKey = cur.includes('[') && cur.replaceAll(/[\[?0-9\]$]/gi.' ');
if (Array.isArray(acc[objKey])) {
cur = cur.replaceAll(/[^?0-9]/gi.' ');
return acc[objKey][cur] || {};
}
return acc[cur] ? acc[cur] : {};
}
const result = keyArr.reduce(reducer, obj);
return Object.keys(result).length ? result : undefined;
}
/** Here is the test code */
deepGet({
school: {
student: { name: 'Tomy'}},},'school.student.name') // => 'Tomy'
deepGet({
school: {
students: [{name: 'Tomy' },
{ name: 'Lucy'},]}},'school.students[1].name') // => 'Lucy'
// For nonexistent attributes, return undefined
deepGet({ user: { name: 'Tomy'}},'user.age'); // => undefined
deepGet({ user: { name: 'Tomy'}},'school.user.age'); // => undefined
Copy the code
22, various methods to generate random numbers?
// Generate a random number for [min, Max], where math.random () is a random number for [0, 1)
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
// Generate a random number for [min, Max]
function getRandom(min, max) {
return Math.floor(Math.random() * (max + 1 - min)) + min
}
// Generate (min, Max) random number
function getRandom(min, max) {
let result = Math.random()*(m-n)+n;
while(result == n) {
result = Math.random()*(m-n)+n;
}
return result;
}
// Generate (min, Max) random number
function getRandom(min, max) {
let result = Math.random()*(m-n+1)+n-1;
while(result<n) {
result = Math.random()*(m-n+1)+n-1;
}
return result;
}
Copy the code
23, 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
24, to achieve regular segmentation thousandths
// No decimal point
let num1 = '1321434322222'
num1.replace(/(\d)(? =(\d{3})+$)/g.'$1');
// Has a decimal point
let num2 = '342243242322.3432423';
num2.replace(/(\d)(? =(\d{3})+\.) /g.'$1');
Copy the code
Parse the URL Params as an 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], // Duplicate keys to array, can be converted to number type city: 'Beijing ', // Chinese decoding needs to be enabled: True, // The value key convention is not specified to be true} */
Copy the code
function parseParam(url) {
const paramsStr = /. + \? (. +) $/.exec(url)[1]; / / will be? I'm going to pull out the string
const paramsArr = paramsStr.split('&'); // Split the string with & and store it in the array
let paramsObj = {};
// Save params to the object
paramsArr.forEach(param= > {
if (/ = /.test(param)) { // Handle arguments with value
let [key, val] = param.split('='); // Split 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 { // Handle arguments without value
paramsObj[param] = true; }})return paramsObj;
}
Copy the code
26. Template engine implementation
let template = 'I am {{name}}, age {{age}}, gender {{sex}}';
let data = {
name: 'name'.age: 18
}
render(template, data); // I am name, age 18, gender undefined
Copy the code
/ / method
function render(template, data) {
const reg = /\{\{(\w+)\}\}/; // The template string is regular
if (reg.test(template)) { // Check if there is a template string in the template
const name = reg.exec(template)[1]; // Find the first template string field in the current template
template = template.replace(reg, data[name]); // Render the first template string
return render(template, data); // Recursively render and return the rendered structure
}
return template; // If the template does not have a template string
}
Copy the code
// Method 2 (recommended)
function render(template, data) {
let computed = template.replace(/\{\{(\w+)\}\}/g.function (match, key) {
return data[key];
});
return computed;
}
Copy the code
27. Convert to hump naming
var s1 = "get-element-by-id";
// Convert to getElementById
Copy the code
var f = function(s) {
return s.replace(/-\w/g.function(x) {
return x.slice(1).toUpperCase(); })}Copy the code
Find the maximum number of characters in a string
- Example: the most common abbcccDDDDd -> 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 a 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
Lazy loading of images
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
30. Implement Reduce and forEach
// reduce
Array.prototype.reduce = function(fn, val) {
// Check if val has a value
for (let i = 0; i < this.length; i++) {
// No value is passed in
if (typeof val === 'undefined') {
val = this[i];
} else { // Val is passed in
// total is the initial value val
val = fn(val, this[i], i, this); }}return val;
};
Copy the code
// forEach
// Base version
Array.prototype.forEach = function(callback) {
var len = this.length;
for(var i = 0; i < len; i++) {
callback(this[i], i, this); }}/ / call
Array.prototype.forEach = function(callback, thisArg) {
var len = this.length;
for(var i = 0; i < len; i++) {
// callback(this[i], i, this);
callback.call(thisArg, this[i], i, this); }}/ / the bind
Array.prototype.forEach = function(callback, thisArg) {
var len = this.length;
callback = callback.bind(thisArg);
for(var i = 0; i < len; i++) {
callback(this[i], i, this); }}Copy the code
Use setTimeout to implement setInterval
let timer = null;
function mockSetInterval(fn, delay, ... args) {
let recur = function() {
timer = setTimeout(() = > {
fn.apply(this, args);
recur();
}, delay)
}
recur();
}
function mockClearInterval(id) {
clearTimeout(id);
}
mockSetInterval((a, b) = > {console.log(a, b)}, 1000.'1'.'2')
setTimeout(() = > {
mockClearInterval(timer);
}, 4000)
Copy the code
Implement the chunk function
- Divide the array into segments based on size, for example, arr = [1,2,3,4,5,6,7], size = 2;
- Target = [[1,2], [3,4], [5,6], [7]
function chunk(arr, size) {
let target = [];
let count = size;
if (arr.length < size) {
target.push(arr.slice());
} else {
let len = arr.length - arr.length % size;
for (let i=0; i<len; i=i+size) {
let newArr = arr.slice(i, count);
count = count + size;
target.push(newArr);
}
if(arr.length % size ! = =0) { target.push(arr.slice(arr.length - arr.length % size)); }}return target;
}
let target = chunk([1.2.3.4.5.6].7);
console.log(target);
Copy the code
Achieve traffic lights
- Using a div for the traffic light effect, you rotate a circular div with green 3s, yellow 1s, and red 2s
#traffic-color {
width: 100px;
height: 100px;
overflow: hidden;
border-radius: 50%;
}
Copy the code
<div id="traffic-color"></div>
const TRAFFIC_COLOR_CONFIG = {
'green': 3000.'yellow': 1000.'red': 2000
}
function delay(duration) {
return new Promise((resolve, reject) = > setTimeout(resolve, duration));
}
async function changeColor(color) {
document.getElementById('traffic-color').style.background = color;
await delay(TRAFFIC_COLOR_CONFIG[color]);
}
async function run() {
// while(1) {
// await changeColor('green', 3000);
// await changeColor('yellow', 1000);
// await changeColor('red', 2000);
// }
// await changeColor('green', 3000);
// await changeColor('yellow', 1000);
// await changeColor('red', 2000);
for (const key in TRAFFIC_COLOR_CONFIG) {
await changeColor(key);
}
run()
}
run();
Copy the code
34, Implement indexOf()
A few points to note:
- Returns -1 if the index starts larger than the string/array length;
- If the index starts less than or equal to 0, the index starts from 0.
- If the string or array length is 0, return 0;
- Otherwise, return -1;
function indexOf(searchValue, index=0) {
if (this.length < 1 || index > this.length) return -1;
if(! searchValue)return 0;
index = index <= 0 ? 0 : index;
for (let i=0; i<this.length; i++) {
if (this[i] === searchValue) {
returni; }}return -1;
}
Array.prototype.myIndexOf = indexOf;
String.prototype.myIndexOf = indexOf;
console.log([1.2.3].myIndexOf(2));
console.log('123'.myIndexOf('2'));
Copy the code
35, write version number sort method
- Title description: a group of version number as follows [‘ while ‘, ‘2.3.3’, ‘0.302.1’, ‘4.2’, ‘4.3.5’, ‘4.3.4.5’]. Now you need to sort it;
- Sorting result for [‘ 4.3.5 ‘, ‘4.3.4.5’, ‘2.3.3’, ‘0.302.1’, ‘while’].
arr.sort((a, b) = > {
let i = 0;
const arr1 = a.split(".");
const arr2 = b.split(".");
while (true) {
const s1 = arr1[i];
const s2 = arr2[i];
i++;
if (s1 === undefined || s2 === undefined) {
return arr2.length - arr1.length;
}
if (s1 === s2) continue;
returns2 - s1; }});console.log(arr);
Copy the code
Class array to array method
- How do I convert an array of classes to an array?
const arrayLike=document.querySelectorAll('div')
// 1. Extend the operator
[...arrayLike]
// 2.Array.from
Array.from(arrayLike)
// 3.Array.prototype.slice
Array.prototype.slice.call(arrayLike)
// 4.Array.apply
Array.apply(null, arrayLike)
// 5.Array.prototype.concat
Array.prototype.concat.apply([], arrayLike)
Copy the code
Object.is()
- Object.is does not convert the type of the two values being compared, much like ===, although there are some differences.
-
- NaN is not equal in ===, but is equal in object.is ();
-
- +0 and -0 are equal in ===, but not in object.is ();
-
Object.is = function (x, y) {
if (x === y) {
// In the current case, only one case is special: + 0-0
// If x! == 0, returns true
Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity
returnx ! = =0 || 1 / x === 1 / y;
}
// x ! In the case of == y, we just need to determine if it is NaN, if x! If ==x, then x is NaN, and likewise y
// Return true if x and y are both NaN
returnx ! == x && y ! == y; };Copy the code
38. Virtual DOM is converted into real DOM
JSON
Format virtualisationDOM
How do you make it realDOM
;
Title description:
{
tag: 'DIV'.attrs: {id:'app'
},
children: [{tag: 'SPAN'.children: [{tag: 'A'.children: []}]}, {tag: 'SPAN'.children: [{tag: 'A'.children: []}, {tag: 'A'.children: []}]}} virtualize the appeal`DOM`Into the truth below`DOM`;
<div id="app">
<span>
<a></a>
</span>
<span>
<a></a>
<a></a>
</span>
</div>
Copy the code
The implementation code is as follows:
// Real render function
function _render(vnode) {
// If it is a numeric type, convert it to a string
if (typeof vnode === "number") {
vnode = String(vnode);
}
// The string type is directly a text node
if (typeof vnode === "string") {
return document.createTextNode(vnode);
}
/ / common DOM
const dom = document.createElement(vnode.tag);
if (vnode.attrs) {
// Iterate over attributes
Object.keys(vnode.attrs).forEach((key) = > {
const value = vnode.attrs[key];
dom.setAttribute(key, value);
});
}
// Subarrays operate recursively
vnode.children.forEach((child) = > dom.appendChild(_render(child)));
return dom;
}
Copy the code
39. DOM node output JSON format
Title description:
<div>
<span>
<a></a>
</span>
<span>
<a></a>
<a></a>
</span>< / div > the appeal`DOM`The structure turns into the one below`JSON`Format {tag: 'DIV'.children: [{tag: 'SPAN'.children: [{tag: 'A'.children: []}]}, {tag: 'SPAN'.children: [{tag: 'A'.children: []}, {tag: 'A'.children: []}]}Copy the code
The implementation code is as follows:
function dom2Json(domtree) {
let obj = {};
obj.name = domtree.tagName;
obj.children = [];
domtree.childNodes.forEach((child) = > obj.children.push(dom2Json(child)));
return obj;
}
Copy the code
Implement the Flatten method of an object
Title description:
const obj = {
a: {
b: 1.c: 2.d: {e: 5}},b: [1.3, {a: 2.b: 3}].c: 3} flatten(obj) returns the following result/ / {
// 'a.b': 1,
// 'a.c': 2,
// 'a.d.e': 5,
// 'b[0]': 1,
// 'b[1]': 3,
// 'b[2].a': 2,
// 'b[2].b': 3
// c: 3
// }
Copy the code
The implementation code is as follows:
function isObject(val) {
return typeof val === "object"&& val ! = =null;
}
function flatten(obj) {
if(! isObject(obj)) {return;
}
let res = {};
const dfs = (cur, prefix) = > {
if (isObject(cur)) {
if (Array.isArray(cur)) {
cur.forEach((item, index) = > {
dfs(item, `${prefix}[${index}] `);
});
} else {
for (let k in cur) {
dfs(cur[k], `${prefix}${prefix ? "." : ""}${k}`); }}}else{ res[prefix] = cur; }}; dfs(obj,"");
return res;
}
flatten();
Copy the code
41. Lists become trees
Title description:
[{id: 1.text: Nodes' 1 '.parentId: 0 // The top-level node is represented by 0
},
{
id: 2.text: '1 _1 nodes'.parentId: 1 // Use this field to determine the child and parent levels
}
...
]
转成
[
{
id: 1.text: Nodes' 1 '.parentId: 0.children: [{id: 2.text: '1 _1 nodes'.parentId: 1}}]]Copy the code
The implementation code is as follows:
function listToTree(data) {
let temp = {};
let treeData = [];
for (let i = 0; i < data.length; i++) {
temp[data[i].id] = data[i];
}
for (let i in temp) {
if(+temp[i].parentId ! =0) {
if(! temp[temp[i].parentId].children) { temp[temp[i].parentId].children = []; } temp[temp[i].parentId].children.push(temp[i]); }else{ treeData.push(temp[i]); }}return treeData;
}
Copy the code
42. Tree structure to list
Title description:
[{id: 1.text: Nodes' 1 '.parentId: 0.children: [{id:2.text: '1 _1 nodes'.parentId:1}]}] into [{id: 1.text: Nodes' 1 '.parentId: 0 // The top-level node is represented by 0
},
{
id: 2.text: '1 _1 nodes'.parentId: 1 // Use this field to determine the child and parent levels}... ]Copy the code
The implementation code is as follows:
function treeToList(data) {
let res = [];
const dfs = (tree) = > {
tree.forEach((item) = > {
if (item.children) {
dfs(item.children);
delete item.children;
}
res.push(item);
});
};
dfs(data);
return res;
}
Copy the code
Depth first traversal
Depth-first traversal — starts at a vertex, visits that vertex first, finds the first unvisited neighbor that just visited that vertex, and then continues to find its next vertex to access. Repeat this step until all nodes are accessed.
Recursive writing of depth-first traversal
function deepTraversal(node) {
let nodes = []
if(node ! =null) {
nodes.push(node)
let childrens = node.children
for (let i = 0; i < childrens.length; i++) {
deepTraversal(childrens[i])
}
}
return nodes
}
Copy the code
Non-recursive writing of depth-first traversal
function deepTraversal(node) {
let nodes = []
if(node ! =null) {
let stack = []
// Store the nodes to be accessed in the future
stack.push(node)
while(stack.length ! =0) {
let item = stack.pop()
// The node being accessed
nodes.push(item)
let childrens = item.children
for ( let i = childrens.length - 1; i >= 0; i--) {
// Stack the children of the node at the current access point for future access.)
stack.push(childrens[i])
}
}
}
return nodes
}
Copy the code
Breadth first traversal
Breadth-first traversal — starts at a vertex, visits that vertex first, finds all unvisited neighbors that have just visited that node, visits all of the first of those neighbors, and repeats until all of them have been accessed.
Recursive writing of breadth-first traversal
function wideTraversal(node) {
let nodes = [], i = 0
if(node ! =null) {
nodes.push(node)
wideTraversal(node.nextElementSibling)
node = nodes[i++]
wideTraversal(node.firstElementChild)
}
return nodes
}
Copy the code
Nonrecursive writing of breadth-first traversal
function wideTraversal(node) {
let nodes = [], i = 0
while(node ! =null) {
nodes.push(node)
node = nodes[i++]
let childrens = node.children
for (let i = 0; i < childrens.length; i++) {
nodes.push(childrens[i])
}
}
return nodes
}
Copy the code