The front end needs to be improved: How bad can the code be? _html/css_WEB-ITnose

WBOY
Release: 2016-06-24 11:57:36
Original
836 people have browsed it

1. How is bad code defined?

! KissyUI is a group for the front-end project Kissy on Taobao. After watching my "Reading Bad Code Series" on the company intranet, Long Zang asked in the group: How is bad code defined? ?

Yeah, what exactly is bad code? This reminds me of one thing, which is a question another netizen asked me on gtalk: He needs the three conditions a, b, and c to be false when they are all true, and false when they are all false. How to judge.

Next, students in the KissyUI group gave many answers:

[javascript] view plaincopy

  1. // 1. Center of circle
  2. if( a&&b&&c || !a&&!b&&!c){
  3. return false
  4. }
  5. /// 2. Long Zang
  6. (a ^ b) & c
  7. // 3. Answer from Yu Gong (I gave it to the questioner on gtalk)
  8. (a xor b) or (a xor c)
  9. // 4. The questioner’s own thoughts
  10. (a b c) % 3
  11. // 5. Yun Qian’s improved version of answer 4
  12. (!!a !!b !!c)%n
  13. // 6. Ba Chi
  14. a ? ( b?c:b) : (b?!b:!c)
  15. // 7. Wu Yingjie
  16. (a != b || b != c)
  17. or
  18. (!a != !b || !b != !c)
  19. // 8. Ji Guang
  20. var v = a&&b&&c;
  21. if(!v){
  22. return false;
  23. }else if(v){
  24. return false;
  25. }else{
  26. return true;
  27. }

en... Indeed, I have not fully verified the validity of the comprehensive answer above. Because as Long Zang later emphasized: "It seems that we are going to discuss what is bad code?" Indeed, how can we write bad code? Various strange codes appear above, including the trick used by the original questioner:

[javascript] view plaincopy

  1. // 4. The questioner’s own thoughts
  2. (a b c) % 3

Because of this question Appearing in js, there is a weak type problem, that is, a, b, c may be integers, or strings, etc., so the (a b c)%3 approach will not work, so there is

[javascript] view plaincopy

  1. // 5. Yun Qian’s answer to answer 4 Improved version
  2. (!!a !!b !!c)%n Transformation and solution: Normal level
What if the above question is changed:

- What if there are not three conditions a, b, and c, but two or more conditions?

- What if it is emphasized that a, b, c themselves are not necessarily Boolean values?

Then the basic abstraction of this problem is:

[c-sharp]

view plaincopy

// v0, find xor for any number of operands function e_xor() { ... }

