JavaScript碎知识总结

for循环中放定时器造成的异步问题

	//问题复现
	for (var i = 0; i < 5; i++) {
	    setTimeout(function() {
	        	console.log(i);
	    }, 1000);
	}
	console.log(i)
	
	//实际输出
	5->5 5 5 5 5 //->代表间隔了1s
  • 如果我们期待的输出是5 -.> 0,1,2,3,4 有几种改写方式呢?

    //第一种、使用闭包中的IIFE(立即执行函数)
    for (var i = 0; i < 5; i++) {
        (function(j){
    	    setTimeout(function() {
    	        	console.log(i);
    	    }, 1000);
    	})(i);
    }
    console.log(i)	
    
    //第二种、用setTimeOut的参数 
    for (var i = 0; i < 5; i++) {
    	setTimeout(function() {
    	        console.log(i);
    	}, 1000,i);
    }
    console.log(i)	
    
    //第三种、利用js中函数的传参是按值传递(把for和setTimeOut分离,将循环的值传进一个带定时器的函数)
    function output(i){
    	setTimeout(function() {
    	        console.log(i);
    	}, 1000,i);
    }
    for(var i=0;i<5;i++){
    	output(i)
    }
    console.log(i)	
    
    //第四种、利用es6中的let
    for (let i = 0; i < 5; i++) {
        (function(j){
    	    setTimeout(function() {
    	        	console.log(i);
    	    }, 1000);
    	})(i);
    }
    console.log(i)	//这里i要报错,因为i改为块级作用域,所以全局作用域不存在一个i
    
    
  • 如果我们期待的输出是0->1->2->3->4->5,又该如何改写呢?

    //方法一、暴力改写法,定时器改成逐渐递增1s的
    for (var i = 0; i < 5; i++) {
        (function(j) {
            setTimeout(function() {
                console.log(j);
            }, 1000 * j);  // 这里修改 0~4 的定时器时间
        })(i);
    }
    
    setTimeout(function() { // 这里增加定时器,超时设置为 5 秒
        console.log(i);
    }, 1000 * i);
    
    //方法二、promise+es6改写 (在所有异步操作都结束后再进行一个操作)
    let arr = []
    let output = (i)=>new Promise((resolve,reject)=>{
    	setTimeout((i)=>{
    		console.log(i)
    		resolve()
    	},1000*i)
    })
    for(var i=0;i<5;i++){
    	arr.push(output(i))
    }
    Promise.all(arr).then(()=>{
    	setTimeout(()=>{
    		console.log(i)
    	},1000)
    })
    
    //方法三、手写一个sleep函数,利用async和await
    // 模拟其他语言中的 sleep,实际上可以是任何异步操作
    const sleep = (timeountMS) => new Promise((resolve) => {
        setTimeout(resolve, timeountMS);
    });
    
    (async () => {  // 声明即执行的 async 函数表达式
        for (var i = 0; i < 5; i++) {
            if (i > 0) {
                await sleep(1000);
            }
            console.log(new Date, i);
        }
    
        await sleep(1000);
        console.log(new Date, i);
    })();
    

几种手写sleep函数,以及可能遇到的问题


手写new函数(还可以继续更新)

目标有三:
1.获取原型中的属性
2.获取构造函数的私有属性
3.根据构造函数返回值的差异设置实例的返回值

Function.prototype.new = (cons,...args)=>{
	if(typeof cons!= 'Function'){
		throw 'this new function the first param must be a function'
	}
	let obj = Object.create(cons.prototype)
	let res = cons.apply(obj,args)
	if((typeof res==='Object'&& typeof res!=='null')||typeof res==='Function'){
		return res
	}
	return obj
}

手写apply和call

目标有三
1.将函数放进新的目标this对象中
2.执行他
3.删除它

Function.prototype.call = function(context,...args){
	var context = context||window
	context.fn = this
	let res = context.fn(...args)
	delete context.fn
	return res
}


Function.prototype.apply = function(context,args){
	var context = context||window
	context.fn = this
	let res = context.fn(...args)
	delete context.fn
	return res
}

使用es6的解构语法,apply和call的区别只在传参的处理:…args/args


手写bind

目标有许多
1.返回一个函数
2.这个函数也可以作为构造函数,所以this指向也要相应的更改
3.构造函数和bind函数的传参要叠加在一起使用

Function.prototype.bind = function(context,...args){
	if(typeof this != 'Function'){
		throw new Error('Function.prototype.bind - what is trying to be bound is not callable')
	}
	var self = this
	var fun =function(...arr){
		self.apply(this instanceof self?this:context,[...args,...arr])
	}
	fun.prototype = Object.create(self.prototype)
	return fun
}

new object()和object.create()的区别

在这里插入图片描述

new Object() 通过构造函数来创建对象, 添加的属性是在自身实例下。
Object.create() 创建对象的另一种方式,可以理解为继承一个对象, 添加的属性是在原型下。

使用到这个知识点的地方:

  • 最优的继承方案:寄生式组合继承

      function Parent5 () {
        this.name = 'parent5';
        this.play = [1, 2, 3];
      }
      function Child5() {
        Parent5.call(this);
        this.type = 'child5';
      }
      Child5.prototype = Object.create(Parent5.prototype);
      Child5.prototype.constructor = Child5;
    
  • 手写new 详见上文

  • 手写bind 详见上文


类数组转普通数组的方法

  • [].slice.call(arguments)
  • Array.from()
  • [].concat.apply([],arguments)
  • […arguments]

js数组判断是否包含某一值

  • arr.indexOf() 返回索引
  • arr.includes() 返回布尔值
  • arr.find(callback) 返回符合条件的第一个值
  • arr.findIndex(callback) 返回符合条件的第一个值的下标

数组扁平化

  • arr.flat(Infinite)
  • JSON.Stringfy(arr).replace('/(\ [ | \ ] )/g','').split(',')
  • JSON.parse('[' + JSON.Stringfy(arr).replace('/(\ [ | \ ] )/g','') +']')
  • while(arr.some(Array.isArray)){
    	arr = [].concat( ...arr );	
       }
    
  • let result = [ ];
    let fn = function(arr){
    	for(let i =0;i<arr.length;i++){
    		if(Array.isArray(arr[i])){
    		fn(arr[i])
    		}
    		else{
    			result.push(arr[i])
    		}
    	}
    }
    

手写promise

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值