In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-08 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
In this issue, the editor will bring you about how the various source codes in JavaScript are realized. The article is rich in content and analyzes and describes for you from a professional point of view. I hope you can get something after reading this article.
Preface
Recently, many people like me are actively preparing for the front-end interview written test, so I have sorted out some native function implementations and various front-end principle implementations that are very easy to ask in the front-end interview written test.
Being able to handwrite all kinds of JavaScript native functions can be said to be the first step to get rid of the hat of API callers. We should not only know how to use them, but also explore their implementation principles!
The learning and implementation of JavaScript source code can help us to improve our front-end programming ability quickly and solidly.
Implement a new operator
The first thing we know is what new did:
Create an empty simple JavaScript object (that is, {})
Link this object (that is, set its constructor) to another object
Use the newly created object in step (1) as the context of the this
If the function does not return an object, it returns this.
Knowing what new has done, let's implement it.
Function create (Con,... args) {/ / create an empty object this.obj = {}; / / point the empty object to the prototype chain Object.setPrototypeOf (this.obj, Con.prototype) of the constructor; / / bind the obj to the constructor to access the properties in the constructor, that is, this.obj.Con (args) let result = Con.apply (this.obj, args) / / if the returned result is an object, the / / new method is invalid, otherwise obj return result instanceof Object? Result: this.obj;} implement an Array.isArrayArray.myIsArray = function (o) {return Object.prototype.toString.call (Object (o)) = ='[object Array]';}
Implement an Object.create () method
Function create = function (o) {var F = function () {}; F.prototype = o; return new F ();}; implement an EventEmitter
Real experience, recently in the byte jump of the interview was asked by the interviewer, let me handwritten implementation of a simple Event class.
Class Event {constructor () {/ / stores the data structure of events / / for fast lookup, use object (dictionary) this._cache = {}} / / bind on (type, callback) {/ / to facilitate and save space by class / / put the same type of events in an array / / the array here is the queue Follow the FIFO / / that is, the newly bound event triggers let fns = (this._ [type] = this._ [type] | | []) if (fns.indexOf (callback) =-1) {fns.push (callback)} return this} / / unbind off (type) Callback) {let fns = this._ [type] if (Array.isArray (fns)) {if (callback) {let index = fns.indexOf (callback) if (index! = =-1) {fns.splice (index) 1)}} else {/ / clear all fns.length = 0}} return this} / / trigger emit trigger (type Data) {let fns = this._ [type] if (Array.isArray (fns)) {fns.forEach ((fn) = > {fn (data)})} return this} / / one-time binding once (type, callback) {let wrapFun = () = > {callback.call (this) This.off (type, callback);}; this.on (wrapFun, callback); return this;}} let e = new Event () e.on ('click',function () {console.log (' on')}) e.on ('click',function () {console.log (' onon')}) / / e.trigger ('click',' 666') console.log (e) implement an Array.prototype.reduce
First, take a look at the Array.prototype.reduce syntax.
Array.prototype.reduce (callback (accumulator, currentValue [, index [, array]]) [, initialValue])
And then you can do it:
Array.prototype.myReduce = function (callback, initialValue) {let accumulator = initialValue? InitialValue: this [0]; for (let I = initialValue? 0: 1; I
< this.length; i++) { let _this = this; accumulator = callback(accumulator, this[i], i, _this); } return accumulator; }; // 使用 let arr = [1, 2, 3, 4]; let sum = arr.myReduce((acc, val) =>{acc + = val; return acc;}, 5); console.log (sum); / / 15 implement a call or apply
Let's take a look at an example of call to see what call has done:
Let foo = {value: 1}; function bar () {console.log (this.value);} bar.call (foo); / / 1
From the execution result of the code, we can see that call first changes the direction of this so that the this of the function points to foo, and then makes the bar function execute.
To sum up:
Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community
Call changes the function this to point to
Call function
Think about it: how can we achieve the above effect? The code is modified as follows:
Function.prototype.myCall = function (context) {context = context | | window; / / Mount the function to the fn property of the object context.fn = this; / / process the passed parameter const args = [... arguments] .slice (1); / / call the method const result = context.fn (.. ARGs) through the property of the object; / / delete the attribute delete context.fn; return result}
Let's take a look at the code above:
Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community
First of all, we have done compatible processing for the parameter context. No value is passed, and the default value of context is window.
Then we mount the function on context, context.fn = this
Process the parameters, intercept the parameters passed into myCall, remove the first bit, and then convert them to an array
Call context.fn, and the this of fn points to context
Delete the property delete context.fn on the object
Return the result.
And so on, let's implement apply by the way, the only difference is the handling of parameters, the code is as follows:
Function.prototype.myApply = function (context) {context = context | | window context.fn = this let result / / myApply is in the form of (obj, [arg1,arg2,arg3]); / / so the second parameter of myApply is [arg1,arg2,arg3] / / here we use the extension operator to deal with the way the parameter is passed if (arguments [1]) {result = context.fn (... Arguments [1])} else {result = context.fn ()} delete context.fn; return result}
The above is the simulation implementation of call and apply, the only difference is the way the parameters are handled.
Implement a Function.prototype.bindfunction Person () {this.name= "zs"; this.age=18; this.gender= "male"} let obj= {hobby: "read"} / / bind the this of the constructor to obj let changePerson = Person.bind (obj); / / call the constructor directly, and the function manipulates the obj object, adding three attributes to it; changePerson (); / / 1, output obj console.log (obj) / / using the constructor that changes the point of this, new an instance of let p = new changePerson (); / / 2, output obj console.log (p)
Take a closer look at the above code and then look at the output.
We use bind on the Person class to point its this to obj and get the changeperson function. Here, if we call changeperson directly, we will change obj. If we call changeperson with new, we will get instance p, and its _ _ proto__ points to Person. We find that bind is invalid.
We have come to the conclusion that the function pointed to by this is changed with bind, and if called with the new operator, bind will be invalidated.
This object is an example of this constructor, so as long as you execute the this instanceof constructor inside the function to determine whether the result is true, you can determine whether the function is called through the new operator. If the result is true, it is called with the new operator. The code is modified as follows:
/ / bind implements Function.prototype.mybind = function () {/ / 1, save function let _ this = this; / / 2, save target object let context = arguments [0] | | window; / / 3, save parameters outside the target object and convert them into an array; let rest = Array.prototype.slice.call (arguments,1) / / 4. Return a function to be executed, return function F () {/ / 5, and convert the parameters passed twice into an array Let rest2 = Array.prototype.slice.call (arguments) if (this instanceof F) {/ / 6. If called with the new operator, call the original function directly with new and pass the parameter return new _ this (... rest2)} else {/ / 7 with the extension operator, call the function saved in the first step with apply and bind this to pass the merged parameter array Namely context._this (rest.concat (rest2)) _ this.apply (context,rest.concat (rest2)) Implement a JS function to be Corey
The concept of Currying is not complicated, in easy-to-understand words: pass only part of the arguments to the function to call it, and let it return a function to handle the remaining parameters.
Function progressCurrying (fn, args) {let _ this = this let len = fn.length; let args = args | | []; return function () {let _ args = Array.prototype.slice.call (arguments); Array.prototype.push.apply (args, _ args); / / if the number of parameters is less than the original fn.length, it is called recursively to continue collecting parameters if (_ args.length)
< len) { return progressCurrying.call(_this, fn, _args); } // 参数收集完毕,则执行fn return fn.apply(this, _args); } }手写防抖(Debouncing)和节流(Throttling) 节流 防抖函数 onscroll 结束时触发一次,延迟执行 function debounce(func, wait) { let timeout; return function() { let context = this; // 指向全局 let args = arguments; if (timeout) { clearTimeout(timeout); } timeout = setTimeout(() =>{func.apply (context, args); / / context.func (args)}, wait);};} / use _ window.onscroll = debounce (function () {console.log ('debounce');}, 1000)
Throttling
The throttle function onscroll is triggered at regular intervals, like water droplets.
Function throttle (fn, delay) {let prevTime = Date.now (); return function () {let curTime = Date.now (); if (curTime-prevTime > delay) {fn.apply (this, arguments); prevTime = curTime;}};} / use var throtteScroll = throttle (function () {console.log ('throtte');}, 1000); _ window.onscroll = throtteScroll; hand-write a deep copy of JS
Beggar version
JSON.parse (JSON.stringfy))
It is very simple, but the defects are also obvious, such as copying other reference types, copying functions, circular references, and so on.
Basic edition
Function clone (target) {if (typeof target = = 'object') {let cloneTarget = {}; for (const key in target) {cloneTarget [key] = clone (target [key])} return cloneTarget;} else {return target}
Writing here can help you cope with some interviewers to examine your recursive problem-solving ability. But obviously, there are still some problems with this deep copy function.
For a relatively complete deep copy function, you need to consider both objects and arrays and circular references:
Function clone (target, map = new WeakMap ()) {if (typeof target = 'object') {let cloneTarget = Array.isArray (target)? []: {}; if (map.get (target)) {return target;} map.set (target, cloneTarget); for (const key in target) {cloneTarget [key] = clone (target [key], map)} return cloneTarget;} else {return target }} implement an instanceOf
Principle: whether the proto of L is equal to R.prototype does not mean that you can find L.L. Protozoa. Until proto is null.
/ / L denotes the left expression, R denotes the right expression function instance_of (L, R) {var O = R.prototype; L = L.prototypic expression; while (true) {if (L = null) {return false;} / / key here: when O is strictly equal to L, return true if (O = L) {return true } L = L.prototypes;}} implement prototype chains inherit function myExtend (C, P) {var F = function () {}; F.prototype = P.prototype; C.prototype = new F (); C.prototype.constructor = C; C.super = P.prototypes;} implement an async/await
Principle
Is to use generator (generator) to split the code snippet. Then we use a function to iterate through itself, with each yield wrapped in promise. The timing of the next step is controlled by promise
Realize
Function _ asyncToGenerator (fn) {return function () {var self = this, args = arguments; / / return value return new Promise (function (resolve, reject) {/ / get iterator instance var gen = fn.apply (self, args) / / execute the next step function _ next (value) {asyncGeneratorStep (gen, resolve, reject, _ next, _ throw, 'next', value);} / / throw an exception function _ throw (err) {asyncGeneratorStep (gen, resolve, reject, _ next, _ throw,' throw', err) } / / trigger _ next (undefined) for the first time;});};} implement an Array.prototype.flat () function
Recently, the front-end interview with bouncing bytes was also asked by the interviewer to achieve it by handwriting.
Array.prototype.myFlat = function (num = 1) {if (Array.isArray (this)) {let arr = []; if (! Number (num) | | Number (num))
< 0) { return this; } this.forEach(item =>{if (Array.isArray (item)) {let count = num arr = arr.concat (item.myFlat (--count))} else {arr.push (item)}); return arr;} else {throw tihs + ".flat is not a function";}}; implement an event proxy
This question usually asks you to talk about event bubbling and event capture mechanisms.
Red yellow blue green black white (function () {var color_list = document.getElementById ('color-list'); color_list.addEventListener (' click', showColor, true); function showColor (e) {var x = e.target; if (x.nodeName.toLowerCase () = 'li') {alert (x [XSS _ clean])) }) (); implement a two-way binding
Object.defineProperty version of Vue 2.x
/ / data const data = {text: 'default'}; const input = document.getElementById (' input'); const span = document.getElementById ('span'); / / data hijacking Object.defineProperty (data,' text', {/ / data change-> modify view set (newVal) {input.value = newVal; span [XSS _ clean] = newVal;}}) / / View change-- > data change input.addEventListener ('keyup', function (e) {data.text = e.target.value;})
Proxy version of Vue 3.x
/ / data const data = {text: 'default'}; const input = document.getElementById (' input'); const span = document.getElementById ('span'); / / data hijacking const handler = {set (target, key, value) {target [key] = value; / / data change-> modify the view input.value = value; span [XSS _ clean] = value; return value;}} Const proxy = new Proxy (data, handler); / / View change-> data change input.addEventListener ('keyup', function (e) {proxy.text = e.target.value;}); this is how the various source codes in the JavaScript shared by Xiaobian are realized. If you happen to have similar doubts, please refer to the above analysis to understand. If you want to know more about it, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.