Home  >  Article  >  Web Front-end  >  JavaScript tips

JavaScript tips

hzc
hzcforward
2020-06-12 10:38:161691browse

Arrays can be found everywhere in JavaScript, and we can do a lot of great things using the new feature spread operator in ECMAScript 6.

1. Iterate over an empty array


Arrays created directly in JavaScript are loose, so there will be many pitfalls. Try creating an array using the array constructor and you will understand it instantly.

const arr = new Array(4);
[undefined, undefined, undefined, undefined]
// 谷歌浏览器中是 [empty x 4]

You will find that it is very difficult to loop through some transformations through a loose array.

const arr = new Array(4);
arr.map((elem, index) => index);
[undefined, undefined, undefined, undefined]

To solve this problem, you can use Array.apply when creating a new array.

const arr = Array.apply(null, new Array(4));
arr.map((elem, index) => index);
[0, 1, 2, 3]

2. Pass an empty parameter to the method


If you want to call a method and do not fill in one of the parameters, JavaScript will report an error .

method('parameter1', , 'parameter3'); // Uncaught SyntaxError: Unexpected token ,

One of our common solutions is to pass null or undefined.

method('parameter1', null, 'parameter3') // or
method('parameter1', undefined, 'parameter3');

According to the introduction of the spread operator in ES6, there is a cleaner way to pass empty parameters to a method. As mentioned above, arrays are loose, so it is okay to pass null values ​​to them, and we take advantage of this.

method(...['parameter1', , 'parameter3']); // 代码执行了...

3. Array deduplication


I have never understood why the array does not provide a built-in function that allows us to easily obtain the deduplicated value. . The spread operator helps us. Using the spread operator with Set can generate a unique array.

const arr = [...new Set([1, 2, 3, 3])];
// [1, 2, 3]

4. Get array elements from back to front


If you want to get the elements of an array from back to front, you can write like this:

var arr = [1, 2, 3, 4]

console.log(arr.slice(-1)) // [4]
console.log(arr.slice(-2)) // [3, 4]
console.log(arr.slice(-3)) // [2, 3, 4]
console.log(arr.slice(-4)) // [1, 2, 3, 4]

5. Short-circuit conditional sentence


If you want to execute a function when the logical value of a certain condition is true, like this:

if (condition) {
  dosomething()
}

At this time, you can use short circuit like this:

condition && dosomething()

6. Use the operator "||" to set the default value


If You must assign a default value to a variable, which can be simply written like this:

var a

console.log(a) // undefined
a = a || 'default value'
console.log(a) // default value
a = a || 'new value'
console.log(a) // default value

7. Use Object.is() in equality comparison


We We all know that JavasScript is weakly typed, and when we use == for comparison, in some cases unexpected things will happen due to type conversion or "convert one of the two operands to the other and then compare" the result of. Like this:

0 == ' ' //true
null == undefined //true
[1] == true //true

So JavaScript provides us with the equality operator ===, which is more strict than the inequality operator and does not cause type conversion. But using === for comparison is not the best solution. You may get:

NaN === NaN //false

ES6 provides a new Object.is() method, which has some features of ===, is better and more precise, and performs well in some special cases. :

Object.is(0 , ' '); //false
Object.is(null, undefined); //false
Object.is([1], true); //false
Object.is(NaN, NaN); //true

8. Give a function Bind object


We often need to bind an object to this of a method. In JS, if you want to call a function and specify its this, you can use the bind method.

Bind Syntax

fun.bind(thisArg[, arg1[, arg2[, ...]]])

Parameters

thisArg

When the binding function is called, the The parameters will serve as this pointers to the original function when it is run.

arg1, arg2, …

When the bound function is called, these parameters will be passed to the bound method before the actual parameters.

Return value

Returns a copy of the original function modified by the specified this value and initialization parameters

Instance in JS

const myCar = {
 brand: 'Ford',
 type: 'Sedan',
 color: 'Red'
};

const getBrand = function () {
 console.log(this.brand);
};

const getType = function () {
 console.log(this.type);
};

const getColor = function () {
 console.log(this.color);
};

getBrand(); // object not bind,undefined

getBrand(myCar); // object not bind,undefined

getType.bind(myCar)(); // Sedan

let boundGetColor = getColor.bind(myCar);
boundGetColor(); // Red


9. Get the file extension

Solution 1: Regular expression

function getFileExtension1(filename) {
  return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename)[0] : undefined;
}

Solution 2: String's split method

function getFileExtension2(filename) {
  return filename.split('.').pop();
}

These two solutions cannot solve some edge cases. There is another more powerful solution.

Solution 3: String's slice and lastIndexOf methods

function getFileExtension3(filename) {
  return filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
}

