[Interview question] Which operators of Javascript do you know?

 

Front-end interview question bank ( necessary for interview) recommendation: ★★★★★            

Address: front-end interview question bank

[National Day Avatar] - National Day patriotic programmer avatar! always one option fit for you!

theme: devui-blue highlight: a11y-light

Whether it is JavaScript or other languages, operators are the foundation, and operators may exist in expressions and statements. The following is a list of the functions and usage scenarios of some operators in JavaScript that you may not know.

+ addition operator

If it is a unary operation (also called a unary operation), that is, an operand, it will be  implicitly converted  to numbera type:

// 获取当前时间戳
new Date().getTime() // 1681607509065
Date.now() // 1681607509065

// better
+new Date() // 1681607509065

If there are two operands, +the operands on both sides will be  implicitly converted  to the basic data type first, and judged in the following order:

  1. If one side is string, turn the other side into string:
[1, 2, 3] + '' // '1,2,3'
  1. BigIntAddition is performed if both sides BigIntare, and if only one side is BigInt, an error is thrown TypeErrorbecause BigIntunary +operations are not supported:
10n + 20n; // → 30n
+ 10n // → TypeError: Cannot convert a BigInt value to a number
  1. Otherwise convert both sides numberto perform numeric addition:
let a = {
    valueOf: () => false
}
a + true // 1

** Power (exponent) operator

** It is a new exponentiation operator in ES7, which can replace Math.pow():

Math.pow(2, 3) // 8

// better
2 ** 3 // 8

** A characteristic of the operator is right associativity, rather than the usual left associativity. When multiple exponentiation operators are used together, they are counted from the far right:

2 ** 2 ** 3 // 256
// 相当于
2 ** (2 ** 3) // 256

()The precedence of expressions can be controlled using the parenthesis operators :

(2 ** 2) ** 3 // 64

? : conditional (ternary) operator

condition ? exprIfTrue : exprIfFalse

In simple conditional judgments, ternary operations can be used ? :instead if else:

if (age >= 18) {
    console.log('成年')
} else {
    console.log('未成年')
}

// better
age >= 18 ? console.log('成年') : console.log('未成年')

Of course, the conditional operator can also be chained, and it also satisfies the right combination:

age >= 70 ? console.log('从心所欲')
    : age >= 60 ? console.log('耳顺')
    : age >= 50 ? console.log('知天命')
    :age >= 40 ? console.log('不惑')
    : age >= 30 ? console.log('立')
    : console.log('啥也不是')

Note: if condition is not a boolean an implicit conversion will occur , if it is a true value Truthy, it will be executed exprIfTrue:

let studyList = [{ name: 'jude', age: 25 }, { name: 'andy', age: 24 }]
let person = studyList.find(item => item.age < 18) // undefined
person ? console.log('要开花') : console.log('要发芽') // '要发芽'

To add to Truthy and Falsy:

Falsy: false , 0, -0, 0n, "", null, undefined and NaN

Truthy:  Everything but false is true

, the comma operator

The comma operator can create more than one compound expression, the entire compound expression evaluates to the value of the rightmost expression :

x => {
    x = x + 1
    return x
}

// better
x => (x++, x)
// or
x => ++x

Most commonly used to provide multiple arguments in a for loop:

for (let i = a.length - 1, j = b.length - 1; i >= 0 || j >= 0; i--, j--) {
  //do sth
}

% remainder operator

The remainder operator returns the remainder of dividing the left operand by the right operand, with the sign of the return value consistent with the sign of the dividend:

13 % 5  // 3
13 % -5 // 3
13.5 % 5 // 3.5
-13 % 5 // -3
NaN % 2 // NaN
Infinity % R // NaN    // R表示任意一个实数
R % Infinity // R
Infinity % Infinity // NaN

It can be applied in some algorithm problems:

已知2019年的第一天是周四,求第x天是周几:

function getDay(x) {
    return [4, 5, 6, 0, 1, 2, 3][x % 7]
}

?. optional chaining operator

We know that js will throw a when reading the property of nullor :undefinedTypeError

null.name // TypeError: Cannot read properties of null (reading 'name')
undefined.name //  TypeError: Cannot read properties of undefined (reading 'name')