For this e_xor( ), the most direct way to write code is:
  1. // v1, scan all parameters, and return true if they are different, and return false if they are all the same.
  2. function e_xor() {
  3. var args=arguments, argn=args.length;
  4. args[0] = !args[0];
  5. for (var i=1; i
  6. if (args[0] != !args[i]) return true;
  7. }
  8. return false;
  9. }
  10. Next, let’s consider a question. Since arguments is an array, can we use the array method? In fact, it is said that in some js environments, direct access to arguments[x] is inefficient. Therefore, the above v1 version can have a modified version:

    [javascript] view plaincopy

    1. // v1.1, revision of v1
    2. function e_xor() {
    3. var args=[].slice.call(arguments,0), ​​argn=args.length;
    4. ...
    5. }

    This small code involves the use of splice/slice. Because it operates on arguments, splice may cause "singular" changes in function entry, and the performance effects in different engines are inconsistent, while slice may cause twice as much data copying. The reason why slice() is still used here is: after all, this is just a function parameter, not a "very large" array, so there is no need to overly consider storage issues.

    3. Generalization and solution of problems: professional level

    Next, since what we get in args is an array, then It's really not that modern to use a for loop again. The correct, popular style, and not despised by the front end is:

    [javascript] view plaincopy

    1. // v2, implementation of array method using js1.6
    2. function e_xor(a) {
    3. return ([].slice.call(arguments,1)) .some(function(b) { if (!b != !a) return true });
    4. }

    In order to explain to some people who don’t know much about js1.6 Students with new features explain the v2 version. The following code breaks down the above implementation:

    [javascript] view plaincopy

    1. //v2.1, detailed breakdown of v2
    2. function e_xor(a) {
    3. var args = []. slice.call(arguments,1);
    4. var callback = function(b) {
    5. if (!b != !a) return true
    6. }
    7. return args.some(callback);
    8. }

    some() This method will pass each element in the array args as parameter b to callback function. some() has a feature that is consistent with our original requirements:

    - when callback() returns true, some() will interrupt the enumeration of args and return the true value ; Otherwise,

    - when all elements are enumerated and callback() does not return true, some() returns a false value.

    Now read the v2 version of e_xor(), is it clear?

    Of course, just for the sake of reducing !a operation, the v2 version can also have the following revision:

    [ javascript] view plaincopy

    1. // v2.2, optimization of v2 to reduce the number of !a operations
    2. function e_xor( a) {
    3. return (a=!a, [].slice.call(arguments,1)).some(function(b) { if (!b != a) return true });
    4. }

    In this line of code, continuous operations are used:

    [javascript] view plaincopy

    1. (a=!a, [].slice.call(arguments,1))

    The continuous operation returns the value of the last subexpression, which is the array after slice(). This way of writing is mainly to control the code to "one expression".

    4. Generalization and solution of the problem: Guy entry level

    Okay, now we start writing the v3 version. Why? Because the v2 version is still not cool enough, the v2 version uses Array.some(). This feature expanded in js1.6 is not so "functional" and has some traces of object-oriented. As a diehard fan of functional languages, I believe that the most normal solution to problems like "enumerating an array" is: recursion.

    Why? Because a purely functional language like Erlang will not come up with the idea of ​​​​Array.some()? Of course there is such a method, but from a "purer" perspective, we have to write one ourselves. hehe. How to do this kind of "pure recursion" in js? The approximate prototype will look like this:

    [javascript] view plaincopy

    1. / / v3, a framework using purely functional and recursive solutions
    2. function e_xor(a, b) { ... }

    In this framework, we set e_xor() has countless parameters, but each time we only process two a and b. If a and b are equal, we will recursively compare any one of them with the subsequent n-2 parameters. In order to achieve "recursive processing of the subsequent n-2 parameters", we need to borrow an important concept in functional languages: continuity/continuation (continuous). Dongdong Yueying once had a special topic to talk about it, here it is:

    http://bbs.51js.com/viewthread.php?tid=85325

    Simple In other words, continuation is to perform continuous callbacks on function parameters. This stuff is supported in the newer functional language paradigm. For this example in this article, I wrote a separate version to analyze it. I call it the tail() method, which means specifying the tail of the function parameters. It is designed as a prototype method on the function Function.

    [javascript] view plaincopy

    1. Function.prototype.tail = function() {
    2. return this.apply(this, [].slice.call(arguments,0).concat([].slice.call(this.arguments, this.length)));
    3. }

    Note the interesting thing about this tail() method: it uses this.length. Functions in JavaScript have two length values. One is foo.length, which indicates the number of formal parameters of the foo function when it is declared; the other is arguments.length, which indicates the actual parameters passed in when the function is called. number. That is to say, for the function foo():

    [javascript] view plaincopy

    1. function foo(a, b) {
    2. alert([arguments.length, arguments.callee.length]);
    3. }
    4. foo(x);
    5. foo(x,y,z);

    The first call will display [1,2], the second time it will Display [3,2]. In any case, the parameters a and b when declared are always two, so foo.length == arguments.callee.length == 2.

    Return to the tail() method. It means:

    [javascript] view plaincopy

    1. Function.prototype .tail = function() {
    2. return this.apply( // Recall the function itself
    3. this, // Use function foo itself as this Object
    4. []. slice.call(arguments,0) // Get all the parameters when calling tail and convert them into arrays
    5. .concat( // Array connection
    6. [].slice.call(this.arguments , // Get the parameters when calling this function foo. Since tail() is always called in foo(), it actually takes the actual parameters of the latest foo()
    7. this.length) // According to The number of formal parameters when declaring foo(), intercept the tail of the foo() function parameters
    8. )
    9. );
    10. }

    So how is tail() used in this example?

    [javascript] view plaincopy

    1. // v3 .1, version using tail()
    2. function e_xor(a, b) {
    3. if (arguments.length == arguments.callee.length) return !a != !b;
    4. return (!a == !b ? arguments.callee.tail(b) : true);
    5. }

    Arguments.callee.length is used again here to determine the number of formal parameters. In other words, the end condition of the recursion is: there are only two parameters a and b left, and there is no need to scan the tail() part. Of course, the right half of the ternary expression (?:) in return will also terminate the recursion. In this case, a different condition has been found.

    In this example, we write e_xor() as a tail recursive function. This tail recursion is the essence of functional style. Unfortunately, its optimization is not supported in js. . WUWU~~ I will check the resources later to see if the new chrome v8 supports it. Classmate v8, do you still want to be V5? :)

    5. Generalization and solution of problems: Guy’s advanced level

    From the previous section, we saw Guy’s idea of ​​​​solving problems. But at this level, the first step of abstraction is often the most critical. Simply put, V3 considers:

    [javascript] view plaincopy

    1. / / v3, a framework using purely functional, recursive solutions
    2. function e_xor(a, b) { ... }

    This framework abstraction itself may be question. The correct understanding is not "a, b are exclusive-or", but "a is exclusive-or with other elements". Therefore, the framework abstraction of v4 is:

    [javascript] view plaincopy

    1. //v4, better functional framework abstraction, thinking about interfaces
    2. function e_xor(a) { ... }

    In v3, since the b value needs to be passed to the subsequent part each time, we need to do array splicing concat() in tail(). However, when we use v4's framework, the b value itself is implicit in the subsequent part, so there is no need for splicing. In this way, tail() has a new way of writing? In fact, this is more in line with the original intention of tail(). If there is a splicing process, it should be handled by foo() instead of tail() ) to handle.

    [javascript] view plaincopy

    1. //More The tail method that conforms to the original abstract meaning
    2. Function.prototype.tail = function() {
    3. return this.apply(this, [].slice.call(this.arguments, this.length ));
    4. }

    The code writing in v4 will become simpler:

    [javascript] view plaincopy

    1. // v4.1, a simpler implementation than v3
    2. function e_xor(a) {
    3. if (arguments.length < 2) return false;
    4. return (!a == !arguments[1] ? arguments. callee.tail() : true);
    5. }
    6. // v4.1.1, a concise version that does not use ternary expressions
    7. function e_xor(a) {
    8. if (arguments.length < 2) return false;
    9. if (!arguments[1] != !a) return true;
    10. return arguments.callee. tail();
    11. }

    6. Generalization and solution of the problem: Guy has no class >

    The so-called classless level means that you know he is a Guy, but you don’t know how far he can be a Guy. For example, we can find a pattern in the v4.1 version of e_xor(), namely:

    - the real processing logic is only the second line.

    Since everything else is part of the framework, we can consider a programming paradigm, which is an extension of tail. The purpose is to call e_xor on tail just like calling the sort() method on an array. The meaning of tail is to get data, and the meaning of the new extension is that both array and logic are taken as a whole. For example:

    [javascript] view plaincopy

    1. // The tailed method extended on the function prototype is used to tail the parameters
    2. Function.prototype.tailed = function() {
    3. return function( f) { // Keep the function this on the closure through the parameter f
    4. return function() { // The callable e_xor() function after tailed()
    5. if ( arguments.length < f.length 1) return false;
    6. if (f.apply(this, arguments)) return true; // Function f before calling tailed()
    7. return arguments.callee.apply(this, [].slice.call(arguments, f.length));
    8. } }
    9. }(this)
    10. }

    The usage of tailed() is very simple:

    [javascript] view plaincopy

    1. e_xor = function(a){
    2. if (!arguments[1] != !a) return true;
    3. }. tailed();

    Simply speaking, we can use the xor function as the operand of tailed(). In this way, we can expose a function named tailed The core of the public library is to expose a set of functions similar to xor. Developers can use the following programming paradigm to implement operations. For example:

    [javascript] view plaincopy

    1. /* tiny tailed library, v0 .0.0.1 alpha. by aimingoo. */
    2. Function.prototype.tailed = ....;
    3. // Exclusive OR of parameter a and all subsequent parameters
    4. function xor(a) {
    5. if (!arguments[1] != !a) return true;
    6. }
    7. //...More There are many similar library functions

    So, how to use this so-called tailed library? Very simple, one line of code:

    [javascript] view plaincopy

    1. // Find the xor value of any multiple parameters
    2. xor.tailed()(a,b,c,d,e,f,g);

    Now we have a semi-mature open library called tailed. The so-called semi-mature is because our tailed() still has a small flaw, the following line of code:

    [javascript] view plaincopy

    1. if (arguments.length < f.length 1) return false;

    The "1" in f.length 1 in the middle is a conditional parameter, which is related to the way xor processes data. To put it simply, it is precisely because a and arguments[1] need to be compared, so 1 is required here. If an algorithm needs to compare multiple operands, tailed() is not universal. So correct and complete tailed should allow the caller to specify termination conditions. For example:

    [javascript] view plaincopy

    1. // less_one() as a global constant in the tailed library function, and the default closed condition
    2. // When less_one returns true, it indicates that the recursion should terminate
    3. function less_one(args, f) {
    4. if (args.length < f.length 1) return true;
    5. }
    6. // Extended on the function prototype tailed method, used to tail the parameters
    7. Function.prototype.tailed = function(closed) {
    8. return function(f) { // Keep the function this in the parameter f On the closure
    9. return function() { // The callable e_xor() function after tailed()
    10. if ((closed||less_one).apply(this, [arguments ,f])) return false;
    11. if (f.apply(this, arguments)) return true; // Function f before calling tailed()
    12. return arguments.callee.apply (this, [].slice.call(arguments, f.length)); >
    13. The method used is still:
    [javascript] view plaincopy

    xor.tailed()(a,b,c,d,e,f,g);

    // or

    xor.tailed(less_one)( a,b,c,d,e,f,g);

    1. In different operations, less_one() can be Other termination conditions.
    Now, in this solution?? I mean, is the tailed library enough for Guy? No. It is said that there is no end to adultery, and adulterers have different ways of committing adultery. For example, we can see a problem in the above code, that is, there are many levels of function closures in tailed(), which means that there is unnecessary consumption of efficiency and storage space when calling. So, what can be done? For example? Haha, we can engage in paradigm programming and create a template:

    [javascript]

    view plaincopy

    /* tiny tailed library with templet framework, v0.0.0.1 beta. by aimingoo. */

    Function.prototype.templeted = function(args) {

    var buff = ['[', ,'][0]'];

    buff[1] = this.toString().replace(/_([^_]*)_/g, function ($0,$1) { return args[$1]||'_'});
      return eval(buff.join(''));
    1. }
    2. function tailed() {
    3. var f = _execute_;
    4. if (_closed_(arguments, f)) return false;
    5. if (f.apply(this, arguments) ) return true;
    6. return arguments.callee.apply(this, [].slice.call(arguments, f.length));
    7. }
    8. function less_one( args, f) {
    9. if (args.length < f.length 1) return true;
    10. }
    11. function xor(a) {
    12. if (!arguments[1] != !a) return true;
    13. }
    14. e_xor = tailed.templeted({
    15. closed: less_one,
    16. execute: xor
    17. })
    18. Of course, we can still do more. For example, this templet engine is quite crude, and the method of using eval() is not as ideal as new Function, etc. Regarding this part, you can refer to QoBean's way of processing meta-language, because in fact, the latter part is already approaching meta language programming.
    19. 7. Guy?
    What are we doing? We have moved further and further away from the truth. In other words, I deliberately led everyone through circles that seemed interesting but gradually moved away from the truth.

    Aren’t we looking for a piece of “less bad code”? If so, then the best way to judge the three operating conditions a, b, c is probably:

    [javascript] view plaincopy

    1. (a!=b || a!=c)

    Or, if you consider Type issues to a, b, c:

    [javascript] view plaincopy

    1. (!a!=!b || !a!=!c)

    If we consider the situation of judging a group of operands, then It is treated as an array and written as:

    [javascript] view plaincopy

    1. function e_xor( a) {
    2. for (var na=!a,i=1; i
    3. if (!arguments[i] != na) return true
    4. }
    5. return false;
    6. }

    For this code, we use the JS default The access rules for arguments should be optimized if they are optimized, and forget them if they are not, because our application environment does not require such requirements as "there are thousands of arguments here" or "e_xor() is called extremely frequently". If there is no demand, the optimization we have done in this area will be a wasted function. Apart from technical perfection, it is meaningless to the application environment.

    That’s enough. What we have learned is enough in the application environment, don't let the techniques spread in your code. The so-called technology is the ability to control the complexity of code and make the code beautiful, rather than making the technology itself powerful or perfect.

    So, when I discussed in the "Reading Bad Code" system before, I actually emphasized three processes:

    - Think clearly about the business needs first,

    - Design a clear and clear calling interface,

    - Implement it with the simplest and shortest distance code.

    Other magic horses are just floating clouds.

    =====

    Note: This article from Section 2 to Section 6 is only for students who are interested in architecture, frameworks, libraries, etc. Those who are interested in studying and researching and interested in using related technologies in language design, architectural abstraction, etc., or in basic projects are welcome to discuss it, and please do not abuse it in general application projects.

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template