[Pregunta de la entrevista] ¿Qué operadores de Javascript conoces?

 

Recomendación del banco de preguntas de la entrevista inicial ( necesario para la entrevista) : ★★★★★            

Dirección: banco de preguntas de la entrevista inicial

[Avatar del Día Nacional] - ¡Avatar del programador patriótico del Día Nacional! ¡Siempre hay una opción adecuada para ti!

tema: devui-blue resaltado: a11y-light

Ya sea JavaScript u otros lenguajes, los operadores son la base y pueden existir en expresiones y declaraciones. La siguiente es una lista de las funciones y escenarios de uso de algunos operadores en JavaScript que quizás no conozca.

+ operador de suma

Si es una operación unaria (también llamada operación unaria), es decir, un operando, se convertirá  implícitamente  a numberun tipo:

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

// better
+new Date() // 1681607509065

Si hay dos operandos, +los operandos de ambos lados se convertirán  implícitamente  primero al tipo de datos básico y se juzgarán en el siguiente orden:

  1. Si un lado es string, convierta el otro lado a string:
[1, 2, 3] + '' // '1,2,3'
  1. BigIntLa suma se realiza si ambos lados BigIntlo son, y si solo un lado lo es BigInt, se genera un error TypeErrorporque no se admiten operaciones BigIntunarias :+
10n + 20n; // → 30n
+ 10n // → TypeError: Cannot convert a BigInt value to a number
  1. De lo contrario, convierta ambos lados numberpara realizar una suma numérica:
let a = {
    valueOf: () => false
}
a + true // 1

** Operador de potencia (exponente)

** Es un nuevo operador de exponenciación en ES7, que puede reemplazar Math.pow():

Math.pow(2, 3) // 8

// better
2 ** 3 // 8

** Una característica del operador es la asociatividad por la derecha, en lugar de la habitual asociatividad por la izquierda. Cuando se utilizan varios operadores de exponenciación juntos, se cuentan desde el extremo derecho:

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

()La precedencia de las expresiones se puede controlar mediante los operadores de paréntesis :

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

?: operador condicional (ternario)

condition ? exprIfTrue : exprIfFalse

? :En juicios condicionales simples, se pueden utilizar operaciones ternarias if else:

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

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

Por supuesto, el operador condicional también se puede encadenar y también satisface la combinación correcta:

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

Nota: si la condición no es booleana se producirá una conversión implícita , si es un valor verdadero Truthy, se ejecutará 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('要发芽') // '要发芽'

Para agregar a Verdad y Falso:

Falso: false , 0, -0, 0n, "", null, undefined y NaN

Verdad:  Todo menos lo falso es verdad.

, el operador de coma

El operador de coma puede crear más de una expresión compuesta; toda la expresión compuesta se evalúa como el valor de la expresión situada más a la derecha :

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

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

Se utiliza más comúnmente para proporcionar múltiples argumentos en un bucle for:

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

% operador restante

El operador restante devuelve el resto de dividir el operando izquierdo por el operando derecho, con el signo del valor devuelto consistente con el signo del dividendo:

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

Se puede aplicar en algunos problemas de algoritmos:

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

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

?. operador de encadenamiento opcional

Sabemos que js arrojará un al leer la propiedad de nullo :undefinedTypeError

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

ES2020 Se agregó un operador de cadena opcional, que se puede usar en los casos anteriores y en retornos de cortocircuito undefined:

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

Encadenamiento opcional para llamadas a funciones :

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

También se puede utilizar con descriptores de acceso de propiedades de corchetes  y  acceso a elementos de matriz :

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

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

Tenga en cuenta que el operador de encadenamiento opcional no se puede utilizar para la asignación :

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

&& Operador Y lógico y || Operador O lógico

De izquierda a derecha, &&buscar Falsy||buscar Truthy, si se encuentra, devuelve el valor encontrado; de lo contrario, devuelve el siguiente:

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

