JS callback function practice

I read an article recently: Mastering Hard Parts of JavaScript
which mainly includes the following parts:

  1. Callbacks & Higher order functions Closure
  2. scope and executioncontext
  3. JavaScript & the event loop
  4. Classes & Prototypes (OOP)

This article lists a lot of examples for practice, which helps me to learn.

I list the examples in this article that I think are very good, and then attach my own answer and some of my own understanding.

You are also welcome to think together, don’t read the answers at first, try to write by yourself first, and then you will find a lot of knowledge points that you think you understand, but there are still blind spots, try a little bit, grow a little bit, a small example every day, I will be really happy~~.

In addition, if you have other answers, welcome to leave a message in the comment area, (completed)

Let's start the main article:

Part 1 Callbacks

Q1

Write an add function to add 2 to all the values ​​in the array, and the function of adding 2 has been provided.
For example: console.log(add([1, 2, 3], addTwo)), the output should be [3,4,5]

function addTwo(num) {
    
    
    return num + 2
}
function add (arr,callback) {
    
    
  // 要写的代码
}
console.log(add([1, 2, 3], addTwo))

my answer:

The first:

function add(arr,callback) {
    
    
    let newArr = []
    for(let item of arr) {
    
    
        newArr.push(callback(item))
    }
    return newArr
}

The first method uses the usage of for...of.... Here, it should be noted that for...of outputs the value of the array, and for...in outputs the index of the array, and the output index is a string.

for(let item in arr) {
    
    
        console.log(typeof item) //string,string,string
        console.log(item) // 0,1,2
    }

The second type:

function add(array, callback) {
    
    
    const newArr = [];
    array.forEach(item => {
    
    
      newArr.push(callback(item));
    });
    return newArr;
  }

The third type:

function add (arr,callback) {
    
    
    let newArray = arr.map(item => callback(item))
    return newArray
}

Q2

Simulate the function of the accumulator to add the values ​​of the array. Note: reduce can not be used directly!
For example: the array is [4,1,3], the output value is 8

const nums = [4, 1, 3];
const add = function (a, b) {
    
    
  return a + b;
}
function reduce() {
    
    
  // 要写的代码
}
console.log(reduce(nums, add, 0))
console.log(reduce(nums, add))

my answer:

function reduce(array,callback,initalValue) {
    
    
    let accum //定义一个累加器
    if(arguments.length > 2) {
    
     //有初始值
        accum = initalValue
    } else {
    
     //无初始值
        accum =  array[0]  
        array.shift() //数组第一个值为初始值,需要将第一个值排除
    }    
    array.forEach(item => {
    
          
        accum = callback(item,accum)
    });
    return accum
}

In this part I made two mistakes:

  1. I didn't consider the problem of no initial value: In fact, else{accum = array[0]}this part of the code is only known by reading the author's answer. When we provide a function to others, we should actually consider it comprehensively and cover a variety of situations. In addition, there is still a problem with this code, that is, I did not add a checksum and report an error. When someone else passes a parameter, or the parameter passed in is not compliant, there will be a problem. It is good enough as an example, but as a function for others to use, there is still a lot to be perfected.
  2. After I considered no initial value, I added a conditional judgment, but I only considered it accum = array[0], but forgot to exclude the number that has been used as the initial value, that is, no additionarray.shift()

There is not much to look at the code, but there are many issues to consider.

Q3

Extract values ​​common to multiple arrays.
For example: [5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20], [5,12,1,15]); // output The result is [5,15]

function intersection() {
    
    
  //代码部分
}
console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20],[5,12,1,15]))

my answer:

function intersection(...arrays) {
    
    
  let array =  arrays.reduce((totalArray,currentArray) => {
    
    
    return currentArray.filter(item => totalArray.includes(item))
  })
  return [...new Set(array)]
}

My thoughts:

When writing this answer, I considered using the combination of map and filter, but later found that there are many loops, forget it... Later, I found that the combination of reduce and filter is really fragrant~~, and there are few powerful codes.

  1. The previous question simulated the simple usage of reduce. One of the usages in reduce is that when no initial value is passed in, the first value of the passed parameter is taken . In this question the initial value is arrays[0].
  2. When passing parameters, because you don’t know how many parameters there are, use the extension operator (…)
  3. There was a version of the code before, as follows:
