In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
Today, I will talk to you about the JavaScript problems often encountered in development, which may not be well understood by many people. in order to make you understand better, the editor has summarized the following contents for you. I hope you can get something according to this article.
Get how many days there are in a month
Today encountered a demand, known month, get the first and last day of this month as a query condition to check the scope of the data
New Date (year, month, date, hrs, min, sec), new Date can accept these parameters to create a time object where when we set date to 0, we can get the date of the last day directly through getDate () and then get the last day we want.
New Date (2019, 12, 0). GetDate (); / 31 new Date (2018, 2, 0). GetDate (); / 28 / / from this we can get a method function getMonthLength (month) {const date = new Date (month); const year = date.getFullYear (); / / month is const _ month = date.getMonth () + 1; return new Date (year, _ month, 0). GetDate () } about the length property of a function
There is a very interesting question about the length attribute of the function, which is abbreviated as follows.
(() = > 1) .length = 0; / / output what
The objects that I understand have length are generally arrays or class array objects, or objects with length attributes defined, so I replied that this should be false. Later, the interview told me that the function had a length attribute, and the length attribute of the function was the number of function parameters. It suddenly dawned on me that the parameter of the function is arguments, and arguments is also an array object, so he has the length attribute.
/ / so (() = > 1). Length = 0; / / output true (a = > a) .length; / / processing of string key values in array 1
In JavaScript, arrays are indexed by numbers, but interestingly, they are also objects, so they can also contain string keys and attributes, but these are not calculated in the length of the array (length)
If a string key can be cast to a decimal number, it will be treated as a numeric index
Const arr = []; arr [0] = 1; arr ['1'] = 'cym'; console.log'; arr ['cym'] =' cym'; console.log (arr); / / [1, 'hey', cym: 'cym'] console.log (arr.length); / / 2void operator
Undefined is a built-in marker whose value is undefined (unless redefined), which can be obtained through the void operator
Statements or expressions that follow void will return undefined. Void does not change the result of the expression, just makes the expression return no value
Void true; / / undefined void 0; / / undefined
The void operator can also be useful in other places, such as not letting the expression return any results.
/ / this function does not need to return any result function doSomething (sign) {if (! sign) {return void setTimeout (doSomething, 100);}} / / maybe you often write function doSomething (sign) {if (! sign) {setTimeout (doSomething, 100); return;}} about JSON.stringify as follows
The effects of JSON.stringify and toString () are basically the same, except that the result of serialization is always a string
JSON.stringify (42); / / "42" JSON.stringify ('42'); / / "42" (string with double quotes) JSON.stringify (null); / / "null" JSON.stringify (true); / / "true"
Unsafe JSON value
All safe JSON values can be serialized using JSON.stringify, and unsafe JSON values are: undefined, function, symbol, and circular references. JSON.stringify
These unsafe JSON values are automatically ignored when they are encountered in an object, and null is returned when encountered in an array to ensure that the position of the array members remains unchanged.
JSON.stringify (undefined); / null JSON.stringify (function () {}); / / null JSON.stringify ([1, undefined, 2, function () {}, 3]); / / "1, null, 2, null, 3" JSON.stringify ({a: 2, b: function () {}}); / / "{" a ": 2}"
ToJSON method
If the toJSON method is defined in the object, it is called first when JSON is serialized, mainly in order to return a reasonable value when dealing with circular references.
In other words, the toJSON method should return a JSON value that can be secured by a string.
Const o = {a: 'cym', toJSON () {return {c:' b'};},}; JSON.stringify (o); / / {"c": "b"}
The second parameter of JSON.stringify
We can pass an optional parameter, replacer, to JSON.stringify, which can write either an array or a function to specify which properties should be processed and which should be excluded when objects are serialized, much like toJSON
1. When replacer is an array, it must be an array of strings containing the property names of the objects to be serialized, and other properties are ignored
Const obj = {a: 42, b: 30, c: 100,}; JSON.stringify (obj, ['a','c']); / / {"a": 42, "c": 100}
two。 When replacer is a function, it calls once on the object itself, and then once on each property in the object. Pass two parameters (the key and value of the object) at a time. Return 2.undecided if you want to ignore a key, otherwise return the specified value
Const obj = {a: 42, b: 30, c: 100,}; JSON.stringify (obj, (k, v) = > {/ / Note: the first time k is the original object if (k! = ='c') return v;}); / / "{" a ": 42," b ": 30}" unary operator "
We all know that a string can be converted to a number, you can use + "12" to convert to the number 12, or you can use -, such + and-are unary operators, so the method of converting a number to a string is a display conversion.
The operator also has the function of reversing symbol bits. of course, you can't write unary operators together, otherwise it will become-- it will be calculated as a decreasing operation symbol, and we can understand that-operator will change symbol bits in singular numbers. the occurrence of a double will counteract the inversion, for example, 1-1 = = 2.
# this is the js code, not the python 1 +-1 # 0 1-1 # 2 1-1 # 0 bit reversal operator
~ ~ returns the complement of 2, and ~ x is roughly equivalent to-(xroom1)
~ 42; / /-(42 / 1) = = >-43
The only x value that can get 0 (or strictly speaking-0) in-(xdistinct 1) is-1, which means that ~ returns a false value of 0 together with some numbers, and true value in other cases.
-1 is a sentry value, and sentinel values are values that are given a special meaning in each type. In C language,-1 represents the failure of function execution, and a value greater than or equal to 0 represents the success of function execution.
For example, the indexOf method of a string in JavaScript also follows this convention. This method searches for a specified string in a string and returns the location of the substring if it is found, otherwise it returns-1
The use of
We know that false values in JavaScript are: undefined, null, false, + 0,-0, NaN,'', and all others are true values, so negative values are also true values, so we can use ~ and indexOf to check the result to force the conversion to true / false values.
Const str = 'hello world'; ~ str.indexOf (' lo'); / /-4, truth value if (~ str.indexOf ('lo')) {/ / true / / find a match} ~ str.indexOf (' ol'); / / 0, false value! ~ str.indexOf ('ol'); / / true if (! ~ str.indexOf (' ol')) {/ / true / / No match found}
~ is more concise than > = 0 and = =-1
Word bit truncation
We often use ~ ~ to intercept the decimal part of a numerical value, thinking that this is the same as the Math.floor effect, but in fact this is not the case.
The first ~ in ~ executes ToInt32 and reverses the bit, and then the second does a bit reversal, that is, all the bits are reversed to the original value, and the final result is still the result of ToInt32.
~ ~ it is only suitable for 32-bit numbers, and more importantly, its handling of negative numbers is different from that of Math.floor, so you should pay more attention to it.
Math.floor (1.9); / / 1 ~ 1.9; / / 1 / / Operand negative Math.floor (- 1.9); / /-2 ~-1.9; / /-1
~ x can truncate the value to a 32-bit integer, or x | 0, and it looks more concise, but we prefer to use ~ x because of operator precedence.
~ ~ 1.9; / / 11.9 | 0; / 1 ~-1.9; / /-1-1.9 | 0; / /-1 given a group of url to implement concurrent requests
The original topic is as follows: given a set of url, use the asynchronism of js to implement concurrent requests, and output the results sequentially.
Promise.all
The first thing we can think of is to implement it using Promise.all, which is implemented in the following code
Const urls = ['. / 1.json,'. / 2.json,'. / 3.json`]; function getData (url) {/ / return a Promise to accept return new Promise using Promise.all ((resolve, reject) = > {const xhr = new XMLHttpRequest (); xhr.responseType = 'json' Xhr.onreadystatechange = () = > {if (xhr.readyState = 4) {if (xhr.status = 200) {resolve (xhr.response);}; xhr.open ('GET', url, true); xhr.send (null);}) } function getMultiData (urls) {/ / Promise.all accepts an array containing promise, if it is not promise, it will be converted to promise Promise.all (urls.map (url = > getData (url)). Then (results = > {console.log (results);});}
No need for Promise
The original title is not Promise to achieve, we can write a method, add a callback function, when all the data back, trigger the callback function to pass in the data, then all the data back is the core issue we need to consider, we can use an array or object, and then determine whether the length of the array length and the incoming url is the same.
Use objects for mapping
Const urls = ['. / 1.json,'. / 2.json,'. / 3.json`]; function getAllDate (urls, cd) {const result = {}; function getData (url, idx) {const xhr = new XMLHttpRequest (); xhr.responseType = 'json'; xhr.onreadystatechange = () = > {if (xhr.readyState = 4) {if (xhr.status = 200) {result [idx] = xhr.response / / if both length are equal, it means that if (Object.keys (result). Length = urls.length) {/ / add length attribute to the object to facilitate the conversion of the array result.length = urls.length; cd & & cd (Array.from (result));} } / / trigger function to execute urls.forEach ((url, idx) = > getData (url, idx));} / / use getAllDate (urls, data = > {console.log (data);})
Using arrays to implement
It is similar to the basic idea above, but this time it is changed to an array, and you can also give a semaphore to make a judgment.
Function getGroupData (urls, cb) {const results = []; let count = 0; const getData = url = > {const xhr = new XMLHttpRequest (); xhr.responseType = 'json'; xhr.onreadystatechange = _ = > {if (xhr.readyState = 4) {if (xhr.status = 200) {results.push (xhr.response); if (+ + count = = urls.length) {cb & cb (results) }; xhr.open ('GET', url, true); xhr.send (null);}; urls.forEach (url = > getData (url));} getGroupData (urls, data = > {console.log (data);}); Type conversion problem
Original question: how to make the value of (a = = 1 & & a = = 2 & & a = = 3) to true?
This question examines the data type conversion, = = there is a basic rule for type conversion.
NaN is not equal to any value, including itself
Undefined is equal to null (= =), and the others are not equal.
Object is compared to a string type, the object is converted to a string and then compared
Other types of comparisons should be converted into numbers for comparison.
Then we can rewrite the toString or valueOf method for this problem.
Const a = {val: 1, toString () {return this.val++;},}; if (a = = 1 & a = = 2 & & a = = 3) {console.log ('ok');}
There is another way to implement
Var I = 1; Object.defineProperty (window, 'OK', {get () {return iTunes;},}); if (a = = 1 & & a = = 2 & & a = = 3) {console.log (' OK');}
Expand [] =! [] Why true
As mentioned in the implicit type conversion rule above, other types of comparisons have to be converted into numbers for comparison, and this corresponds to that rule.
First [] .toString () will get a''string
! [] get a Boolean false
Compared with false, it must be converted to digital comparison.
Then the''conversion is 0, and the false conversion is also 0
So this question is true.
The problem with 1..toString
Sometimes when we see that other people's code will write about other types of methods, it will be written as 1..toString ().
Because if you directly use the integer number adjustment method, you will get an error, but if it is a floating point number, you will not get it wrong.
Because it may be. There is controversy above, a number is followed by a dot, and the interpreter does not know whether this is a decimal or a method to retrieve, so he runs abnormally.
1.toString () / / Uncaught SyntaxError: Invalid or unexpected token 1..toString () / /'1' 1.2.toString () / / '1.2'Generator
Object add iterator
The characteristics of a class array object: it must have length, index, and can be iterated, otherwise this object cannot be used. Syntax rotation array, we can use Array.from to turn, of course, we can also add an iterator to the object
Const obj = {0: 1,1: 2,2: 3,3: 4, length: 4, [Symbol.iterator] () {let idx = 0 return {next () {return {value: obj [idx], done: idx++ > = obj.length At this point, the object is added an iterator [... obj] / / 1 2 3 4 for (const val of obj) {console.log (val) / / 1 2 3 4}
The above problem can be implemented by byte generator. The generator returns an iterator. The iterator has a next method. Calling the next method can return value and done.
Const obj = {0: 1,1: 2,2: 3,3: 4, length: 4, [Symbol.iterator]: function* () {let idx = 0 while (idx! = = this.length) {yield this [idx++]}}
Implement an iterator for a string
Implement an iterator for a string: pass in a set of strings and return an example of a single character. Once the updated string is updated, the output also replaces the old one
Function generator (str) {let idx = 0; return {next () {return {value: str [idx], done: idx++ > = str.length,};},};} / / Test const str = 'as'; let gen = generator (str); console.log (gen.next ()); console.log (gen.next ()); console.log (gen.next ()) Console.log (gen.next ()); gen = generator ('str'); console.log (gen.next ()); console.log (gen.next ()) / / {value: 'asides, done: false} / / {value: false} / / {value: undefined, done: true} / / {value: undefined, done: true} / / {value:' slots, done: false} / / {value: 'tweets, done: false} / / {value:' ritual, done: false} / / {value: undefined, done: true}
Simple simulation of co
Simulate the implementation of co
First, let's look at an example.
Const fs = require ('fs'); const path = require (' path'); const {promisify} = require ('util'); const readFile = promisify (fs.readFile); function* read () {const name = yield readFile (path.resolve (_ dirname,' name.txt'), 'utf8'); const age = yield readFile (path.resolve (_ dirname, name),' utf8'); return age;} const it = read (); let {value, done} = it.next () Value.then (data = > {let {value, done} = it.next (data); / / console.log (data,'?') Value.then (data = > {let {value, done} = it.next (data); console.log (value);});})
This problem can be easily solved by using the co library
Const co = require ('co'); / / co accepts a generator co (read ()) .then (data = > {console.log (data);}) / / then simulate function _ co (it) {/ / first return a promise return new Promise ((resolve, reject) = > {/ / because the value can be passed, it cannot be directly implemented using a loop. You need to use recursive function next (data) {const {value, done} = it.next (data); if (done) return resolve (value)) / / guarantee value is a promise Promise.resolve (value). Then (data = > {next (data);}, reject);} next ();});} Fibonaccine sequence
Today's interview with New Oriental also mentioned the Fibonacci tangent series. In fact, this thing is very interesting. Let's briefly introduce it.
1 、 1 、 2 、 3 、 5 、 8 、 13 、 21 、 34....
There is a rule in this question. The first plus the second is always equal to the third: 1 + 1 = 2 + 2 = 3 + 3 = 5 + 5 = 8.
Which item should be passed in to get the value and realize it according to this rule?
Simple writing method
Function fibonacci (n) {/ / both the first and second terms return 1 if (n = 1 | | n = 2) return 1; / / We just return the sum of n-1 (the first term of n) and n-2 (the first two terms of n) is the value we want, return fibonacci (n-1) + fibonacci (n-2);}
Optimized version
The above writing method, the sum of less than 20 times will run very fast, more than 50 times is very slow, and more than 100 times may burst the stack, so we need to optimize the writing method and cache the value after each calculation.
Function feibo (n, sum1 = 1, sum2 = 1) {if (n = 1 | | n = 2) return sum2; return feibo (n-1, sum2, sum1 + sum2);}
This method of writing caches the value after each calculation, and the execution efficiency will be very high, and the result will be returned in a second for more than 100 times. this is also called tail recursive optimization.
Observer and publish subscription
For a long time, I thought that publishing subscriptions and observers were the same idea, and by chance I found that they were two different design ideas.
Although they all implement an one-to-many dependency on an object, when the state of an object changes, all objects that depend on it will be notified and updated automatically. But there is a difference between them.
Observer mode
In the observer mode, there will be two objects: the observer and the observed (observed target). There can be multiple observers, and multiple observers can be added to the observer to notify the observer. The observer pattern is programmed with goals and observers, coupling goals and observers.
/ / class Subject {constructor () {this.subs = [];} add (observer) {this.subs.push (observer);} notify (... args) {this.subs.forEach (ob = > ob.update (.args);}} / / Observer class Observer {update (. Args) {console.log ('Observer-> update-> args', args) } / / use const o1 = new Observer (); const o2 = new Observer (); const o3 = new Observer (); const o5 = new Observer (); const sub = new Subject (); / / add observer sub.add (o1); sub.add (O2); sub.add (o3); / / notify observer sub.notify ('hey hey')
Publish and subscribe model
The publish-subscribe model will have the concept of a scheduling center. It is programmed for the dispatching center to decouple the publisher from the subscriber.
Class PubSub {constructor () {this.handlers = {};} subscribe (type, fn) {if (! this.handlers [type]) {this.handlers [type] = [];} this.handlers [type] .push (fn);} publish (type,... args) {if (! this.handlers [type]) return; this.handlers [type] .forEach (fn = > fn (.. ARGs)) }} const ps = new PubSub (); ps.subscribe ('asides, console.log); ps.publish (' asides, 'hello world'); string to txt files (blob)
There is a requirement: pure front-end implementation, can not use nodejs
The implementation principle is also very simple, just like we usually download a local file, we can dynamically create a downloadable a tag, set the download attribute to it, and then transfer the downloaded content to blob to create a download link to download.
The specific implementation is as follows:
Function exportTxt (text, filename) {const eleLink = document.createElement ('a'); eleLink.download = filename; eleLink.style.display = 'none'; / / convert content to blob const blob = new Blob ([text]); eleLink.href = URL.createObjectURL (blob); document.body.appendChild (eleLink); eleLink.click (); document.body.removeChild (eleLink);} parity judgment
You may come across a way to judge odd and even numbers. Anyway, I met it, and it was done in a word.
Const isEven = num = > num% 2 = = 0; format money
In the project, we often encounter the need for money formatting, or number formatting, to facilitate reading (when the number is relatively large).
For example, 999999999, direct reading is not intuitive, 999999999 after formatting.
Usually we use rules to deal with
Function formatPrice (price) {return String (price) .replace (/\ B (? = (\ d {3}) + (?!\ d) / g,',');}
Or you can deal with it gracefully without using regularities.
Function formatPrice (price) {return String (price) .split (') .reverse () .reduce ((prev, next, index) = > {return (index% 3? Next: next +',') + prev;});}
These are the two more commonly used schemes mentioned above, but js also has a powerful API that can directly implement this requirement, oh, it is toLocaleString, and we can directly digitally call this method to achieve the formatting of the amount.
(999999999) .toLocaleString (); / / 999999999 / / of course you can show a little more const options = {style: 'currency', currency:' CNY',}; (123456) .toLocaleString ('zh-CN', options); / / ¥123456.00
ToLocaleString can accept two optional parameters: locales and options, and this api does not have compatibility problems in all major browsers, and this api not only exists on the prototype of Number, but also has this api on Array, Object, and Date prototypes, and the formatted values can produce various results according to the parameters we passed in.
Parameters and usage can be found in MDN.
Deeply frozen object
In the development of the vue project, there are some constant constants. We do not want vue to do two-way binding for him to reduce some performance consumption. We can use Object.freeze to freeze the object. At this time, vue will not freeze the object, but this freeze is only the first layer of the frozen object, so if the object level is relatively deep, we can write a deeply frozen api to do some freezing optimization on constant objects.
Const deepFreeze = o = > {const propNames = Object.getOwnPropertyNames (o); propNames.forEach (name = > {const prop = o [name]; if (typeof prop = 'object' & & prop! = = null) {deepFreeze (prop);}}); return Object.freeze (o);}; desensitization treatment
In some cases involving user privacy, we may encounter desensitization of information such as the user's mobile phone number and ID number, but the rule of desensitization data is dynamically generated according to the desensitization field of the user information. at this time, we dynamically splice the rule to implement a dynamic desensitization rule.
Const encryptReg = (before = 3, after = 4) = > {return new RegExp ('(\\ d {'+ before +'})\\ d * (\\ d {'+ after +'})');}; / / use: '13456789876'.replace (encryptReg (),' $1 million for each tree)-> "134 trees traverse the tree"
Generally speaking, there are depth first and breadth first for traversing tree structure.
The concepts of breadth first and depth first are simple, and the differences are as follows:
Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community
Depth first, visit a subtree and then visit the later subtree, while when visiting the subtree, first visit the root and then access the root subtree, which is called preorder traversal; visit the subtree first and then the root, which is called post-order traversal.
Breadth first, that is, layer n must be accessed before accessing layer 1 of the tree structure.
1. Depth first
Preorder traversal
Const treeForEach = (tree, func) = > {tree.forEach (data = > {func (data); data.children & & treeForEach (data.children, func);});}
Post-order traversal, only need to change the order of node traversal and subtree traversal.
Const treeForEach = (tree, func) = > {tree.forEach (data = > {data.children & & treeForEach (data.children, func); func (data);});}
two。 Breadth first
The idea of breadth first is to maintain a queue whose initial value is a list of tree root nodes, and repeat the following steps until the queue is empty. Take out the first element in the queue, perform access-related operations, and then append all its descendant elements (if any) to the end of the queue.
Const treeForEach = (tree, func) = > {let node, list = [... tree]; while ((node = list.shift () {func (node); node.children & & list.push (.node.children);}}; array grouping
When developing the mobile terminal, we encountered the need for a revision of the home menu, which was visible and hidden according to the permission control, while the menu displayed eight small menus per page, and more than eight of them did swipe sliding switch. at that time, the project used the UI framework made by vant, and the menu module chose his carousel plug-in, and the menu made a flat list configuration. First, all the authorized menu items were filtered according to the permissions, and then grouped every eight. Process it into a two-dimensional data to traverse the menu
Const arrayGroupBySize = (arr, size = 2) = > {const result = []; for (let I = 0, len = arr.length; I
< len; i += size) { result.push(arr.slice(i, i + size)); } return result; };下划线与驼峰 做一些数据持久化的工作的时候经常会出现下划线命名和驼峰命名的转化,因为在前端处理中规范是驼峰命名,而像 mysql 之类的规范是下划线命名,所以在处理后返回给前端的数据需要转换为驼峰命名,而对数据库的读写需要下划线命名 const toHump = name =>{return name.replace (/\ _ (\ w) / g, function (all, letter) {return letter.toUpperCase ();});}; const toLine = name = > {return name.replace (/ ([AMEZ]) / g,'_ $1'). ToLowerCase ();}; check time format
When a person is encountered in the business to verify whether the incoming time format is a time format, the following method can be used to verify it perfectly
Const isDate = str = > {return typeof str! = 'number' & & str! = = null & & new Date (str)! = =' Invalid Date';}; after reading the above, do you have any further understanding of the JavaScript problems often encountered in development? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.
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.