Entonces ambos pertenecen al operador de cortocircuito :

&&Se puede utilizar como juicio de ejecución de la función:

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

||Se puede utilizar para establecer valores alternativos:

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

Los métodos de escritura anteriores juzgarán namesi se Falsydebe establecer su valor predeterminado, y el valor predeterminadoES6 de solo juzgará si es :undefined

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

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

Tenga en cuenta que &&la prioridad es mayor que ||:

1 || 1 && 0  // 1

Operador coalescente nulo

El operador coalescente nulo devuelve ??el operando derecho si y sólo si el operando izquierdo es nullOR .undefined

Como se mencionó anteriormente, el operador lógico u ||se puede utilizar para establecer valores alternativos, pero en realidad existen peligros ocultos:

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

El operador lógico OR devuelve el ||operando derecho Falsycuando el operando izquierdo es . Sin embargo 0, ''también pertenece a Falsy, pero en algunos escenarios en realidad quieren los resultados, como en el código anterior.

El operador coalescente nulo ??resuelve este problema:

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

?.A menudo se utiliza con el operador de encadenamiento opcional :

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

!! doble no operador

El operador lógico NOT !, que comprueba si el operando es verdadero o falso y Truthydevuelve si lo es false, y Falsydevuelve si lo es true. El operador de doble vuelo !!, sobre esta base, es negado, y su función es equivalente a Boolean():

Boolean('') // false

// or
!!'' // false

Aquí hay algunos operadores bit a bit.

Los operadores bit a bit tratan a los operandos como cadenas4byte(32bit) binarias . Realiza operaciones sobre esta base, pero finalmente devuelve un número decimal .

<< operador de desplazamiento a la izquierda y >> operador de desplazamiento a la derecha

x << n Convertirá   el bit a binario, luego  se desplazará y el bit fuera de x los  límites de la izquierda se descartará:32n

10 * 2³ // 80

// better
10 << 3 // 80

x >> n Se convertirá  x en  32 bits binarios y luego nse desplazará y los bits fuera de límites de la derecha se descartarán:

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

// better
a >> n

Esto se puede aplicar en la búsqueda binaria :

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
}

^ operador XOR bit a bit

Después de que el operador XOR bit a bit  ^ convierta los operandos de ambos lados en números binarios de 32 bits, compare cada bit uno por uno y 1regrese si solo hay uno 1:

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

Se puede utilizar para intercambiar dos valores:

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

El operador XOR ^satisface las tres propiedades siguientes:

  1. Operación XOR entre cualquier número y 0, el resultado sigue siendo el número original: �⊕0=�x⊕0=x
  2. XOR cualquier número consigo mismo, el resultado es 0: �⊕�=0x⊕x=0
  3. La operación XOR satisface las leyes conmutativa y asociativa: �⊕�⊕�=�⊕�⊕�=�⊕(�⊕�)=�⊕0=�x⊕y⊕x=y⊕x⊕x=y⊕( x ⊕x)=y⊕0=y

El siguiente es un problema algorítmico resuelto utilizando las tres propiedades anteriores :

Dada una  matriz de números enteros no vacía  , cada elemento aparece dos veces, excepto cierto elemento que aparece solo una vez. Encuentra el elemento que aparece solo una vez. (Tendrías que diseñar e implementar un algoritmo de tiempo lineal para resolver este problema que utiliza solo espacio adicional constante).