function intersection(...arrays) {
    
    
    return arrays.reduce((acc, array) => {
    
    
        return array.filter((item) => acc.includes(item));
      })
}

This code can realize the answer in the question, but when there are repeated numbers in our array, for example console.log(intersection([5, 5,10, 15, 20], [15, 10, 1, 5, 7], [1, 10, 15, 5, 20],[5,12,1,15])), there will be problems because there is no deduplication.

Q4

Return an array, which contains all the elements of the array, remove duplicate elements
such as: [5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5], output The result is [5, 10, 15, 88, 1, 7, 100]

function union() {
    
    
// 代码部分
}
console.log(union([5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5])) //[5, 10, 15, 88, 1, 7, 100]

My answer:
the first one:

function union (...arrays) {
    
    
  const flatArray = arrays.flat()
  return [...new Set(flatArray)]
}

The second type:

function union(...arrays) {
    
    
  return arrays.reduce((totalArray,currentArray) => {
    
    
    let array = currentArray.filter(item => !totalArray.includes(item))
    return totalArray.concat(array)
  })
}

My thinking:
With the experience of the previous question, it is easy to realize this function

Q5

Constructs a function objOfMatches that takes two arrays and a callback. objOfMatches will build an object and return it. To build the object, objOfMatches will use a callback to test each element of the first array to see if the output matches the corresponding element (by index) of the second array. If there is a match, the elements in the first array will become the keys in the object, and the elements in the second array will become the corresponding values.

For example:

function objOfMatches(array1, array2, callback) {
    
    
   //代码部分
 }
 
 console.log(
    objOfMatches(
      ["hi", "howdy", "bye", "later", "hello"],
      ["HI", "Howdy", "BYE", "LATER", "hello"],
      function (str) {
    
    
        return str.toUpperCase();
      }
    )
  )

The output is { hi: 'HI', bye: 'BYE', later: 'LATER' }

My answer:
the first one:

function objOfMatches(array1, array2, callback) {
    
    
  return array2.reduce((result,value,index)=>{
    
    
    if(value === callback(array1[index])) {
    
    
      result[array1[index]] = value
    }
    return result
  },{
    
    })
}

This method is mainly for practicing reduce. I rarely used this method before. Through continuous practice of these examples, I can use it proficiently.

Attach the usage method of reduce:

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
array: the array to be traversed
total: the required value, the initial value or the result return value
currentValue: the required value, the current element
currentIndex: the optional value, the index of the current element
arr: the optional value, the current element the array object that belongs to

The second type:

 function objOfMatches(array1, array2, callback) {
    
    
    let res = {
    
    }
    array2.filter((item,index) => {
    
    
      if (item === callback(array1[index])) {
    
    
        res[array1[index]] = item;
      } 
    })
    return res
  }

Q6

Constructs a multiMap function that will accept two arrays: an array of values ​​and an array of callbacks. multiMap will return an object whose keys match elements in the values ​​array. The corresponding value assigned to a key will be an array consisting of the output of an array of callbacks, where each callback's input is a key.

For example:

function multiMap(array,callback){
    
    
   // 代码部分
}
console.log(
    multiMap(
      ["catfood", "glue", "beer"],
      [
        function (str) {
    
    
          return str.toUpperCase();
        },
        function (str) {
    
    
          return str[0].toUpperCase() + str.slice(1).toLowerCase();
        },
        function (str) {
    
    
          return str + str;
        },
      ]
    )
  );

应该输出 { catfood: [‘CATFOOD’, ‘Catfood’, ‘catfoodcatfood’], glue: [‘GLUE’, ‘Glue’, ‘glueglue’], beer: [‘BEER’, ‘Beer’, ‘beerbeer’] }

my answer:

function multiMap(array,callback){
    
    
    return array.reduce((result,val)=>{
    
    
        result[val] = callback.map(fun => fun(val)) //map本身返回一个数组
        return result
    },{
    
    })
}