console.log(getFileExtension3(''));                            // ''
console.log(getFileExtension3('filename'));                    // ''
console.log(getFileExtension3('filename.txt'));                // 'txt'
console.log(getFileExtension3('.hiddenfile'));                 // ''
console.log(getFileExtension3('filename.with.many.dots.ext')); // 'ext'


How is this implemented?

  • ## The #String.lastIndexOf() method returns the last position where the specified value ('.' in this example) appears in the string that calls the method, or -1 if not found.

  • For 'filename' and '.hiddenfile', the return values ​​​​of lastIndexOf are 0 and -1 respectively. The unsigned right shift operator (»>) converts -1 to 4294967295, Convert -2 to 4294967294. This method can ensure that the file name remains unchanged in edge cases.

  • String.prototype.slice() Extracts the extension of the file from the index calculated above. If the index is greater than the length of the file name, the result is "".

10. Prevent unapply attacks


Rewrite the prototype method of the built-in object. External code can be exposed by rewriting the code. and functions that modify bound parameters. This is a serious security issue when using polyfills under es5's approach.

// bind polyfill 示例
function bind(fn) {
  var prev = Array.prototype.slice.call(arguments, 1);
  return function bound() {
    var curr = Array.prototype.slice.call(arguments, 0);
    var args = Array.prototype.concat.apply(prev, curr);
    return fn.apply(null, args);
  };
}


// unapply攻击
function unapplyAttack() {
  var concat = Array.prototype.concat;
  Array.prototype.concat = function replaceAll() {
    Array.prototype.concat = concat; // restore the correct version
    var curr = Array.prototype.slice.call(arguments, 0);
    var result = concat.apply([], curr);
    return result;
  };
}

上面的函数声明忽略了函数bind的prev参数,意味着调用unapplyAttack之后首次调用.concat将会抛出错误。

使用Object.freeze,可以使对象不可变,你可以防止任何内置对象原型方法被重写。

(function freezePrototypes() {
  if (typeof Object.freeze !== 'function') {
    throw new Error('Missing Object.freeze');
  }
  Object.freeze(Object.prototype);
  Object.freeze(Array.prototype);
  Object.freeze(Function.prototype);
}());

11.Javascript多维数组扁平化


下面是将多位数组转化为单一数组的三种不同方法。

var arr = [[1, 2],[3, 4, 5], [6, 7, 8, 9]];

期望结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

解决方案1:使用concat()和apply()

var newArr = [].concat.apply([], arr);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

解决方案2:使用reduce()

var newArr = arr.reduce(function(prev, curr) {
  return prev.concat(curr);
});
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

解决方案3:使用 ES6 的展开运算符

var newArr = [].concat(...arr);
console.log(newArr);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

12. 函数中如何使用可选参数(包括可选回调函数)


实例函数中第2个与第3个参数为可选参数

function example( err, optionA, optionB, callback ) {
        // 使用数组取出arguments
        var args = new Array(arguments.length);
        for(var i = 0; i < args.length; ++i) {
            args[i] = arguments[i];
        };
        
        // 第一个参数为错误参数
        // shift() 移除数组中第一个参数并将其返回
        err = args.shift();

        // 如果最后一个参数是函数,则它为回调函数
        // pop() 移除数组中最后一个参数并将其返回
        if (typeof args[args.length-1] === &#39;function&#39;) { 
            callback = args.pop();
        }
        
        // 如果args中仍有元素,那就是你需要的可选参数
        // 你可以像这样一个一个的将其取出:
        if (args.length > 0) optionA = args.shift(); else optionA = null;
        if (args.length > 0) optionB = args.shift(); else optionB = null;

        // 像正常一样继续:检查是否有错误
        if (err) { 
            return callback && callback(err);
        }
        
        // 打印可选参数
        console.log(&#39;optionA:&#39;, optionA);
        console.log(&#39;optionB:&#39;, optionB);
        console.log(&#39;callback:&#39;, callback);

        /* 你想做的逻辑 */

    }

    // ES6语法书写更简短
    function example(...args) {
        // 第一个参数为错误参数
        const err = args.shift();
        // 如果最后一个参数是函数,则它为回调函数
        const callback = (typeof args[args.length-1] === &#39;function&#39;) ? args.pop() : null;

        // 如果args中仍有元素,那就是你需要的可选参数你可以像这样一个一个的将其取出:
        const optionA = (args.length > 0) ? args.shift() : null;
        const optionB = (args.length > 0) ? args.shift() : null;
        // ... 重复取更多参数

        if (err && callback) return callback(err);

        /* 你想做的逻辑 */
    }

推荐教程:《JS教程

The above is the detailed content of JavaScript tips. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.im. If there is any infringement, please contact admin@php.cn delete