奇怪的代码!

135 阅读4分钟

奇怪的代码

总结一下曾经遇到的"奇怪"的代码

变量提升

var b
function b(){}
console.log(b)
// function b(){}

NC 问题

console.log(typeof undefined == typeof NULL) // true 
console.log(typeof function () {} == typeof class {}) // true

加法问题

1 + '1' = 11
1 + undefined = NaN
1 + NaN = NaN
1 + null = 1
1 + [] = 1
1 + {} = 1[object Object]
[] + {} = [object Object]
1 + true = 2
1 + false = 1

for 循环的异步

async function sleepNext () {
    for(let x = 0; x < 5; x++) {
        await new Promise((resolve) => {
            setTimeout(() => {
                console.log(x)
                resolve(true)
            }, 1000)
        })
    }
}
sleepNext()
// 0
// 1
// 2
// 3
// 4

a变量赋值问题

console.log(a); // undefined
var a = 0;
console.log(a) // 0
if (true) {
    console.log(a) // function a() {return '123'} 
    function a() {return '123'} 
    console.log(a) // function a() {return '123'} 
    a = 1;
    console.log(a) // 1
    a = 21;
    console.log(a) // 21
}
console.log(a);  // function a() {return '123'}

// 据说每个浏览器不同的版本返回的不一样 这是 chrome

var x = [typeof x, typeof y]

var x = [typeof x, typeof y]
// ['undefined', 'undefined']

async await 中 await 在等什么?

function simpleEvent() {
    return "simple";
}
async function asyncEvent() {
    return Promise.resolve("async event");
}
async function test() {
    const v1 = await simpleEvent();
    const v2 = await asyncEvent();
    console.log(v1);
    console.log(v2)
}
test();
// simple
// async event

当返回值不是Promise的话async会阻止同层之后的代码运行,如果不是的话就相当于没有。

indexOf、includes、map、find、forEach

const l = [1, NaN,,];
l.indexOf(1); // 0
l.indexOf(NaN); // -1
l.indexOf(void 0); // -1
l.includes(1); // true
l.includes(NaN); // true
l.includes(void 0); // true
l.find((item, index) => { console.log(index)}) // 0 1 2 
l.map((item, index) => { console.log(index)  }) // 0 1
l.forEach((item, index) => { console.log(index)  }) // 0 1

可以停不下的循环

function createForLoop() {
    var list = [1];
    var _index = 1;
    for (let index = 0; index < list.length; index++) {
        console.log(list[index])
        _index++;
        if (_index < 100) {
            list.push(_index)
        }
    }
}
// 可以 (do while 也可以)
function create() {
    var list = [1];
    var _index = 1;
    for (let item in list) {
        console.log(item)
        _index++;
        if (_index < 100) {
            list.push(_index)
        }
    }
}
// 不可以
function createForEachLoop() {
    var list = [1];
    var _index = 1;
    list.forEach((item, index) => {
        console.log(list[index])
        _index++;
        if (_index < 100) {
            list.push(_index)
        }
    })
}
// 不可以
function createMapLoop() {
    var list = [1];
    var _index = 1;
    list.map((item, index) => {
        console.log(list[index])
        _index++;
        if (_index < 100) {
            list.push(_index)
        }
    })
}

由此可知那些方法会有数组塌陷的风险,针对塌陷倒着触发也是一种好方法。

try...catch不能异步捕获代码错误?

try catch 可以捕获到同步代码的错误但是针对异步代码😮‍💨。

try {
    setTimeout(() => {
        // 异步操作中的代码
        throw new Error('异步错误');
    }, 1000);
} catch (error) {
    console.error('捕获到错误:', error.message);
}
// 捕获失败

const asyncErrorFunction = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error('异步错误'));
        }, 1000);
    });
};
asyncErrorFunction()
.catch(error => {
    console.log('捕获到错误:', error.message);
});
// 捕获成功

try {
  Promise.resolve().then(() => {
    throw new Error('err')
  })
} catch (err) {
  console.log(err);
}
// 捕获失败

try {
    await Promise.resolve().then(() => {
      throw new Error('err');
    });
} catch (err) {
    console.log(err.message);
}
// 捕获成功

Symbol.key(1) 和 Symbol(1)