Thinking:
In fact, there are many solutions, but the combination of reduce and map can make the code clearer and simpler. Sometimes development can not only be satisfied with the realization of a certain function, but also consider the simplicity of the code, computational complexity, readability, etc. , making the code better

Q7

Constructs a function objectFilter that takes an object as the first argument and a callback function as the second argument. objectFilter will return a new object. The new object will contain only the properties of the input object with a key equal to the value of the property passed to the callback

For example:

function objectFilter(obj,callback) {
    
    
 // 代码部分
}
const cities = {
    
    
    London: "LONDON",
    LA: "Los Angeles",
    Paris: "PARIS",
  };
  console.log(objectFilter(cities, (city) => city.toUpperCase()))

should output { London: 'LONDON', Paris: 'PARIS'}

my answer:

function objectFilter(obj,callback) {
    
    
  let result = {
    
    }
  for(let item of Object.keys(obj) ) {
    
    
      if(callback(item) === obj[item]) {
    
    
        result[item] = obj[item]
      }
  }
  return result
}

Thinking:
This answer mainly uses some methods of Object, including Object.keys, Object.entriesetc., these methods can convert objects into arrays containing keys or values.

Q8

Constructs a function prioritize that takes an array as the first argument and a callback function as the second argument. The callback function will return true or false. This function executes a callback for each element of the array and returns a new array, in which the element that returns true is the first in the array, and the remaining elements are the last.
For example:

function prioritize(array,callback) {
    
    
    //代码
}
const startsWithS = function (str) {
    
    
    return str[0] === "s" || str[0] === "S";
  };
  console.log(
    prioritize(
      ["curb", "rickandmorty", "seinfeld", "sunny", "friends"],
      startsWithS
    )
  ); 

Should output: ['sunny', 'seinfeld', 'curb', 'rickandmorty', 'friends']

my answer:

The first:

function prioritize(array,callback) {
    
    
    return array.reduce((accum,item) => {
    
    
        callback(item) ? accum.unshift(item):accum.push(item)
        return accum
    },[]);
}

The second type:

function prioritize(array,callback) {
    
    
    let newArray = []
    array.forEach(item => {
    
    
        callback(item) ? newArray.unshift(item):newArray.push(item)
    });
    return newArray
}

My thoughts:

This method mainly uses the unshift and push methods, which can reduce some variables and make the code more concise.

Q9

Constructs a function groupBy that takes an array as the first argument and a callback function as the second argument. This function executes a callback for each element of the array and returns a new object. The key of the new object is the return value of the callback, and the value associated with each key will be an array that contains all the values ​​passed to the callback function. The element that caused this return value.
For example:

function groupBy(array,callback){
    
    
  //代码部分
}
const decimals = [1.3, 2.1, 2.4];
const floored = function (num) {
    
    
  return Math.floor(num);
};
console.log(groupBy(decimals, floored));

Should output: { 1: [ 1.3 ], 2: [ 2.1, 2.4 ] }

my answer:

function groupBy(array,callback){
    
    
    return array.reduce((accum,item)=>{
    
    
        // accum[callback(item)]?(accum[callback(item)].push(item)):(accum[callback(item)]=[item])
        accum.hasOwnProperty(callback(item))?(accum[callback(item)].push(item)):(accum[callback(item)]=[item])
        return accum
    },{
    
    })
}

In the commented part of this answer, both writing methods can achieve this function, but I tried to use the hasOwnProperty()writing method to determine whether the current object has a specified key value.

Q10

Create a function pipe that accepts an array as the first parameter, this array is composed of multiple functions, and accepts a value (value) as the second parameter. value into the first function in the first argument, then use the output of that function as input to the second function, then use the output of that function as input to the third function, and so on, until Get the output of the last function in the array, the function should return the final output.
For example:

function pipe(array,value){
    
    
 //代码部分
}

const capitalize = (str) => str.toUpperCase();
const addLowerCase = (str) => str + str.toLowerCase();
const repeat = (str) => str + str;
const capAddlowRepeat = [capitalize, addLowerCase, repeat];
console.log(pipe(capAddlowRepeat, "cat"));

should output CATcatCATcat

