Recomendación del banco de preguntas de la entrevista inicial ( necesario para la entrevista) : ★★★★★
Dirección: banco de preguntas de la entrevista inicial
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 number
un 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:
- Si un lado es
string
, convierta el otro lado astring
:
[1, 2, 3] + '' // '1,2,3'
BigInt
La suma se realiza si ambos ladosBigInt
lo son, y si solo un lado lo esBigInt
, se genera un errorTypeError
porque no se admiten operacionesBigInt
unarias :+
10n + 20n; // → 30n
+ 10n // → TypeError: Cannot convert a BigInt value to a number
- De lo contrario, convierta ambos lados
number
para 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 null
o :undefined
TypeError
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 name
si se Falsy
debe 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 null
OR .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 Falsy
cuando 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 Truthy
devuelve si lo es false
, y Falsy
devuelve 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á:32
n
10 * 2³ // 80
// better
10 << 3 // 80
x >> n
Se convertirá x
en 32
bits binarios y luego n
se 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 1
regrese 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:
- Operación XOR entre cualquier número y 0, el resultado sigue siendo el número original: �⊕0=�x⊕0=x
- XOR cualquier número consigo mismo, el resultado es 0: �⊕�=0x⊕x=0
- 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 a
objeto prototipo, por lo que las _a
propiedades 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() :name
a
myName
age
age
a
myName
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 String
un objeto y el método String
se 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