const mp = new WeakMap();
mp.set(Symbol(1), 1); // 可以
mp.set(Symbol.key(1), 1); // 不可以
// 对于WeakSet同样
// WeakMap key(弱键)只能为对象, Symbol.for(1) 其实是注册在全局下的Symbol对应的一个原始值

(,)和=号情况下的this问题

var out = 25
var inner = {
  out: 20,
  func: function () {
    var out = 30
    return this.out
  }
};
console.log((inner.func, inner.func)())
console.log(inner.func())
console.log((inner.func)())
console.log((inner.func = inner.func)())
// ,赋值会取最后一个的值本身,“值”在全局变量下this指向window
// (inner.func)() 和 inner.func() 一样本身函数调用指向自己
// 赋值表达式和逗号表达式相似,都是返回的值本身,所以也相对于在全局环境下调用函数

赋值

// 第一种
let obj = { num1: 111 };
obj.child = obj = { num2: 222 };
console.log(obj.child); // 输出? undefined 
// 第二种
let obj = { num1: 111 }, ref = obj; 
obj.child = obj = { num2: 222 };
console.log(obj.child); // 输出? { num1: 111 }

var [ a, b ] = { a:1, b:2 }; (负责人发飙代码)

const a = {a:1,b:2};
Object.prototype[Symbol.iterator] = function() {
    // 简单写法
    return Object.values(this)[Symbol.iterator]();
    // 麻烦写法但是很直观 😓
    // let index = 0;
    // const keys = Object.keys(this);
    // return {
    //    next() {
    //        if (index < keys.length)
    //        { 
    //            return {done: false, value: obj[keys[index++]]}
    //        }
    //        return { done:true,value:undefined}
    //    } 
    // }
}
const [c, d] = a;

事件循环-空不下来的宏队列(😳)

var a = true;
setTimeout(function(){
    a = false;
}, 100)
while(a){
    console.log('while执行了')
}
// 请勿尝试 😳

自执行代码(太多了看不过来),搞这么多花样也没啥用原理都一样。

(function(){;}());
(function(){;})();
[function(){;}()];
~function(){;}();
!function(){;}();
+function(){;}();
-function(){;}();
delete function(){;}();
typeof function(){;}();
void function(){;}();
new function(){;}();
new function(){;};
var f=function(){;}();
1,function(){;}();
1^function(){;}();
1>function(){;}();

[] == ![]?

[] == ![] // true

++[[]][+[]]+[+[]] == '10'
// Number([].valueOf()) 为 0
// [[]][+[]] --> ++[[]][0] ---> ++[] ---> 1
// [+[]] --> [0]
// 1 + [0] = '10'

计算无限或判断+0和-0

1/0 = Infinity
1/-0 = -Infinity

取整数

const a = 123.567;
a >> 0;
~~a;
x|0;
Math.floor(x);

a == 1 && a == 2 && a == 3 (脑残代码)

// 第一种
var a = Object.create(null);
a['value'] = 1;
a.toString = function() {
    return this.value++;
}
a == 1 && a == 2 && a == 3;
// 第二种
var b = Object.create(null);
b['value'] = 1;
b[Symbol.toPrimitive] = function() {
    return this.value++;
}
b == 1 && b == 2 && b == 3;

加法

0.1 + 0.2 = ? // 0.0.30000000000000004
// 二进制的精度问题

赋值

var name = 1;
function name() {
    name = 2;
    console.log(name);
}
name();
console.log(name);
// 变量提升 1
// 函数提升 2
// name --> void 0
// name --> Function 赋值
// name --> 1 赋值
// 执行name() 报错 name 是 1 不是函数

创建一个函数生成器

// bind处理
function createGenerate() {
   const callBack = {
        a: 1,
        end: false
   }
   const b = (function* fn() {
        while (!this.end) {
            this.a++;
            console.log(this.a);
            yield;
        }
   }).bind(callBack)()
   callBack['b'] = b
   return callBack
}
const B = createGenerate();
B.n.next();

// 对象处理
function createGenerate() {
   const callBack = {
        a: 1,
        end: false
   }
   callBack['#b'] =function* () {
         while (!this.end) {
            this.a++;
            console.log(this.a);
            yield this.a;
        }
   }
   callBack['b'] = callBack['#b']()
   return callBack
}