分类 JavaScript 下的文章

日期的Date对象

创建一个日期的对象


let date = new Date();

console.log(date);  //Tue Mar 23 2021 10:10:51 GMT+0800 (中国标准时间)

let year = date.getFullYear();  // 获取年份
let mon = date.getMonth()+1;  // 获取月份,从0开始的,真实的月份是需要加一
let day = date.getDate();  // 获取日期(天)
console.log(year,mon,day)

let h = date.getHours();  // 获取小时
let m = date.getMinutes();  // 获取分钟
let s = date.getSeconds();  // 获取秒
console.log(h,m,s)

let week = date.getDay();  //获取星期(0 ~ 6),星期日 - 0
console.log(week)

补0函数封装


function add0(n){
    if(n<10){
        return '0'+n;
    }else{
        return ''+n;
    }
}

function add0(n){
    return n<10?'0'+n:''+n;
}

console.log(add0(15));  // 15
console.log(add0(5));  // 05


setTimeout 和 clearTimeout

setTimeout() 延时定时器,即多久时间之后去执行(一次性的)
语法:
主要包含两个参数,函数和单位为毫秒的数值。


// 一
setTimeout("function();",delaytime);

// 二
// 定义一个变量 (timerId) 用于保存 setTimeout() 这个定时器,以便使用 clearTimeout(timerId) 来取消。
let timerId;
timerId = setTimeout("function();",delaytime);

//----------------------------------

// 3秒后在console里打印一句1
function x(){
    console.log(1);
}
setTimeout(x,3000);

// 上面代码等效下面的代码

setTimeout(function (){
    // alert(1)
    console.log(1);
},3000);

并且可以使用 clearTimeout() 来取消执行 setTimeout()


clearTimeout(timerId );

setInterval 和 clearInterval

setInterval 间隔定时器,每隔一段时间就执行一次(重复执行)
语法:
setTimeout() 用法一样,区别仅在于一次性执行和重复执行,主要包含两个参数,函数和单位为毫秒的数值。


// 每个1秒打印会一个数,让i一直加1

setInterval(fn,1000)
var i = 0;
function fn(){
    i++;
    console.log(i)
}

使用clearInterval()来取消执行setInterval()

demo

点击移动div


<body>
    <button>停止</button>
    <div class="box"></div>
    <script>
       let box = document.querySelector('.box');
       let btn = document.querySelector('button');
       let num = 0;
       // 1.要结束一个定时器,就先声明一个变量(存定时器)
       let timer = null;

       box.onclick = function(){
            // 3.当多次执行时,先把上一次开着的定时器关掉,再往下执行开新的
            clearInterval(timer); //第一次执行时这还是个undefined,会自动忽略
            // 2.然后把(开)定时器里的内容存起来
            timer = setInterval(function(){
                num+=3;
                box.style.left = num+'px';
            },30);
       }

       btn.onclick = function(){
          clearInterval(timer);
       }
    </script>
</body>

定时器有多次执行或者使用setInterval()时一定要先关再开!!!否则很容易出现一些不可预料的情况。

DEMO展示

函数自执行


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        .box{
            width: 100px;
            height: 100px;
            background: red;
        }

        .box2{
            width: 100px;
            height: 100px;
            background: yellow;
        }
    </style>
</head>
<body>
    <div class="box" title="123"></div>
    <div class="box2"></div>
    <script>  
	
		var box = document.querySelector('.box');
		box.onclick = function(){
		    alert(box.title)
		}
		
		var box = document.querySelector('.box2');
		//鼠标移入
		box.onclick= function(){
		    alert(2);
		}
		
    </script>
</body>
</html>

工作中,也许两个事件出自不同的人,这时,就有可能出现重名,这避免的方法就是都使用作用域。


// 作用域
// 在函数内部,它作用域的概念就是局部的函数它只能调用局部作用域的变量
// 这时就可以把函数封装起来自执行 - 避免命名冲突

(function(){})();

// 这样这个var box就是局部变量了,就算外面有相同的命名,也不会影响到当前代码本身的逻辑
(function(){
var box = document.querySelector('.box');
box.onclick = function(){
    alert(box.title)
}

})();

(function(){
var box = document.querySelector('.box2');
//鼠标移入
box.onclick= function(){
    alert(2);
}

})();

// 原生js逻辑基本上就是采用这种方式去分离代码业务的

