Sorted out the front end test questions, share with everyone to study together. If you have any questions, please point out!
directory
- Handwritten new function
- Handwritten instanceof
- Handwritten call function
- Handwritten Apply function
- Handwritten bind
- Handwriting Debounce anti – shake function
- Handwritten throttle throttling function
- Hand-written array object deduplicating
- Handwriting array flattening
- Handwritten deep copy
1. Write new functions by hand
What new does:
- An empty object is created.
- Empty object
proto
Point to the prototype of the constructorprototype
. - make
this
Point to the newly created object and execute the constructor. - The result of execution has a return value and is an object. Returns the result of execution, otherwise returns the newly created object.
// Create a new constructor -- a function for new
// Constructor is a special method used to assign initial values to object member variables when an object is created
function Cat(name){
// This refers to the window, so we need to redirect this to itself to mount the property successfully
this.name = name
this.say = function() {
console.log("my name is" + this.name); }}// Write the new function
function sd_new(fn,... arg){
const obj = {};
// Mount the constructor prototype to the new object
Object.setPrototypeOf(obj, fn.prototype)
// Point this to the new object and execute the constructor
let result = fn.apply(obj, arg);
return result instanceof Object ? result : obj
}
/ / verification
var cat = sd_new(Cat, "shamao")
cat.say();// my name is shamao
Copy the code
2. The handwritten instanceof
The advantages and disadvantages:
- Advantages: Can distinguish Array, Object, and Function, suitable for judging custom class instance objects
- Disadvantages: Number, Boolean, String Basic data types cannot be determined
Implementation steps:
- The arguments passed in are instance L on the left, and constructor R on the right
- Handles bounds, and returns false if you want to detect an object of primitive type
- Take the prototype of the passed parameters, respectively
- Check whether the left prototype is null, if null returns false; Return true if both archetypes are equal, otherwise continue with the left archetype.
function sd_instanceof(L,R){
// Verify that if it is a basic data type, return false directly, because instanceof can only determine the reference type
const baseType = ['string'.'number'.'boolean'.'undefined'.'symbol'];
if(baseType.includes(typeof(L)) || L === null) { return false };
let Lp = L.__proto__;
let Rp = R.prototype; // The function has the prototype attribute
while(true) {if(Lp === null) {return false;
}
if(Lp === Rp){
return true; } Lp = Lp.__proto__; }}/ / test
const flag = sd_instanceof([], Array);
Copy the code
3. Write the call function
Implementation steps:
- Processing boundaries:
- Object does not exist, this refers to window;
- Will “call function”Mount to theOn the FN property of the object to which this points.
- Execute the fn function on “the object to which this points”, pass in the argument, and return the result.
Function.prototype.sd_call = function (context, ... args) {
//obj does not point to window
if(! context || context ===null) {
context = window;
}
// Create a unique key value for the internal method name of the context we construct
let fn = Symbol(a);// This refers to the function that calls call
context[fn] = this;
// Executing the function and returning the result is equivalent to calling itself as a method of the passed context
returncontext[fn](... args); };/ / test
var value = 2;
var obj1 = {
value: 1};function bar(name, age) {
var myObj = {
name: name,
age: age,
value: this.value,
};
console.log(this.value, myObj);
}
bar.sd_call(null); // print 2 {name: undefined, age: undefined, value: 2}
bar.sd_call(obj1, 'tom'.'110'); {name: "top", age: "110", value: 1}
Copy the code
Write the Apply function by hand
Implementation steps:
- In line with the call
- As distinct from the form of parameters
Function.prototype.sd_apply = function (context, args) {
//obj does not point to window
if(! context || context ===null) {
context = window;
}
// Create a unique key value for the internal method name of the context we construct
let fn = Symbol(a);// This refers to the function that calls call
context[fn] = this;
// Executing the function and returning the result is equivalent to calling itself as a method of the passed context
returncontext[fn](... args); };/ / test
var value = 2;
var obj1 = {
value: 1};function bar(name, age) {
var myObj = {
name: name,
age: age,
value: this.value,
};
console.log(this.value, myObj);
}
bar.sd_apply(null[]);// print 2 {name: undefined, age: undefined, value: 2}
bar.sd_apply(obj1, ['tom'.'110']); {name: "top", age: "110", value: 1}
Copy the code
5. Write bind
Function.prototype.sd_bind = function (context, ... args) {
if(! context || context ===null) {
context = window;
}
// Create a unique key value for the internal method name of the context we construct
let fn = Symbol(a); context[fn] =this;
let _this = this;
// bind is a bit more complicated
const result = function (. innerArgs) {
// In the first case, if you use the new operator as a constructor after bind, instead of binding this passed in, you point this to the instantiated object
// Since the new operator calls this to the result instance, which in turn inherits from _this, we can draw the following conclusions from our knowledge of the prototype chain
// this.__proto__ === result.prototype //this instanceof result =>true
// this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true
if (this instanceof _this === true) {
// This points to an instance of result
this[fn] = _this;
this[fn](... [...args, ...innerArgs]);// Es6 methods are used here to enable bind to support parameter merging
delete this[fn];
} else {
It would be easy to change this to refer to the context passed in if it was just called as a normal functioncontext[fn](... [...args, ...innerArgs]);deletecontext[fn]; }};// If you bind to a constructor, you need to inherit the constructor prototype properties and methods
// Implement inheritance by using object.create
result.prototype = Object.create(this.prototype);
return result;
};
function Person(name, age) {
console.log(name); //' I am the name of the parameter passed in '
console.log(age); //' I am the age passed in '
console.log(this); // The constructor this points to the instance object
}
// The method to construct the prototype
Person.prototype.say = function () {
console.log(123);
};
// A normal function
function normalFun(name, age) {
console.log(name); //' I am the name of the parameter passed in '
console.log(age); //' I am the age passed in '
console.log(this); // The normal function this points to the first argument to the bind, which in our example is obj
console.log(this.objName); //' I am the name of obj '
console.log(this.objAge); //' I am an age from obj '
}
let obj = {
objName: 'I'm the name that OBj passed in.'.objAge: 'I'm the age that OBj sent in.'};// Test as constructor call first
// let bindFun = person.sd_bind (obj, 'I am the name of the parameter ');
// let a = new bindFun(' I am an age');
// a.say(); //123
// retest as a normal function call a;
let bindFun = normalFun.sd_bind(obj, 'I'm the name that was passed in as a parameter');
bindFun('I'm the age that the parameter is passed in.');
Copy the code
6. Handwritten Debounce anti-shake function
Function stabilization is to execute the callback n seconds after the event is triggered. If the event is triggered again in n seconds, the timer is reset.
function debounce(fn, wait) {
let timer = null;
return function () {
if(timer ! =null) {
clearTimeout(timer);
}
timer = setTimeout(() = > {
fn();
}, wait);
};
}
/ / test
function handle() {
console.log(Math.random());
}
// If the window size changes, handle is triggered
window.addEventListener('resize', debounce(handle, 1000));
Copy the code
7. Handwritten throttle functions
When an event is triggered, only a certain period of time is specifiedOne callFunction. For example, send requests every once in a while while the page is scrolling
Implementation steps:
- The argument passed is to execute the function fn and wait time wait.
- Save the initial time now.
- Returns a function that updates now to the current time if the wait time is exceeded.
function throttle(fn, wait, ... args) {
var pre = Date.now();
return function () {
// The function may have input parameters
var context = this;
var now = Date.now();
if (now - pre >= wait) {
// Will execute the function this to the current scope
fn.apply(context, args);
pre = Date.now(); }}; }/ / test
var name = 'mu';
function handle(val) {
console.log(val + this.name);
}
// Roll the mouse to trigger the handle
window.addEventListener('scroll', throttle(handle, 1000.'4'));
Copy the code
8. Hand-write array objects for deduplication
Keys using map cannot be duplicated, removing items with the same attributes
function uniqBy(arr, key) {
return [...new Map(arr.map((item) = > [item[key], item])).values()];
}
const list = [
{ id: 1.name: 'tom' },
{ id: 1.name: 'jey' },
{ id: 2.name: 'joy'},];console.log(uniqBy(list, 'id')); // [{id:1,name:"jey"},{id:2,name:"joy"}]
Copy the code
9. Handwriting array flattening
flat
let arr = [1.2[3.4], [5.6[7.8.9]]]
console.log(arr.flat(Infinity))//[1, 2, 3, 4, 5, 6, 7, 8, 9]
Copy the code
join/ split
console.log(arr.toString().split(",").map(Number))//[1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(arr.join().split(",").map(Number))//[1, 2, 3, 4, 5, 6, 7, 8, 9]
Copy the code
Functional version
function flatter(arr) {
if(! arr.length)return;
while (arr.some((item) = > Array.isArray(item))) { arr = [].concat(... arr); }return arr;
}
// console.log(flatter([1, 2, [1, [2, 3, [4, 5, [6]]]]]));
Copy the code
10. Deep copy by hand
A deep copy of an object is essentially a recursive method of deep cloning: iterating through the object and array until it contains all the basic data types, and then copying.
Simple version of
function deepCopy(obj){
// Check if it is a simple data type,
if(typeof obj == "object") {// Complex data types
var result = obj.constructor == Array ? [] : {};
for(let i in obj){
result[i] = typeof obj[i] == "object"? deepCopy(obj[i]) : obj[i]; }}else {
// Assign to simple data types directly ==
var result = obj;
}
return result;
}
Copy the code
premium
function deepClone(obj, hash = new WeakMap(a)) {
// If it is null or undefined, I will not copy it
if (obj === null) return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// May be objects or ordinary values if functions do not need deep copies
if (typeofobj ! = ='object') return obj;
// Make a deep copy of an object
if (hash.get(obj)) return hash.get(obj);
// Find the constructor from the parent class stereotype, which points to the current class itself
let cloneObj = new obj.constructor();
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// Implement a recursive copycloneObj[key] = deepClone(obj[key], hash); }}return cloneObj;
}
let obj = { name: 1.address: { x: 100}}; obj.o = obj;// The object has a circular reference
let d = deepClone(obj);
obj.address.x = 200;
console.log(d);
Copy the code