my answer:

function pipe(array,value){
    
    
  return array.reduce((accum,fn)=> {
    
    
      return fn(accum)
  },value)
}

This result code is actually very short, but it requires accumproficiency in usage in the early stage

Part IIClosure

This part is an exercise on closures

Q1

Let's start with an appetizer.

Create a function addByX that returns a function that adds input x.
For example:

// 3
function addByX(value) {
    
    
   // 代码部分
}

const addByTwo = addByX(2); 
console.log(addByTwo(1));
// => 输出为 3  3 = 2  + 1
console.log(addByTwo(2));
// => 4        4 = 2 + 2
console.log(addByTwo(3));
// => 5

const addByThree = addByX(3);
console.log(addByThree(1));
// =>  4     4 = 3 + 1
console.log(addByThree(2));
// =>  5

my answer

function addByX(value) {
    
    
   return function addByNum(num) {
    
    
     return value + num
  }
}

This is a very simple closure application, which returns the value of the internal function to the outside, and realizes that the external scope calls the internal scope.

Q2

Write a function that accepts two parameters, the first parameter is the value of the number of times the callback needs to be called, and the second parameter is the callback function function to be performed. The result will be output only when the number of times the callback is executed is equal to value.

For example:

function after(value,func) {
    
    
   // 代码部分
}
const called = function () {
    
    
  console.log("hello");
};
const afterCalled = after(3, called);

afterCalled(); // => nothing is printed
afterCalled(); // => nothing is printed
afterCalled(); // => 'hello' is printed

my answer:

function after(value,func) {
    
    
    value-=1
   return function afterCalled() {
    
    
      !value ? func() : value--
   }
}

I think this example is a bit interesting. In this code, in order to declare less variables and save a little memory, I use the ternary operator; in addition, the number of times is reduced by 1 at the beginning, so that it can be judged by a non-operator Whether the specified number of times has been reached.

Another answer:

function after(count, func) {
    
    
  let counter = 0;
  function runAfter() {
    
    
    counter++;
    if (count === counter) {
    
    
      func();
    }
  }
  return runAfter;
}

This answer is also possible.

Q3

Write function delay, which accepts a callback as the first argument, and waits milliseconds (milliseconds) before allowing the callback to be called as the second argument. Any additional arguments after wait are provided when func is called.

For example:

function delay(func, wait, ...rest) {
    
    
    // 代码部分
  }
  
 function addThree(value) {
    
    
     console.log(value + 3)
  }

  delay(addThree,1000,2)

The result should output 5 after 1000ms

my answer:

function delay(func, wait, ...rest) {
    
    
    function delayRun() {
    
    
      func(...rest);
    }
    setTimeout(delayRun, wait);
  }

Q4

Write a function rollCall that takes an array and returns a function. The first time this function is called, log the first name to the console. The second time it is called, it should log the second name to the console, and so on until all names have been called. After calling all names, it should log "Everyone accounted for".

For example:

function rollCall(array) {
    
    
  //代码部分
}
const rollCaller = rollCall(["Victoria", "Juan", "Ruth"]);
rollCaller(); // => should log 'Victoria'
rollCaller(); // => should log 'Juan'
rollCaller(); // => should log 'Ruth'
rollCaller(); // => should log 'Everyone accounted for'

my answer:

The first:

function rollCall(array) {
    
    
   return function caller() {
    
    {
    
    
    if(!array.length){
    
    
        console.log('Everyone accounted for')
    } else {
    
    
        let arr = array.shift() //shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
        console.log(arr)
    }
   }}
}

This method using shift can return the first element of the array, but the problem is that it will change the array. If you just want the result, this method is still very simple

The second type:

function rollCall(array) {
    
    
    let counter = 0
    return function caller() {
    
    {
    
    
     if(counter === array.length) {
    
    
        console.log('Everyone accounted for')
     } else {
    
    
         console.log(array[counter])
         counter++
     }
    }}
 }

This method is a very normal one. Define a variable to judge how many times it has been executed. This method will definitely not change the original array.

Q5