/**
 * @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

Además, el operador XOR se puede utilizar para operaciones sencillas de cifrado y descifrado. Por ejemplo, podemos XOR cada carácter de una cadena con una clave para obtener una cadena cifrada, y luego XOR la ​​cadena cifrada con la clave para obtener la cadena original:

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'

~ operador NOT bit a bit

El operador NOT bit a bit ~ convierte el operando en un entero con signo de 32 bits y luego invierte el bit a bit:

enfocar:

  • Los números almacenados en la computadora se almacenan en forma de código de complemento (en cuanto a por qué está involucrado el circuito, solo se puede sumar, no restar, por lo que el código inverso y el código de complemento están diseñados para almacenar números negativos)
  • El complemento y complemento de números positivos son iguales al código original.
  • El complemento de un número negativo es igual a la inversión del código original + 1

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

En resumen: cuando se realiza una operación NOT bit a bit,  x el resultado de la operación en cualquier número es  -(x + 1).

Por tanto, se puede utilizar un juicio ~alternativo :!== -1

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

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

Una última introducción útil...

... extensión

El carácter de extensión ...puede expandir la expresión de matriz o cadena en el nivel gramatical durante la llamada a función/construcción de matriz; también puede expandir la expresión de objeto en forma de clave-valor al construir un objeto literal.

expansión de objetos

Solo se copian las propiedades enumerables y propias del objeto de destino :

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: '张三'}

En el código anterior,  Object.create()_a se utilizará  como aobjeto prototipo, por lo que las _apropiedades que contiene no son sus propias propiedades ; al mismo tiempo, crea propiedades gratuitas para sí mismo , pero está configurado para que no sea enumerable. . Finalmente, la extensión se utiliza para realizar la clonación del objeto, y solo se clona esta propiedad propia y enumerable . Este es el mismo resultado que  Object.assign()  :nameamyNameageageamyName

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

expansión de matriz

Para la clonación (superficial) de matrices, para elementos de matriz de tipos de datos complejos solo se clonarán sus referencias:

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

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

Para concatenar matrices:

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]

para llamadas a funciones:

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

// better
fn(...args)

expansión de cuerdas

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

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

No se puede decir que se utilice para convertir matrices de clases en matrices.

Un objeto similar a una matriz es un objeto con una propiedad .length.

Array.from() crea una nueva copia superficial de la instancia de Array a partir de un objeto iterable o similar a una matriz . Cuando se usa la sintaxis extendida en matrices o parámetros de función , la sintaxis solo se puede usar con  objetos iterables :

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

Tal vez se pregunte, ¿ [...'123']no se utiliza también la sintaxis de expansión en la matriz, '123'sino el tipo de datos básico, cómo se puede iterar?

De hecho, el motor '123'lo envolverá en Stringun objeto y el método Stringse encapsula en el objeto 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}

...parámetros restantes

Si el último parámetro de la función ...tiene el prefijo , será una matriz verdadera de los argumentos restantes , y argumentos es una pseudomatriz:

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): ƒ]

Los parámetros de descanso ...se pueden desestructurar:

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

Los parámetros de descanso ...deben estar al final:

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

... atributos restantes

En la asignación de desestructuración, las propiedades restantes ...pueden obtener las propiedades restantes de la matriz u objeto y almacenarlas en una nueva matriz u objeto:

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]

De nuevo, aquí ...debe estar al final:

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

Resumir:

Qué es elegancia, menos código no es necesariamente elegante, la elegancia debe garantizar un cierto grado de legibilidad sobre la base de la simplicidad. Y la legibilidad se basa en el equipo: si el equipo tiene un alto nivel y ha formado memoria muscular para ciertas "conversiones implícitas", entonces no es "implícita" para ellos y tiene legibilidad.

Y después de dominar lo suficiente estos conocimientos básicos, al menos puedes optar por ser flexible según el estilo general del equipo.

Lo anterior es el poco conocimiento sobre algunos operadores en JavaScript, espero que pueda ser de ayuda para todos.

 

Recomendación del banco de preguntas de la entrevista inicial ( necesario para la entrevista) : ★★★★★            

Dirección: banco de preguntas de la entrevista inicial

[Avatar del Día Nacional] - ¡Avatar del programador patriótico del Día Nacional! ¡Siempre hay una opción adecuada para ti!

Supongo que te gusta

Origin blog.csdn.net/weixin_42981560/article/details/132721933
Recomendado
Clasificación