Some interesting javascript tricks

Source: Internet
Author: User
Tags call back

Finishing some brush problems learned tips ...


    1. Variables that are greater than 0 and less than 0
    2. String.Split () and regular expressions
    3. Several methods of caching
    4. Initializes an array of
Variables that are greater than 0 and less than 0

Problem: Design a variable val so that the following expression returns true:

Val<0 && val>0;

Logically, a number is unlikely to be greater than 0 and less than 0. All we can do is make a variable that is greater than 01 and less than 0. Is there a sequence in this expression? The answer is yes. Let us first determine if Val is greater than 0 before judging if it is less than 0. But for normal variables, this order has no meaning: the value of a normal variable does not change because you read it. So, what kind of variable will be changed by reading?

Yes, that's the selector property of the object.

We can declare an object and give it a data property, such as _value =-3, and then set it a selector attribute val, the Gettar parameter is set to: When I read the Val attribute, the value of _value is added 2, and the value of _value is returned. So when I first Judge val<0, the return value is -3+2=-1, which is set. The second judgment, once again read it, this time the return value becomes -1+2>0, also established, so the expression is true. The specific code is as follows:

var obj = {    _value: -3};object.defineproperty (obj, "_val", {    get:function () {        This._value + = 2;        return this._value;    }); o Bj._val<0 && obj._val>0;//return True

The task was basically completed here. But this method is not perfect. Why? Look at the updated version of this question:

Problem: Design a variable so that the following function returns true:

function Foo (val) {    return val<0&&val>0;}

It doesn't look right, does it? But if you put the above variables in this way, like this:

Foo (obj.val); False

It's not going to work. Because the parameters of the function are passed by value. Such a call will only read the value of Obj.val once when the parameter is passed in, and the subsequent comparison expression will only copy the value in the past for comparison, without reading the properties of obj, and will not trigger the Gettar function. In this case, the Val value is always -3+2=-1, so the test cannot be passed.

The workaround is to pass in an object instead of a value. But how do you compare objects and values when you pass in objects? The answer is the object.tostring () method.

When we try to compare the size of an object and a number, the ToString () method of the object is called, and the return value is compared to the number. Typically, the object's ToString method return value is not a number, so it cannot be compared. Here, just rewrite the ttostring method of the target object so that it returns to Obj._value. Of course, selector properties are also required.

Object.defineproperty (obj, ' toString ', function () {   get:function () {       This._value + = 2;       return this._value;});   

This way, when we pass in an object to a function parameter, the ToString method is not read and _value remains the original value. The ToString is called and the corresponding value is returned until the number and its size are compared. Done.

What is the use of this feature? I didn't think of it for the moment. However, you can at least deepen your understanding of object properties.

String.Split () and regular expressions

Problem: Splitting the string "javascriptissointeresting" into ["Javascript", "is", "so", "interesting"]

The split method of the string is familiar to everyone, and we can pass in a string parameter to split the target string, for example:

var str = "a=2&b=3&c=4"; Console.log (Str.split (' & '));//[' a=2 ', ' b=3 ', ' c=4 ']

If you have any further information, you can also know that its parameters can be regular expressions, such as:

var str= "a=2&b=3#c=4"; var reg =/[&#]/g;str.split (reg);//[' a=2 ', ' b=3 ', ' c=4 ']

In addition, split can accept the second parameter to determine the length of the split, which is relatively simple to say.

Now back to the question. To split the string in the title, we are missing a separator. A straightforward workaround is to insert a delimiter before each capital letter and then call the Split method.

var str= "javascriptissointeresting"; var reg =/([a-z][a-z])/g;str.replace (Reg, ' &$1 '). Split (' & ');//["", " Javascript ', ' is ', ' so ', ' interesting ']

A bit of a flaw, there is an empty string in front, need to be processed. But the basic goal is to achieve.

Is there a better way?

Before we do this, let's consider a question: When splitting a string with split, what happens if the string is composed only of delimiters? For example, for the string "AAAAA", the Split (' a ') processing, you will get what an array? Look at the following:

var str= "AAA"; Str.split (' a ');     [‘‘, ‘‘, ‘‘, ‘‘]

The result is a new array of empty strings between a, that is, split will assign "interval" as a member to the array when the delimiter appears consecutively.

Try it with regular expressions:

var str= "AAA"; var reg =/a/g;str.split (reg);    [‘‘, ‘‘, ‘‘, ‘‘]

The result is the same. So far everything is normal. The next feature is what we need to use.

Let's make a little change to the above code:

var str= "AAA"; var reg =/(a)/g;str.split (reg);     ["", "a", "", "a", "", "a", "" ")

Strange, isn't it? I just enclose the regular expression in parentheses around the subexpression, and in theory there should be no difference between the subexpression and the above, but when it runs into split, the miracle occurs: not only is the original partition result in the array, but the delimiter that should not exist also comes back.

The test shows that when the argument of split is a regular expression, and the expression contains a subexpression, the delimiter within the subexpression remains in the result array, rather than the usual ignore.

To apply this magical phenomenon to the topic, we use the word "one capital letter plus several lowercase letters" as the delimiter and enclose it in parentheses:

var str= "javascriptissointeresting"; var reg =/([a-z][a-z]+)/g;str.split (reg);//["", "Javascript", "", "is", "", "so", " "," interesting "]

Finally, you need to remove the empty string, and you can use the filter method:

Str.split (REG). Filter (function (val) {return/\s/.test (val);});;

Or it can be more elegant:

Str.split (REG). filter (Boolean);

The use of this feature, such as you want to write a code interpreter, for "1+20+x+y" such input, you may need to break it down into ["1", "+", "a", "+", "X", "Y"], it can be done.

Several methods of caching

Problem: The following function returns true:

function foo () {    return math.random () *math.random () *math.random===0.5;}

Obviously this function is almost impossible to return true. In fact Math.random () is only a pretence, we will have to re-math.random () in order to achieve the purpose. The question is, how to write.

Very simply, just write a function, the return value is 0.5 of the three radicals can be. But this return value is not very good to ask. So I decided to define a function that returns 0.5 on the first call and 1 for each call back.

var val = 0;function m () {  if (val! = 1) val + = 0.5;  return Val;}

Of course, the global variable is the devil, so you need to enclose Val in a closure:

Function V () {  var val = 0;  return function () {    if (val! = 1) val + = 0.5;    return val;  }} var m = V ();
M () *m () *m ();
Return 0.5

That's the first way.

Actually, is that a little familiar? Yes, this is very similar to our first question, which can also be resolved with the object's Selector property.

var obj = {  _value:0};object.defineproperty (obj, ' Val ', {  get:  function () {      if (this._value! = 1)        this._value+= 0.5;      return this._value;  }});                      var i = function () {  return obj.val;} M () *m () *m ();//Return 0.5

The last method, we can not use global variables, or closures. Consider the function itself as an object:

function m () {  if (this.val! = 1) this.val+=0.5;  return this.val;} M.val = 0;

Return 1

So far this problem seems to have little to do with caching. In fact, as long as the value of the stored data is changed to an array/object, the operation of value is changed to add an element, then it can be used as a cache.

Initializing an array

Issue: Declare an array with a length of the given value and initialize all elements to 0.

Of course, this can be done with a For loop:

var arr = [];for (var i=0; i<n; i++) {    arr[i] = 0;}

But we can do it a little bit cooler:

var n = 4;arr = Array (n+1). Join (' 0 '). Split ("). Map (number);//[0,0,0,0]

Like this, an array of all 0 is initialized with a single line of statements.

But there is a drawback: if I want to initialize the value is not single-digit, for example, is 12?

Very simple, remember the above-mentioned split method? You can do this:

var = 4;arr = Array (n+1). Join (' n '). Split (/()/). Map (number). filter (Boolean);//[12,12,12,12]

The regular part can also be changed slightly, to be divided into length, will be more elegant:

var n = 4;arr = Array (n+1). Join (' 1222 '). Split (/(\d{4})/). Map (number). filter (Boolean);//[1222,1222,1222,1222]

The above method later considered, feeling a bit around, why do I have to divide an array into a string and then merge the array? You can't just use a map, like this:

Array (n+1). Map (function () {return 0;});

Try to find out, for arrays created with array (n), no matter how the map is used, each element is still undefined.


There is room for expansion, for example, if we want to declare a 4*4 two-dimensional array, we can do this:

var n = 4;var arr = Array (n+1). Join (' 0 '). Split ('). Map (function (v) {  return Array (n+1). Join (' 0 '). Split (');});

More dimensions can continue to nest ...

The final question to consider is: it's cool, but is it necessary? Quoting a lot of methods can feel very slow.

Give it a try:

var arr1 = [];var arr2 = [];var n = 1e6;console.time ("for"), for (var i=0; i<n; i++)  arr1[i] = 0;console.timeend ("for "); Console.time (" array "); arr2 = Array (n+1). Join (' 0 '). Split ("). Map (number); Console.timeend ("array");

The output is:


The performance is also good look. The above is the data running under Firebug. Switch to local node. js Try it:



So when running code on the browser side, be sure to use it boldly, and the browser's optimizations for these native methods are simply not too powerful.

And if it's running on the back end, or trying to fool over Leetcode's code complexity detection (like me), give up the idea ...

The space is a bit long ... Stop this ...

Some interesting javascript tricks

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.