Create a censor function that takes no arguments. This function will return a function that accepts two strings or one string. When given two strings, the returned function will save the two strings as a pair for future use. Given a string, the returned function will return the string, but the part of this string that is identical to the first string (saved pair) will be replaced by its corresponding (saved pair) second string .

For example:

function censor() {
    
    
 // 代码部分
}
const changeScene = censor();
changeScene("dogs", "cats");
changeScene("quick", "slow");
console.log(changeScene("The quick, brown fox jumps over the lazy dogs."));

应输出 The slow, brown fox jumps over the lazy cats.

my answer:

function censor() {
    
    
    let pair = new Map()
    let res = ''
    return function handleString(...args) {
    
    
        if (args.length === 2) {
    
    
            pair.set(args[0],args[1])
        } else {
    
    
            for(let [key,value] of pair) {
    
    
                reg = RegExp(key)
                res = args[0].replace(reg,value)
            }
        }
        return res
    }
}

My thinking:
This example is still a bit interesting,

  1. Here, new Mapthe method is used for storage instead of directly using the object. The advantage of using map is that this object iterablecan be used for..of..for looping.
  2. Use the spread operator (…) to pass in all parameters together. Note that the parameters passed in at this time are arrays
  3. Use String.replace()the usage to replace the content. Note that replacethe first value needs to be regular, so here I use RegExp(key)to change the value of the first parameter to regular.

Q6

Implement a function createSecretHolder(secret) that accepts any value as secret and returns the object using only two methods. getSecret() returns secret, setSecret() sets secret

For example:

// 13
function createSecretHolder(val) {
    
    
   // 代码部分
}
const obj = createSecretHolder(5);
console.log(obj.getSecret());
// => returns 5
obj.setSecret(2);
console.log(obj.getSecret());
// => returns 2

my answer:

function createSecretHolder(val) {
    
    
    let num = val
    let obj = {
    
    
       getSecret() {
    
    
           return num
       },
       setSecret(value) {
    
    
           num = value
       }
   }
   return obj
}

The code is very short, but it implements simple get and set methods

Q7

Create a function makeFuncTester that takes an array (a subarray with two elements) and returns a function (that will accept a callback). The returned function should return true if the first element (of each subarray) passed into the callback yields the corresponding second element (of the same subarray). Otherwise, the returned function should return false.

For example:

function makeFuncTester() {
    
    
 // 代码部分
}
const capLastTestCases = [];
capLastTestCases.push(["hello", "hellO"]);
capLastTestCases.push(["goodbye", "goodbyE"]);
capLastTestCases.push(["howdy", "howdY"]);
const shouldCapitalizeLast = makeFuncTester(capLastTestCases);
const capLastAttempt1 = (str) => str.toUpperCase();
const capLastAttempt2 = (str) => str.slice(0, -1) + str.slice(-1).toUpperCase();
console.log(shouldCapitalizeLast(capLastAttempt1));
// => should log false
console.log(shouldCapitalizeLast(capLastAttempt2));
// => should log true

My answer:
the first one:

function makeFuncTester(array) {
    
    
    return function closureFn(fn) {
    
    
        let res = array.find(item => fn(item[0]) !== item[1]) || []
        return res.length?false:true
    }
}

This method was first thought of, using find to find a feature that meets expectations and returns to make a judgment.

The second type:

function makeFuncTester(array) {
    
    
    return function closureFn(fn) {
    
    
        return array.every(item => fn(item[0]) === item[1]);
    }
}

The code of this method looks simpler. It mainly uses the every feature, that is, it will return true if every value meets expectations, otherwise it will return false.

Part IIIAsynchronicity

This part exercises on asynchronous calls

Q1

Write a function called everyXsecsForYsecs that will accept three parameters: a function func, a time interval, and another duration. everyXsecsForYsecs will execute the given function at the specified interval, but will automatically stop when the duration is reached.
For example:

function everyXsecsForYsecs() {
    
    
  // 代码部分
}
function theEnd() {
    
    
  console.log("This is the end!");
}
everyXsecsForYsecs(theEnd, 2, 20);
// should invoke theEnd function every 2 seconds, for 20 seconds): This is the end!

my answer:

function everyXsecsForYsecs(func,interval,duration) {
    
    
    function clear() {
    
    
        clearInterval(print)
    }
    const print =  setInterval(func, interval*1000);
    setTimeout(clear, duration*1000);
}

This is a very simple but typical asynchronous call, using setTimeout to put the clearInterval event into the macroTask

Q2

Write a function delayCounter that takes a number (call it "target") as the first argument and a number of milliseconds (call it "duration") as the second argument, and returns a function.

When the returned function is called, this function should output to the console all numbers between 1 and the target number (target), with an interval of "duration" milliseconds between them.

For example:

function delayCounter() {
    
    
 // 代码部分
}

const countLogger = delayCounter(3, 1000);
countLogger();
//After 1 second, log 1
//After 2 seconds, log 2
//After 3 seconds, log 3

my answer:

function delayCounter(target,duration) {
    
    
    return function count() {
    
    
      let num = 1
      const print = setInterval(()=>{
    
    
         if(num === target) {
    
    
            clearInterval(print)
        }
        console.log(num)
        num ++
    }, duration);
    }
}

This example exercises two parts: 1. Training on asynchronous calls; 2. Review the closure calls from the previous part

Q3

Write a Promise function that takes a value and will return this value after 2 seconds.

For example:

function promised() {
    
    
  // 代码部分
}

const createPromise = promised("wait for it...");
createPromise.then((val) => console.log(val));
// will log "wait for it..." to the console after 2 seconds

my answer:

function promised(val) {
    
    
    return new Promise(resolve => {
    
    
      setTimeout(() => resolve(val), 2000);
    });
  }

The premise of this example requires us to understand what is promise, understand resolve,reject, etc., and practice promise.thenand setTimeouthow to use it together to realize the conversion of asynchronous operations into synchronous operations. The code is short and requires a lot of knowledge.

Q4

// I'm too lazy to translate, let's go to English

Write a SecondClock class, with two methods: start and reset.​
start: upon invocation, invokes a callback (this.cb, defined in the constructor) on an argument every second, with the argument to the callback being the current seconds “value”.

In other words, the callback gets invoked every second on the “seconds hand” of the clock. Always start with 1 and don’t utilize the seconds value of the current computer clock time.

The first “tick” with value 1 occurs 1 second after the initial “secondClock” invocation.
The second “tick” with value 2 occurs 2 seconds after the initial “secondClock” invocation.

The sixtieth “tick” with value 60 occurs 60 seconds after the initial “secondClock” invocation.
The sixty-first “tick” with value 1 occurs 61 seconds after the initial “secondClock” invocation. The sixty-second “tick” with value 2 occurs 62 seconds after the initial “secondClock” invocation.
etc.

reset: upon invocation, completely stops the “clock”. Also resets the time back to the beginning Hint: look up setInterval and clearInterval.

For example:

class SecondClock {
    
    
  // 代码部分 
}

const clock = new SecondClock((val) => {
    
    
  console.log(val);
});
console.log("Started Clock.");
clock.start();
setTimeout(() => {
    
    
  clock.reset();
  console.log("Stopped Clock after 6 seconds.");
}, 6000);

One thing to note is to use the constructor

my answer:

class SecondClock {
    
    
    constructor(cb){
    
    
        this.cb = cb 
        this.time = 0
    }
    start(){
    
    
        this.clock = setInterval(() => {
    
    
            this.cb(this.time % 60)
            this.time++
        }, 1000);
    }
    reset(){
    
    
        clearInterval(this.clock)
        this.time = 0

    }
}

This example I find interesting:

  1. Use class to write, this requires us to have a basic understanding of constructors;
  2. There are two functions here, which are timing loop and clear timing loop respectively.
  3. The order of the entire result output can also be seen from the event loop mechanism

Part IV Prototype & Class

Q1

Build a function called personFromPersonStore, which receives two parameters of name and age, which can be output when calling this function. In addition, when calling the function of personFromPersonStore, you can also use the greet method in personStore. This part of the function is in code part 1 realized in. In addition, add an introduce function in code part 2, this function can output the parameter of name in personFromPersonStore.
For example:

// 4 object.create()用法
const personStore = {
    
    
    greet() {
    
    
        console.log('hello')
    }
  };

  function personFromPersonStore(name, age) {
    
    
    // 代码部分1
  }
  
 // 代码部分2

  const sandra = personFromPersonStore("Sandra", 26);
  console.log(sandra.name);
  // -> Logs 'Sandra'
  console.log(sandra.age);
  //-> Logs 26
  sandra.greet();
  //-> Logs 'hello'
  sandra.introduce();
  //-> Logs 'Hi, my name is Sandra'

my answer:

const personStore = {
    
    
    greet() {
    
    
        console.log('greet')
    }
  };

  function personFromPersonStore(name, age) {
    
    
   const person = Object.create(personStore)
   person.name = name
   person.age = age
   return person
  }
  
  personStore.introduce = function() {
    
    
      console.log(`Hi, my name is ${
      
      this.name}`)
  }

Ponder:
This exercise has two parts:

  1. The method used Object.create(), using this method first creates an empty object, and then this empty object points to the person. When we use the person attribute, if the person itself does not have it, he will check whether the personStore has this attribute through the prototype chain.
    As the author mentioned in the description:

Every object has a hidden [[prototype]] property (bad name!). Simply put, when you call a property on an object, the JS engine first checks to see if the object has that property. If it can’t find such a property, it will look at its [[prototype]] property to see which Object it descends from. const person = Object.create(personStore) tells the JS engine to create a new empty object and return it and call it person, but if we call a property of person and person doesn’t have that property, look up to personStore and see if it has that property.

  1. In the process of adding methods, because personStore itself is an object, you can directly add a method on the object. But this is mentioned for comparison with the following example.

Q2

Build a function named personFromConstructor. This function receives two parameters of name and age, which can be output when calling this function. In addition, when calling the function of personFromConstructor, you can also use the greet method in PersonConstructor. This part of the function is in the code part 1 realized in. In addition, add an introduce function in code part 2, this function can output the parameter of name in personFromConstructor.

For example:

function PersonConstructor() {
    
    
  this.greet = function() {
    
    
      console.log('hello')
  }
}

function personFromConstructor(name, age) {
    
    
  // 代码部分1
}

// 代码部分2
const mike = personFromConstructor("Mike", 30);
console.log(mike.name); // -> Logs 'Mike'
console.log(mike.age); //-> Logs 30
mike.greet(); //-> Logs 'hello
mike.introduce();//-> Logs 'I am Mike'

my answer:

function PersonConstructor() {
    
    
  this.greet = function() {
    
    
      console.log('hello')
  }
}

function personFromConstructor(name, age) {
    
    
  const person = new PersonConstructor()
  person.name = name
  person.age = age
  return person
}

PersonConstructor.prototype.introduce = function() {
    
    
  console.log(`I am ${
      
      this.name}`)
}

My thoughts:

  1. The new keyword is used here. Here is a description of the process that an instance of new will go through:
    a. Create a new object: const person = new Object();
    b. Inherit the prototype of the object: person._proto_ = PersonConstructor.prototype;
    c. Point this in PersonConstructor to person;
    d. Determine the return value of PersonConstructor Type, if it is a value type, returns obj. If it is a reference type, return an object of this reference type
    if (typeof(result) == "object") person = result; else person = obj;

  2. The difference between this example and the above example is that personStore in Q1 is an object, but PersonConstructor in Q2 is a function. We cannot directly add attributes to functions like regular objects, so the added attributes cannot be used by new instances. So the prototype is needed, and this method is added to the prototype so that it can be called.

epilogue

So far, this article is over. I practiced every example in the article in the above link, and organized my experience and mistakes in the practice, and put them in this article, although I don’t know how many people can see this article For the article, how many people will be able to practice together to the end, but as far as I am concerned, I think I have grown a lot personally. I have sorted out a lot of knowledge that I don’t know well, and I have done a lot of work on some content that I am not good at. Good intensive training, which has now become a weapon in my development.

Finally, I hope that every child who works hard can make their dreams come true~~

Guess you like

Origin blog.csdn.net/baidu_33438652/article/details/108552699