Reference article:

JS Common handwritten code questions (1)

JS common handwritten code questions (2)

Write the call,apply,bind functions by hand

32 hand-written JS_ Single eyelid bears -CSDN blog

This article from the above article, excerpt summarizes a part of the common and need to have a good understanding of the JS handwritten code question type, interview necessary, on demand

For more detailed explanations, please refer to the source above

  1. call
  2. apply
  3. bind
  4. new
  5. Array flattening
  6. Array to heavy
  7. Prototype inheritance
  8. Promise, promise. All, promise. Race
  9. instanceof
  10. ajax
  11. Closure cache
  12. Shallow copy, deep copy
  13. String turns hump
  14. Lazy loading of images
  15. The rolling load

JS implements a call

Fun. call(obj, argument 1, argument 2…) , the first value is to change this to obj, followed by the parameter queue. Call immediately executes the fun method

The definition and usage of call

// The first argument to the call method refers to this; Accepts a list of arguments; Method executed immediately
/ / Function. The prototype. The call () sample
function fun(arg1, arg2) {
  console.log(this.name)
  console.log(arg1 + arg2)
}
const _this = { name: 'YIYING' }
// This in fun points to _this, and then executes immediately, from which YIYING is output
fun.call(_this, 1.2)
/ / output
YIYING
3
Copy the code

Implement call by hand

Funcion.protoType.mockCall = function (context = window. args) {
	const key = Symbol()
	context[key] = this
	constresult = context[key](... args)delete context[key]
	returnResult} or:Function.prototype.myCall = function(context) {
    if (typeof context === "undefined" || context === null) {
        context = window
    }
   / / the context = context | | window the same as the above code
    context.fn = thisContext. fn = this = myFun) //(context.fn = this = myFun) //(context.fn = this = myFun)
    const args = [...arguments].slice(1)// The first argument is context, to be removed
    constresult = context.fn(... args)delete context.fn
    return result
}
Copy the code

Implementation analysis

  • Context is optional. If not, the default context is Window
  • Next create a unique property for the Content (represented by Symbol) and set the value to the function you want to call
  • Because call can pass multiple arguments as arguments to the calling function, we use… Extended operator
  • The function is then called and removed from the object

JS implements an apply