ES2020 Added an optional chain operator, which can be used in the above cases and short-circuit returns undefined:

null?.name // undefined
undefined?.name // undefined

Optional chaining for function calls :

let personList = [
    { name: 'jude' }
]
// personList[0].sleep() // person.sleep is not a function
if (personList[0].sleep) {
    personList[0].sleep()
}
// better
personList[0].sleep?.() // undefined

// 如果前面的对象也可能不存在的话:
personList[1]?.sleep?.() // undefined

// 当然如果,该属性虽然存在但是不是一个函数,就会报is not a function:
personList[0]?.name() // TypeError: personList[0]?.name is not a function

Can also be used with square bracket property accessors  and  accessing array elements :

let propertyName = 'name'
null?.[propertyName] // undefined

let arr = []
arr?.[0] // undefined

Note that the optional chaining operator cannot be used for assignment :

({})?.name = 'jude' // SyntaxError: Invalid left-hand side in assignment

&& Logical AND operator and || Logical OR operator

From left to right, &&find Falsy||find Truthy, if found, return the found value, otherwise return the next one:

1 && {} && ' ' && NaN && undefined // NaN
'' || 0 || null ||  [] || 1 // []

So they both belong to the short circuit operator :

&&It can be used as the judgment execution of the function:

if (age >= 22) {
    work()
}
// or
age >= 22 && work() 

||Can be used to set alternate values:

name => {
    if (name) {
        return name
    } else {
        return '未知'
    }
}
// better
name => name ? name : '未知'
// or
name => name || '未知'

The above writing methods will judge namewhether it is Falsyto set its default value, and the default valueES6 of will only judge whether it is :undefined

(name = '未知') => name
// 相当于
name => name === undefined ? name : '未知'

// such as
((name = '未知') => name)(null) // null
((name = '未知') => name)(0) // 0
((name = '未知') => name)(undefined) // '未知'
((name = '未知') => name)() // '未知'

Note that &&the priority is higher than ||:

1 || 1 && 0  // 1

?? Null coalescing operator

The null coalescing operator returns ??the right operand if and only if the left operand is nullOR .undefined

As mentioned above, the logical or operator ||can be used to set alternate values, but there are actually hidden dangers:

function getScore(x) {
    x = x || '未知'
    console.log('张三的英语成绩是:' + x)
}
getScore(0) // '张三的英语成绩是:未知'

The logical OR operator returns the ||right operand Falsywhen the left operand is . However 0, ''it also belongs to Falsy, but in some scenarios they are actually wanting the results, such as the above code.

The null coalescing operator ??solves this problem:

function getScore(x) {
    x = x ?? '未知'
    console.log('张三的英语成绩是:' + x)
}
getScore(0) // '张三的英语成绩是:0'

?.Often used with the optional chaining operator :

let person
person?.name ?? '未注册' // '未注册'

!! double not operator

The logical NOT operator !, which checks whether the operand is true or false and Truthyreturns if it is false, and Falsyreturns if it is true. The double-fly operator !!, on this basis, is negated, and its function is equivalent to Boolean():

Boolean('') // false

// or
!!'' // false

Here are some bitwise operators

Bitwise operators treat operands as 4byte(32bit)binary strings . Performs operations on this basis, but ultimately returns a decimal number.

<< left shift operator and >> right shift operator

x << n Will  x convert  32 the bit into binary, then n shift , and the bit out of bounds on the left is discarded:

10 * 2³ // 80

// better
10 << 3 // 80

x >> n It will be  x converted into  32 binary bits, and then nshifted , and the out-of-bounds bits on the right are discarded:

Math.floor(a / Math.pow(2,n))
// or
Math.floor(a / 2 ** n)

// better
a >> n

This can be applied in binary search :

function BinarySearch(arr, target) {
    const n = arr.length
    let left = 0, 
        right = n - 1
    while (left <= right) {
      // let mid = Math.floor((left + right) / 2)
      // better
      let mid = (left + right) >> 1
      if (arr[mid] === target) {
          return mid
      } else if (arr[mid] > target) {
          right = mid - 1
      } else {
          left = mid + 1
      }
    }
    return -1
}