闭包题思考


    function fn(){
            var n = 0;
            function fn2(){
                n++;

                return n;
            }
            return fn2; //不加括号的函数返回的只是函数体
        }

        var fn3 = fn(); // 这里调用时相当于声明了一个 n 等于 0
        var num = fn3(); // 第二次执行时相当于 n++ 了,就等于 1 ,n++不是变量,所以调用时改变的是 var n的值
        var num2 = fn3();
        var num3 = fn3();

        console.log(num3) //3


    function fn(){
            var n = 0;
            function fn2(){
                n++;

                return n;
            }
            return fn2; //不加括号的函数返回的只是函数体
        }

        var fn3 = fn();
        var num = fn3();
        var num2 = fn3();
        var num3 = fn3();
        console.log(num3) //3


        var fn4 = fn(); // 这里调用时相当于又声明了一个新的 n 等于 0 ,影响的是fn4 这个函数
        var num4 = fn4();
        console.log(num4) //1

return


        function fn(){
            
            function a(){
                alert(1)

                // return 'lalala'; // 如果加了return且写了值,才不会返回undefined
            };
            
            // 局部函数在外部可以调用的原因是它加了return
            return a;
        }

        var n = fn(); // 把函数体存起来

        // 既然n是函数 就可以 n() 去执行
        console.log(n()) // 执行结果,弹出 1 ,然后打印 undefined ,打印undefined的原因是a这个函数里没有return,没return默认就返回undefined

        function a(n1){
            var b = 6;
            function c(n2){
                return n2*2;
            }
            return [c,arguments[0]-c(b)+b]; 
        }

        var n  = a(5)[1];

        console.log(n)

// ----------------------------

        function a(n1){  // 2.这时a(n1)就是a(5)
            var b = 6;
            function c(n2){
                return n2*2;
            }
            return [c,arguments[0]-c(b)+b]; //3. 这里返回的是一个数组,这时就看拿的是第几个数,a(5)[1] 可知要的是第一个,第0个的c不用去管他
            // arguments[0]-c(b)+b
            // arguments[0] 它是 函数a(n1)的不定参列表,第0个就是 n1 ,n1 为 5 
            // c(b) 子函数调用父函数变量 这时c(n2)的 n2 就是 6 ,里面 return n2*2就是return 6*2, 这时的c(b)就是 12
            // b 就是父函数里 var b 的值 6 
            // 5-12+6;
        }

        var n  = a(5)[1];  // 1.遇到函数,首先看在什么地方调用

        console.log(n) // -1

        function a(n1){
            var b = 6; //3. 这时,因为函数里也声明了b,这时返回出来的值同时影响了父级的局部变量 也把它变成了 b =12 
            function c(n2){
                b = n2*2; // 1. 6*2等于12后,赋值给了b
                return b; // 2. 这里返回的 b 就是 12 
            }

            // arguments[0] = 5;
            // c(6) = 12
            // b = 12
            return [c,arguments[0]-c(b)+b]; //5-12+12;
        }

        var n  = a(5)[1];

        console.log(n)  // 5


// 闭包 

// 函数套函数 子函数调用父函数的局部变量 - 闭包

function fn(){
    var a = 5;
    function fn2(){
        console.log(a);
    }

    fn2();
}

fn();

闭包能做什么

示例:点击不同的按钮打印不同的下标


<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>

<script>
    var btns = document.querySelectorAll('button');
		
    for(var i = 0;i<btns.length;i++){
        // 按选项卡那的思路的话,给个自定义属性把下标存起来,
        btns[i].index = i;
        btns[i].onclick = function(){
            console.log(this.index);
        }
    }
</script>

优化一:
循环过程中,可以把里面的代码封装成函数,然后循环里调用


for(var i = 0;i<btns.length;i++){
    tab();
}
// 这样写没太大区别,只是把它放外面了
function tab(){
    btns[i].index = i;
    btns[i].onclick = function(){
        console.log(this.index);
    }
}

如果不用声明自定义属性btns[i].index = i;存标签上了,而是用形参把它传进去


for(var i = 0;i<btns.length;i++){
    // 把i传进去
    tab(i);
}
// 然后tab这接收一个值,接收的这个值就是每次调用是i的值
function tab(index){
    // 这样就可以直接在这调用index
    btns[index].onclick = function(){
        // 这就直接使用index
        console.log(index);
    }
}

以上写法也是没问题的,上面index可以直接用的原因


// 因为这段代码里就有闭包的概念
// 函数套函数,
// function tab(index) 套 function(){}
// 子函数调用父函数的局部变量,就称之为闭包
// console.log(index) 里的 index 是调用的 function tab(index) 里的 index(局部变量)

// 如何实现i值的利用的(帮助解决掉局部的属性,下标的存储,不存储下标了也管用)

// 首先这里的循环的作用就是将里面的代码执行3次而已
for(var i = 0;i<btns.length;i++){
    tab(i);
}

// 言外之意就是这个函数体tab(i)有三个,并且会立即执行

// 闭包作用 可以存储局部变量值
function tab(index){
    btns[index].onclick = function(){
        console.log(index);
    }
}

// 解析循环过程
// tab(i),参数里定义了i,循环过程就相当于每次把i传入不同的函数里 