Fun. apply(obj, [parameter 1, parameter 2… Change this to obj and execute fun immediately

Apply takes two arguments, the first being the value to bind to this and the second an array of ** arguments. ** The apply and Call implementations are similar, except for the handling of parameters

Function.protoType.mockApply = function (context = window, args) {
	const key = Symbol()
	context[key] = this
	constresult = context[key](... args)delete context[key]
	return result
}
Copy the code

JS implements a bind

Function.prototype.bind the first argument is a reference to this, and the second argument is a list of received arguments. The difference from call is that the bind method returns values from the function and the use of a list of arguments that BIND receives.

Implementation idea:

  • Use closures to save this from a call to bind, where this is the original function
  • Specify this using call/apply
  • Returns a binding function
  • When the returned binding function is called by the new operator, the context of the binding refers to the object created by the new operator
  • Change the binding function’s prototype to the original function’s prototype
Function.protoType.mockBind = function (context = window. initArgs) {
	const foo = this
	var bindFoo = function (. args) {
		if(this instanceof bindFoo){
      return newfn(... initArgs, ... args) }returnfoo.call(context, ... initArgs, ... args) }returnBindFoo}Function.prototype.mockBind = function(ctx){
    let fn = this
    return function(){
        fn.apply(ctx, arguments) //arguments are arguments passed when a function is called}}Copy the code

The first argument is the reference to this, and the second argument is the list of arguments received. The difference is that the bind method returns a function and uses a list of arguments that BIND receives.

Write a new implementation by hand

Normal use of new

function Dog(name){
    this.name = name
}
Dog.prototype.sayName = function(){
    console.log('name'.this.name)
}
var dog1 = new Dog('dog')
dog1.sayName() // Output the name dog
Copy the code

What does the new operator do?

  • Create a new object
  • The new object will be executed__proto__Link, associated with the constructor.prototypeProperty, which is a stereotype used by the constructor to call the methods on the stereotype
  • The function call’s this is bound to the new object
  • If the function returns no other object, the function call in the new expression automatically returns the new object

Handwriting new implementation

function mockNew (foo, ... args) {
	if (typeoffoo ! = ='function') {
    throw Error('foo is not a constructor')}const obj = Object.create(foo.protoType)
	const result = foo.apply(obj, args)
	return typeOf result === 'object'&& result ! = =null ?  result : obj
}
newSpecific steps of1.Create an empty objectvar obj = {}
2.Modify the obj. __proto__ = t prototype3.Only changethisPoint to and pass the parameter,call or apply4.According to the specification, returnnullundefinedNo processing, still return obJCopy the code

5. Array flattening

Method 1: ES6 Flat method

var arr = [1.2[3.4[5.6[7]]]]
arr.flat(Infinity) / /,2,3,4,5,6,7 [1]
Copy the code

Method two: recursion

var flatArr = function(arr1) {
	let newArr = [];
  function getChild(arr) {
		for(let i = 0; i<=arr.length; i++) {if(arr[i] instanceof Array= = =false && arr[i]) {
				newArr.push(arr[i])
			} else if(arr[i]){
				getChild(arr[i])
			}
		}
	}
	getChild(arr1);
	return newArr;
}

/ / call:
var a = [[1.2.2], [6.7.8[11.12[12.13[14]]].10]].console.log('Utilities', flatArr(a))
// [1, 2, 2, 6, 7, 8, 11, 12, 12, 13, 14, 10]
Copy the code

Method three: re

const res2 = JSON.stringify(arr).replace(/\[|\]/g.' ').split(', ');
res2.map(item= > parseInt(item))
Copy the code

Array deduplication

Method 1: ES6 Set

var arr = [1.2.3.3.4.4.5]
var newArr = Array.from(new Set(arr)); / / [1, 2, 3, 4, 5]
// or arr = [...set] array.from () converts a pseudo-array to an Array
Copy the code

Method two: loop through the number group

function filterArr(arr){
	var newArr = [];
	arr.forEach(item= > {
		if(! newArr.includes(item)) {// Can also be! newArr.indexOf(item)
			newArr.push(item)
		}
	})
	return newArr
}
Copy the code

Method 3: Hash table

let arr = [1.1.2.3.2.1.2]
function unique(arr){
    let obj = {}
    arr.forEach((item) = > {
        obj[item] = true
    })
    let keys = Object.keys(obj)
    keys = keys.map(item= > parseInt(item)) // Convert to a number
    return keys
}
console.log(unique(arr))
Copy the code

Vii. Archetypal Inheritance (Parasitic combination Inheritance)

I'm just going to say that there's a parasitic combination inheritance, and there's a couple of descendents in between but they all have some flawsfunction Parent() {
  this.name = 'parent';
}
function Child() {
  Parent.call(this);
  this.type = 'children';
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Copy the code

Write a Promise by hand

Full parse (well written and worth a look) :

zhuanlan.zhihu.com/p/103651968

function Promise(executor) {
let self = this
this.status = 'pending' // Current status
this.value = undefined  // Store successful values
this.reason = undefined // Cause of storage failure
this.onResolvedCallbacks = []// Store a successful callback
this.onRejectedCallbacks = []// Storage failed callback
function resolve(value) {
  if (self.status == 'pending') {
    self.status = 'resolved'
    self.value = value
    self.onResolvedCallbacks.forEach(fn= >fn()); }}function reject(error) {
  if (self.status == 'pending') {
    self.status = 'rejected'
    self.reason = error
    self.onRejectedCallbacks.forEach(fn= > fn())
  }
}
try {
  executor(resolve, reject)
} catch (error) {
  reject(error)
}
}
Promise.prototype.then = function (infulfilled, inrejected) {
let self = this
let promise2
infulfilled = typeof infulfilled === 'function' ? infulfilled : function (val) {
  return val
}
inrejected = typeof inrejected === 'function' ? inrejected : function (err) {
  throw err
}
if (this.status == 'resolved') {
  promise2 = new Promise(function (resolve, reject) {
    //x can be a promise, or it can be a normal value
    setTimeout(function () {
      try {
        let x = infulfilled(self.value)
        resolvePromise(promise2, x, resolve, reject)
      } catch(err) { reject(err) } }); })}if (this.status == 'rejected') {

  promise2 = new Promise(function (resolve, reject) {
    //x can be a promise, or it can be a normal value
    setTimeout(function () {
      try {
        let x = inrejected(self.reason)
        resolvePromise(promise2, x, resolve, reject)
      } catch(err) { reject(err) } }); })}if (this.status == 'pending') {
  promise2 = new Promise(function (resolve, reject) {
    self.onResolvedCallbacks.push(function () {
      //x can be a promise, or it can be a normal value
      setTimeout(function () {
        try {
          let x = infulfilled(self.value)
          resolvePromise(promise2, x, resolve, reject)
        } catch (err) {
          reject(err)
        }
      });
    })
    self.onRejectedCallbacks.push(function () {
      //x can be a promise, or it can be a normal value
      setTimeout(function () {
        try {
          let x = inrejected(self.reason)
          resolvePromise(promise2, x, resolve, reject)
        } catch(err) { reject(err) } }); })})}return promise2
}
function resolvePromise(p2, x, resolve, reject) {
if(p2 === x && x ! =undefined) {
  reject(new TypeError('Type error'))}// It can be a promise, see if the object has a then method, if it has ~ then it is a promise
if(x ! = =null && (typeof x === 'object' || typeof x === 'function')) {
  try {// To prevent {then:11}, determine if then is a function
    let then = x.then
    if (typeof then === 'function') {
      then.call(x, function (y) {
        //y may still be a promise, so parse until a normal value is returned
        resolvePromise(p2, y, resolve, reject)
      }, function (err) {
        reject(err)
      })
    } else {// If then is not function then may be object or constant
      resolve(x)
    }
  } catch (e) {
    reject(e)
  }
} else {// Indicates a normal value
  resolve(x)
}
}
Copy the code

Promise.all

Promise.all supports chained calls, essentially returning a Promise instance that changes its state through resolve and reject.

Promise.myAll = function(promiseArr) {
  return new Promise((resolve, reject) = > {
    const ans = [];
    let index = 0;
    for (let i = 0; i < promiseArr.length; i++) {
      promiseArr[i]
      .then(res= > {
        ans[i] = res;
        index++;
        if (index === promiseArr.length) {
          resolve(ans);
        }
      })
      .catch(err= >reject(err)); }})}Copy the code

Promise.race

Promise.race = function(promiseArr) {
  return new Promise((resolve, reject) = > {
    promiseArr.forEach(p= > {
      // If it is not a Promise instance, it needs to be converted to a Promise instance
      Promise.resolve(p).then(
        val= > resolve(val),
        err= > reject(err),
      )
    })
  })
}
Copy the code

Implement instanceof detection data type

Left indicates the data to be detected, and right indicates the type. The principle is implemented with the prototype chain, A(instance object)instanceofB(constructor).function instanceof(left, right){
    let proto = left._proto_
    let prototype = right.prototype
    while(true) {if(proto === null) return false
        if(proto === prototype) return true
        proto = proto._proto_
    }
}
Copy the code

Ten, ajax

(1) Ajax of GET request

let xhr = new XMLHttpRequest() // create a connection
xhr.open('GET', url, true) // connect to the server
xhr.onreadystatechange = function () { //4. Receive the request and trigger this function when the state changes
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {//xhr.responseText is a string that needs to be converted to JSON
            success(JSON.parse(xhr.responseText))
        } else {
            fail(xhr.status)
        }
    }
}
xhr.send(null) //3
Copy the code

(2) Ajax for POST requests

let xhr = new XMLHttpRequest() // create a connection
const postData = {
    userName: 'zhangshan'.passWord: 'xxx'
}
xhr.open('POST', url, true) // connect to the server
xhr.onreadystatechange = function () { //4. Receive the request and trigger this function when the state changes
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {//xhr.responseText is a string that needs to be converted to JSON
            success(JSON.parse(xhr.responseText))
        } else {
            fail(xhr.status)
        }
    }
}
xhr.send(JSON.stringify(postData)) //3, send request (need to send string, json to string)
Copy the code

(3) Optimize with Promise

function ajax(url) {
    return new Promise((resolve, reject) = > {
        let xhr = new XMLHttpRequest() // create a connection
        xhr.open('GET', url, true) // connect to the server
        xhr.onreadystatechange = function () { //4. Receive the request and trigger this function when the state changes
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {//xhr.responseText is a string that needs to be converted to JSON
                    resolve(JSON.parse(xhr.responseText))
                }else if(xhr.status === 404){
                    reject(new Error('404'))
                }
            }
        }
        xhr.send(null) //3})}const url = ' '
ajax(url)
.then(res= > console.log(JSON.parse(xhr.responseText)))
.catch(err= > console.log(err))
Copy the code

Closure write a cache tool

function creatCache() {
    let data = {} // Hide data, external access is not available
    return {
        get(key) {
            return data[key]
        },
        set(key, val) {
            data[key] = val
        }
    }
}
var c = creatCache()
c.set('name'.'jin')
console.log(c.get('name'))
Copy the code

Shallow copy, deep copy

The shallow copy copies only the first-layer attributes of an object, while the deep copy copies the attributes recursively.

// Shallow copy (obj1 is the object to be copied)
// Method 1: original version (obj1 is the object to be copied, obj2 is already an object by default)
function shallowCopy(obj1, obj2){
    for(let key in obj1){
        obj2[key] = obj1[key]
    }
}
// Method 1: optimized version (obj is the object to be copied)
function shallowClone(obj){
    if(typeofobj ! = ='object' || obj == null) {//obj is null, or is not an object or array
        return obj
    }
    let result
    if(obj instanceof Array){
        result = []
    }else{
        result = {}
    }
    for(let key in obj){// For in an object can enumerate properties, including the properties and methods of its prototype,
        if(obj.hasOwnProperty(key)){ // Ensure that key is not an attribute of the stereotype
            // recursive call
            result[key] = obj[key]
        }
    }
    // Return the result
    return result
}
2 / / way
function shallowCopy(obj1, obj2){
    obj2 = Object.assign({}, obj1)
}
Copy the code
// Deep copy (obj1 is the object to be copied)
// Method 1: original version (obj1 is the object to be copied)
function deepCopy(obj1, obj2){
    for(let key in obj1){Obj1.hasownperporty (key) can be used to determine if the instance has this property
        let item = obj1[key] 
        if(item instanceof Array) {// Cannot use typeof item because you cannot distinguish objects from arrays
            obj2[key] = []
            deepCopy(item, obj2[key])
        }else if(item instanceof Object){
            obj2[key] = {}
            deepCopy(item, obj2[key])
        }else{
            obj2[key] = item
        }
    }
}
// Method 1: optimized version (obj is the object to be copied, obj2 is already an object by default)Ideas:1, check whether it is a value type or a reference type.2Is an array or an object.3, recursion,function deepClone(obj){
    if(typeofobj ! = ='object' || obj == null) {//obj is null, or is not an object or array
        return obj
    }
    let result
    if(obj instanceof Array){
        result = []
    }else{
        result = {}
    }
    for(let key in obj){// For in an object can enumerate properties, including the properties and methods of its prototype,
        if(obj.hasOwnProperty(key)){ // Ensure that key is not an attribute of the stereotype
            // recursive call
            result[key] = deepClone(obj[key])
        }
    }
    // Return the result
    returnResult} bug: An infinite loop occurs when two objects reference each other.2 / / way
function deepCopy(obj1, obj2){
    obj2 = JSON.parse(JSON.stringify(obj1))} Flaw: This method cannot copy function propertiesCopy the code

String hump

Method 1: Split into arrays, capitalize toUpperCase(), subString ()1) is the element after the first elementvar str="border-bottom-color";
function tf(){
  var arr=str.split("-");
  for(var i=1; i<arr.length; i++){ arr[i]=arr[i].charAt(0).toUpperCase()+arr[i].substring(1);
  }
  return arr.join(""); }; tf(str); Method two: revar str="border-bottom-color";
function tf(){
  var re=/-(\w)/g;
  str=str.replace(re,function($0, $1){
    return $1.toUpperCase();
  });
  alert(str)
};
tf(str);
Copy the code

14. Lazy loading of images

You can customize the img tag attribute data-src=’default.png’. Add the SRC attribute only when the image is detected to appear in the window.

function lazyload() {
  const imgs = document.getElementsByTagName('img');
  const len = imgs.length;
  // Height of viewport
  const viewHeight = document.documentElement.clientHeight;
  // Scroll bar height
  const scrollHeight = document.documentElement.scrollTop || document.body.scrollTop;
  for (let i = 0; i < len; i++) {
    const offsetHeight = imgs[i].offsetTop;
    if (offsetHeight < viewHeight + scrollHeight) {
      constsrc = imgs[i].dataset.src; imgs[i].src = src; }}}// Use throttling to optimize
window.addEventListener('scroll', lazyload);
Copy the code

15. Scroll loading

The principle is to listen to page scrolling events and analyze the property relations of clientHeight, scrollTop and scrollHeight.

window.addEventListener('scroll'.function() {
  const clientHeight = document.documentElement.clientHeight;
  const scrollTop = document.documentElement.scrollTop;
  const scrollHeight = document.documentElement.scrollHeight;
  if (clientHeight + scrollTop >= scrollHeight) {
    // Scroll to the bottom of the page detected, proceed with subsequent operations
    // ...}},false);
Copy the code