^ bitwise XOR operator

After the bitwise XOR operator  ^ converts the operands on both sides into 32-bit binary numbers, compare each bit one by one, and 1return if there is only one 1:

3 ^ 5 // 6
// 00000000000000000000000000000011    // 3
// 00000000000000000000000000000101    // 5
// 00000000000000000000000000000110    // 6

Can be used to swap two values:

let a = 3,
    b = 5;
let temp = a
a = b // 5
b = temp //3

// 以上交换使用额外的内存temp,而^可以in-place原地交换:
// better
a = a ^ b
b = a ^ b // 5
a = a ^ b // 3

The XOR operator ^satisfies the following three properties:

  1. XOR operation between any number and 0, the result is still the original number: �⊕0=�x⊕0=x
  2. XOR any number with itself, the result is 0: �⊕�=0x⊕x=0
  3. The XOR operation satisfies commutative and associative laws: �⊕�⊕�=�⊕�⊕�=�⊕(�⊕�)=�⊕0=�x⊕y⊕x=y⊕x⊕x=y⊕( x⊕x)=y⊕0=y

The following is an algorithmic problem solved using the above three properties :

Given a  non-empty  integer array nums, each element appears twice except for a certain element that appears only once. Find the element that appears only once. (You'd have to design and implement a linear-time algorithm to solve this problem that uses only constant extra space.)

/**
 * @param {number[]} nums
 * @return {number}
 */
function singleNumber (nums) {
    let ans = 0
    for (let i = 0; i < nums.length; i++) {
        ans ^= nums[i]
    }
    return ans
};
singleNumber([4, 1, 2, 1, 2]) // 4

In addition, the XOR operator can be used for simple encryption and decryption operations. For example, we can XOR each character of a string with a key to get an encrypted string, and then XOR the encrypted string with the key to get the original String:

let str = 'Hello World'
let key = 123
let encrypted = ''
for (let i = 0; i < str.length; i++) {
  encrypted += String.fromCharCode(str.charCodeAt(i) ^ key)
}
console.log(encrypted) // '3[,	'
let decrypted = ''
for (let i = 0; i < encrypted.length; i++) {
  decrypted += String.fromCharCode(encrypted.charCodeAt(i) ^ key)
}
console.log(decrypted) // 'Hello World'

~ bitwise NOT operator

The bitwise NOT operator ~ converts the operand to a 32-bit signed integer, and then inverts the bitwise:

focus:

  • The numbers stored in the computer are stored in the form of complement code (as for why the circuit is involved, only addition can be done, not subtraction, so the inverse code and complement code are designed to store negative numbers)
  • The complement and complement of positive numbers are equal to the original code
  • The complement of a negative number is equal to the inversion of the original code + 1

const a = 5;     // 32位二进制:00000000000000000000000000000101
// 取反后:11111111111111111111111111111010(补码)
~a  // -6

In summary: When a bitwise NOT operation is performed,  x the result of the operation on any number is  -(x + 1).

Therefore, an ~alternative !== -1judgment can be used:

// == -1 的写法不是很好称为“抽象渗漏”,意思是在代码中暴露了底层的实现细节,这里指用-1作为失败的返回值,这些细节应该屏蔽调。————出自《你不知道的JavaSript(中卷)》
if (str.indexOf('xxx') !== -1) {}

// better
if (~str.indexOf('xxx')) {}

A useful last introduction...

... extension

The extension character ...can expand the array expression or string at the grammatical level during function call/array construction; it can also expand the object expression in the key-value manner when constructing a literal object.

object expansion

Only the target object's own and enumerable properties are copied :

let _a = { name: 'jude' }
let a = Object.create(
    _a, // 原型链上的属性name,不自有
    { 
        myName: { // 自有属性myName,可枚举
            value: '张三',
            enumerable: true
        },
        age: { // 自由属性age,不可枚举
            value: 30,
            enumerable: false
        }
    }
)
let b = {...a} // {myName: '张三'}

In the above code,  Object.create()  will _abe used aas the prototype object, so the _aproperties on it are not self-owned properties ; at the same time, free properties are created for themselves , but they are set to be non-enumerable . Finally, the extension is used to realize the cloning of the object, and only this own and enumerable property is cloned . This is the same result as  Object.assign()  :nameamyNameageageamyName

let c = Object.assign({}, a) // {myName: '张三'}

array expansion

For (shallow) cloning of arrays, for array items of complex data types only their references will be cloned:

let arr = [{ a: 1 }]
let copyArr = [...arr] // [{ a: 1 }]

arr[0].a = 2
copyArr // [{ a: 2 }]

For concatenating arrays:

let arr1 = [0, 1, 2]
let arr2 = [3, 4, 5]
let arr3 = arr1.concat(arr2) // [0, 1, 2, 3, 4, 5]
// better
let arr4 = [...arr1, ...arr2] // [0, 1, 2, 3, 4, 5]

for function calls:

function fn(a, b, c) { }
let args = [0, 1, 2]
fn.apply(null, args)

// better
fn(...args)

string expansion

'123'.split('') // ['1', '2', '3']

// or
[...'123']  // ['1', '2', '3']

It cannot be said that it is used for converting class arrays to arrays

An array-like object is an object with a .length property.

Array.from() creates a new shallow copy of the Array instance from an iterable or array-like object. When using the spread syntax in arrays or function parameters , the syntax can only be used with  iterable objects :

let fakeArray = {
    0 : 1,
    1 : 2,
    2 : 3,
    length: 3
}
Array.from(fakeArray) // [1, 2, 3]
[...fakeArray] // TypeError: fakeArray is not iterable

Maybe you will ask, [...'123']isn’t it also using the expansion syntax in the array, '123'but the basic data type, how can it be iterated?

In fact, the engine will '123'wrap it into Stringan object, and the method Stringis encapsulated on the object Symbol.iterator():

let str = '123';

let strIterator = str[Symbol.iterator]();
strIterator.next() // {value: '1', done: false}
strIterator.next() // {value: '2', done: false}
strIterator.next() // {value: '3', done: false}
strIterator.next() // {value: undefined, done: true}

...remaining parameters

If the last parameter of the function ...is prefixed with , it will be a true array of the remaining arguments , and arguments is a pseudo-array:

function fn (a, ...b) {
    console.log(b)
    console.log(arguments)
}
fn(1, 2, 3) 
// [2, 3]
// Arguments(3) [1, 2, 3, callee: (...), Symbol(Symbol.iterator): ƒ]

Rest parameters ...can be destructured:

function fn(...[a, b, c]) {
  return a + b + c;
}
fn(1) // NaN (b and c are undefined)
fn(1, 2, 3) // 3
fn(1, 2, 3, 4) // 6

Rest parameters ...must be at the end:

function fn (a, ...b, c) {} // SyntaxError: Rest parameter must be last formal parameter

... remaining attributes

In destructuring assignment, the remaining properties ...can get the remaining properties of the array or object and store them in a new array or object:

const { a, ...others } = { a: 1, b: 2, c: 3 }
console.log(others) // { b: 2, c: 3 }

const [first, ...others2] = [1, 2, 3]
console.log(others2) // [2, 3]

Again, here ...must be at the end:

let [a , ...b , c] = [1, 2, 3]  // SyntaxError: Rest element must be last element
let { a, ...b, c } = { a: 1, b: 2, c: 3 } // SyntaxError: Rest element must be last element

Summarize:

What is elegance, less code is not necessarily elegant, elegance must ensure a certain degree of readability on the basis of simplicity. And readability is based on the team. If the team has a high level and has formed muscle memory for certain "implicit conversions", then it is not "implicit" for them and has readability.

And after mastering these basic knowledge enough, at least you can choose to be flexible according to the overall style of the team.

The above is the little knowledge about some operators in JavaScript, I hope it can be helpful to everyone.

 

Front-end interview question bank ( necessary for interview) recommendation: ★★★★★            

Address: front-end interview question bank

[National Day Avatar] - National Day patriotic programmer avatar! always one option fit for you!

Guess you like

Origin blog.csdn.net/weixin_42981560/article/details/132721933