(function tab(index){ // 2. 参数传入后,这个index就代表0
    // 3. 这时这个局部变量在这个函数里就相当于写了个变量声明
    // var index = 0; 这时值就给固定死了

    // btns[index]就等于btns[0]
    btns[0].onclick = function(){
        console.log(0); // 局部函数调用父级作用域下的局部变量(var index = 0;)
    }
})(0) // 1. 第一次传入了0

(function tab(index){
    // var index = 1; 
    btns[index].onclick = function(){
        console.log(index);
    }
})(1) // 第二次传入了1

(function tab(index){
    // var index = 2; 
    btns[index].onclick = function(){
        console.log(index);
    }
})(2) // 第三次传入了2


// 类似选项卡就可以用这种方法去实现
for(var i = 0;i<btns.length;i++){
    tab(i);
}

// 闭包作用 可以存储局部变量值
function tab(index){
    btns[index].onclick = function(){
        console.log(index);
    }
}

// 简化
// tab(i)无非就是function tab(index){...}的自执行
// 去掉命名,简写成匿名函数,让它自执行
for(var i = 0;i<btns.length;i++){
    (function(index){
        btns[index].onclick = function(){
            console.log(index);
        }
    })(i) //这就把i传递进去
}

JS 预解析机制 (变量提升 Hoisting)

预解析:在当前作用域下,js运行之前,会把带有varfunction关键字声明的变量先声明,然后从上至下解析js语句



console.log(a);  //undefined

let a = 0;

console.log(a);  //0

// 预解析
// 会将页面中的js变量都前置声明!

// 变量声明
let a;

// 只声明了变量,没赋值,打印出来就是undefined
console.log(a);  //undefined

// 赋值变量
a = 0;

// ----------------------------

// 如果连声明都没有,就会报错
console.log(a);  //Uncaught ReferenceError: a is not defined

// let a = 0;



function fn(){
    console.log(1);
}

fn();  // 1

// 预解析
// 会将页面中的函数声明前置!

fn();  // 1

// 就算函数写到下面,它也会给前置了
function fn(){
    console.log(1);
}



fn();  // Uncaught TypeError: fn is not a function

let fn = function (){
    console.log(1);
}

fn();  // 1

// ----------------------------

// 函数声明 - 命名函数
// function fn(){

// }

// fn 变量 =  函数表达式
let fn = function (){
    console.log(1);
}

//它会理解为你声明了一个变量,只不过变量里面存的是函数而已

// 声明变量
var fn;

fn();

// 赋值
fn = function(){
    console.log(1);
}

作用域 (scope)


// 作用域  - 在特定的区域可以使用

// 函数 外面的变量 在里面随便用  - 全局变量 (可以在任何函数下调用)

let a = 12;

function fn(){
    console.log(a)
}

fn(); //12

// ----------------------------

// 函数 里面的变量 在外面不能用  - 局部变量 (只能在函数内部使用)

function fn(){
    let a =5;
    console.log(a);
}

fn();
console.log(a);  //Uncaught ReferenceError: a is not defined

var a =12;

function fn(){
    a = 5;
}

console.log(a); // 12

// ----------------------------

var a =12;

function fn(){
    // 没有var 就是赋值
    a = 5;
}

fn();

console.log(a); // 5

// ----------------------------

var a =12;

fn(); // 预解析

console.log(a); // 5

function fn(){
    a = 5;
}

// ----------------------------

var a =12;

console.log(a); // 12

fn();

function fn(){
    a = 5;
}

// ----------------------------

var a =12;

fn();

console.log(a); // 12

function fn(){
    var  a = 5;
}

// ----------------------------

var a =12;

function fn(a){
    // 形参声明过这个名称,函数内部这就是一个局部变量
    // 形参 -- 局部变量声明
    a = 5;

    return a;
}

console.log(fn()) //5

console.log(a); //12

多个作用域嵌套(作用域链)



// 定义的函数,看到调用后再去看函数内的代码  -- 追根溯源,找到函数触发的点,再去看函数发生了什么

function fn1(){
    var a = 12;
    
    // 函数内声明的函数称为局部函数
    function fn2(){
        var b = 5;
        return a+b;
    }
    return fn2();
}


console.log(fn1()); // 17


// 函数内查找变量时 - 顺序 
// 先从自身作用域下查找 - 如果没有就会从父级作用域下找 - 如果父级也没有 还会往上找
// 由内向外 - 一层一层 - 直到找到window下面
// 反之 不能调用局部变量!(内层作用域能访问外层作用域,而外层不能访问内层。)

var c = 1;
function fn1(){
    var a = 12;
    
    // 局部函数
    function fn2(){
        var b = 5;

        return a+b+c;
    }
    
    // b是fn2的局部变量,它只能在fn2的函数内去调用
    // console.log(b);

    return fn2();
}

console.log(fn1()); // 18