2021年3月

JavaScript是一门弱语言,不像C或者Java等那种强类型语言,用一个变量,还要先定义数据类型,定义成了int整型,就不能放字符串进去。

JavaScript定义的变量,就是你先放了数字进去,它就变成了数字类型,后面改放了字符串进去,也就变了字符串类型。

所以,在进行一些运算的时候,虽然灵活,但也会出毛病,这也是它的弱点。

JS中的数据类型:

1. Number
2. String
3. Boolean
4. undefined
5. Symbol
6. Object
7. null
8. function

除了基本类型以外(Number,String,Boolean,undefined ,Symbol )
其他的都是对象(Object,null,function)


var numa = 18;           // number 数字类型
var stra = 'abc';        // string 字符串
var boola = true;         // boolean  布尔值,两个值  true  false
var a ;              // undefined 未定义
var sya = Symbol ();    //Symbol 类型
var b = document      // object 对象 
var c = null          // object 对象(空对象)
var funa = function(){}  // function 函数

在使用js的时候一定要注意,记清楚每一个变量装什么类型的东西。
比如匈牙利命名法:
数字 | number | n/num | nAge
字符串 | string | s/str | sName strPassword
布尔 | booleans | b/bool | bLogin
对象 | object | o/obj | oUser
函数 | function | fu/func | fuSuccess

获取检测变量的数据类型:

typeof可用来获取检测变量的数据类型,它是一个关键字,不是函数

typeof运算符查看它们的数据类型:不同类型的返回值:numberstringbooleanfunctionundefinedsymbolobject


typeof 18 -> number
typeof "abc" -> string
typeof true -> boolean
typeof undefined -> undefined
typeof null -> object  //返回的是Object类型

字面量:通俗来说,就是字面量表示如何表达这个值。123、"abc"、true
变量:容器,存储的值可以变的 存东西,可以改
常量:容器,存储的值是不可变的 存东西,不可改

数据类型转换

通俗来说,就是把一种数据类型的变量转换成另一种数据类型

显式类型转换(强制):

转换为数字型 Number()
Number() 注:首字母大写

  • Number(val) 将数据转换成数字
  • - 字符串类型,使用 Number() 转换时,规则如下:
    1. 1.当整段字符串都符合数字规则时,转换为数字返回
    2. 2.空字符串,直接返回 0
    3. 3.其余情况,直接返回 NaN
  • - 布尔值类型,使用 Number() 转换时,true 返回 1,false 返回 0
  • - null,使用 Number() 转换时 返回 0
  • - undefined,使用 Number() 转换时 返回 NaN
  • - 对象类型,使用 Number() 转换时,调用的对象的toString()方法,然后再次依照前面字符串的转换规则进行转换

console.log(Number('12'));
//  console.log(Number('12')); ==>  12 

// Number它只能转行纯数字的字符串 否则返回NaN
var num = '123.4a';
console.log(typeof num)  // string
       
var num2 = Number(num);
console.log(num2)  //NaN
console.log(typeof num2) //number 

转换为字符串类型 String()
- 数字类型,直接转换数据类型原样返回
- undefined ,直接返回字符串 undefined
- null,直接返回字符串 null
- 布尔值,直接返回字符串 true 或者 false
- 函数,直接把整个函数变成字符串 返回
- 对象,直接调用对象的 toString 方法


        var num = 123;
        var nud = undefined ;
        var nul = null ;
        var bool = true ;
        var fn = function(){} ;
        var obj = {a:12} ;

        console.log(String(num))   // 123
        console.log(String(nud))   // undefined
        console.log(String(nul))   // null 
        console.log(String(bool))  // true 
        console.log(String(fn))    // function (){}
        console.log(String(obj))   // toString([object Object])

转换为布尔型 Boolean()
- 数字类型:非零的合法数字转换为 true, 零代表 false, NaN 代表 false
- 字符串类型:空字符串转换为false,非空字符串转换为true
- null:转换为false
- 对象:转换为true



var str = ' ';
var num = -0.1;
var arr = [];
var nul = null;

console.log(Boolean(num)); // true
console.log(Boolean(str)); // true
console.log('arr',Boolean(arr)); //arr true
console.log('null',Boolean(nul)); arr true

if(12){
  console.log('真');
}else{
  console.log('假');
}

// 什么是真(true),什么是假( false) -- 有东西就是真,没东西就是假
// 真(true):非零(正负数)、非空字符串、非空对象
// 假( false):零、空字符串、空对象( 0、''、null、undefined  )

隐式类型转换(能不用就尽量别用):

这是存在一定风险的(出现一些小问题什么的),虽然是比较方便的方法,
但如果想要代码严谨一点,不要依赖隐式转换,而是要消除所有存在的隐式转换。
如果是长期使用的,比如一个库什么的,这时就要避免所有存在的隐式操作了,


+    //变字符串
- * / %   //     变数字
==  ===     //  转成布尔值



var a='12';
var b='3';

// + 号有两重含义,数字相加和字符串连接
console.log(a+b);
//  '12' + '3' ==>  ‘123’  变字符串

// - 号就只是存在于数字相减,不存在字符串相减,所以变数字
console.log(a-b);
//  '12' - '3' ==> 9   变数字

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

var a=12;
var b='12';

// == 带有隐式转换,会先转换成一样的类型再进行比较
console.log(a==b);
// a==b   ==>  true

// === 直接比较
console.log(a===b);
// a===b    ==>   false

NaN 和 isNaN

在使用 NaN 时,要注意 NaN是个特殊的数字,它不等于任何值(包括它自己),也就是 NaN 不等于 NaN。

当我们要检测一条数据是否是 NaN 时,可以使用 isNaN(val) 来进行检测, 在 isNaN 方法中,传入的数据 能被转换成 合法数字时,就会返回 false,当传入的数据不能被转换成 合法数字( 也就是NaN) 时,isNaN 就会返回 true



var str = '123.a';

console.log(str)  // 123.a
console.log(isNaN(Number(str))) // true
// isNaN 是一个NaN 返回 true 、反之 就是false

var a = NaN;
if(a == NaN){
    console.log('等于')  // NaN 不等于NaN 
}  

工具函数

1.三种转换成字符串的方式

toString()String() 一般情况下没什么大的区别,用谁都行。唯一不同的是toString()本质上是一个方法,当用在某些特殊的值上时区别就出来了

String() 转换成字符串

toString()转换成字符串

+''和字符串拼接的结果都是字符串(隐式转换了)


var a=12;
console.log(a,String());  // 12 ""
console.log(a,a.toString());  //12 "12"
console.log(a,a+'');  // 12 "12"  
// a+'' ==> String(a)+''  ==>  "12" 

2.转换成数字

parseInt将string类型转换成整数

parseFloat将string类型转换成浮点数(小数)

注意大小写


// 取整
var num = parseInt(12.345);
console.log(num) //12

// 获取浮点数(保留小数) - 将字符串转成数字
var num = '123.4';
console.log(typeof num)  //string
       
var num2 = parseFloat(num);
console.log(num2)  //123.4
console.log(typeof num2)  //number



<body>
    <div class="wrap">
        <nav id="nav">
            <a href="javascript:;" class="active">我的行程</a>
            <a href="javascript:;">消息中心</a>
            <a href="javascript:;">角色管理</a>
            <a href="javascript:;">定时任务补偿</a>
        </nav>
        <div class="bords">
            <div class="active">我的行程</div>
            <div>消息中心</div>
            <div>角色管理</div>
            <div>定时任务补偿</div>
        </div>
    </div>
</body>

首先给nav栏的a设置成单选


        let oNavs = document.querySelectorAll('#nav a');
        let oBoxs = document.querySelectorAll('.bords div');

        // 操作一组元素时,先用循环把它遍历出来
        for (let i = 0; i < oNavs.length; i++) {
            // nav栏的设置成单选,先全部清空,在给点击的设置
            oNavs[i].onclick = function() {
                for (let j = 0; j < oNavs.length; j++) {
                    oNavs[j].classList.remove('active');
                }
                // 这里的this指的就是当前点击着的li
                this.classList.add('active');
            }

然后给下面div设置显示隐藏时有个小技巧,<nav id="nav"><div class="bords">里都是四个子元素,且是上面第一个对应下面第一个的显示,以此类推,可以发现它们的数字下标是统一的。
如果变量声明用的是 let,可以直接使用 oBoxs[i],利用它们的共同点下标是相同的直接操作


        for (let i = 0; i < oNavs.length; i++) {
            oNavs[i].onclick = function() {
                for (let j = 0; j < oNavs.length; j++) {
                    oNavs[j].classList.remove('active');
                    // 这里给div清空时,可以借着上面a标签清空时的这个循环给它清空

                    // 因为for循环不在乎你循环的是谁,它在乎的是循环几次,
                    // 不要认为它循环的是元素或对象,它循环的是一个数值,数字而已
                    oBoxs[j].classList.remove('active');
                }
                this.classList.add('active');
                // console.log(i);
                oBoxs[i].classList.add('active');
            }
        }

DEMO展示

但如果变量声明使用的是var,这里不要直接在点击事件里操作oBoxs[i]


        var oNavs = document.querySelectorAll('#nav a');
        var oBoxs = document.querySelectorAll('.bords div');

        for (var i = 0; i < oNavs.length; i++) {
            oNavs[i].onclick = function() {
                for (var j = 0; j < oNavs.length; j++) {
                    oNavs[j].classList.remove('active');
                }
                this.classList.add('active');
                console.log(i);
                // 4
            }
        }

此时的i,无论点击那个,显示的都是4,是因为此时的i在第一层for循环时,已经循环4次++完了,所以在点击时显示的是一个加完之后的值,i是直接用不了的。而oNavs[i].onclick里的i所处的位置正好在for循环当中,for循环在直接到oNavs[i].onclick时,后面的函数在没点击之前是不会往里读取去触发的,只会告诉你在点击时是会执行这个函数的,具体函数里面是什么,你没点时我也不知道。

这时就可以换个思路,i在for循环里循环时是正常的,这样就可以给oNavs[i]每一个<a>添加一个属性


        var oNavs = document.querySelectorAll('#nav a');
        var oBoxs = document.querySelectorAll('.bords div');

        for (var i = 0; i < oNavs.length; i++) {
            // 
            oNavs[i].title = i;
            oNavs[i].onclick = function() {
                ......
            }
        }

加完之后可以看到每个a标签就都有一个title标签了,数字也是0123,这样可以理解为每一个a都有自己对应的下标了。
既然有下标,就不用再在里面去获取i了,直接用oBoxs[this.title]去代替了,这里的this.title也就是被点击时的a标签的title


        var oNavs = document.querySelectorAll('#nav a');
        var oBoxs = document.querySelectorAll('.bords div');

        for (var i = 0; i < oNavs.length; i++) {
            // 添加一个属性
            oNavs[i].title = i;
            oNavs[i].onclick = function() {
                for (var j = 0; j < oNavs.length; j++) {
                    oNavs[j].classList.remove('active');
                    oBoxs[j].classList.remove('active');
                }
                this.classList.add('active');
                // console.log(i);
                // oBoxs[i].classList.add('active');

                // 打印获取一下this.title的值
                console.log(this.title);
                // 直接用oBoxs[this.title]去操作
                oBoxs[this.title].classList.add('active');

            }
        }

DEMO展示

变量声明

var 老的(逐渐淘汰)

let (推荐)

const 常量
var存在的问题:
1.允许变量重复声明
2.不限制修改
3.不支持块级作用域 – 函数级
let const 的优点:
1.不允许变量重复声明
2.const可以限制修改
3.支持块级作用域 – {}

块级作用域好处:
1.不容易重名
2.每个代码块都有自己的变量副本(这点对普通的if之类的影响不大,但对循环里影响特别大)

for循环里用var声明



<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <button type="button">aaa</button>
    <button type="button">bbb</button>
    <button type="button">ccc</button>
    <script>
        let aBtn = document.querySelectorAll('button');

        for (var i = 0; i < aBtn.length; i++) {
            aBtn[i].onclick = function() {
                alert(i);
            }
        }
    </script>
    <!-- 
        {
            var i=0;
            aBtn[i].onclick = function() {
                alert(i);  // 3
            };
        }
        {
            var i=1;
            aBtn[i].onclick = function() {
                alert(i);  // 3
            };
        }
        {
            var i=2;
            aBtn[i].onclick = function() {
                alert(i);  // 3
            };
        }

        在这个循环里i 只有一个
        因为var是不带块级作用域的,所以就只有一个副本
        换句话说就是在循环过程中i都是同一个,如果其中一个变了,其他的都会变,跟着受影响

    -->

</body>

</html>

for循环里用let声明


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <button type="button">aaa</button>
    <button type="button">bbb</button>
    <button type="button">ccc</button>
    <script>
        let aBtn = document.querySelectorAll('button');

        for (let i = 0; i < aBtn.length; i++) {
            aBtn[i].onclick = function() {
                alert(i);
            }
        }
    </script>
    <!-- 
        {
            let i=0;
            aBtn[i].onclick = function() {
                alert(i);  // 0
            };
        }
        {
            let i=1;
            aBtn[i].onclick = function() {
                alert(i);  // 1
            };
        }
        {
            let i=2;
            aBtn[i].onclick = function() {
                alert(i);  // 2
            };
        }

        let就不一样了,它是一个块级作用域,每个代码块都有自己的变量副本。for也是一个代码块,for本身也在这个代码块当中
        在这个循环里i 一共有三个,且这些i都是完全互相不打扰的,任何一个i变了,其他的不会跟着变

    -->

</body>

</html>

变量作用域(scope)

全局

在所有函数之外声明的 – 可以在任何地方使用 (不推荐)
全局变量在任何地方都可以使用,之所以非常危险,是因为任何人都可以修改,也容易重名



let a=12;
function show(){
    alert(a);
}
show();
console.log(a);

局部

声明在函数内的变量叫做‘局部变量’ – 只能在函数内部使用



function show(){
    let a=12;
    
    alert(a);
};
show();

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

块级

if{} for{} function{} ...都是块级作用域
类似局部作用域,只不过在一定程度上分的更细了


<div id="box" class="text">使用classlist属性设置class属性</div>

使用元素的classList属性可以访问或者添加删除修改元素的class属性

element.classList

使用classList属性访问class属性


let oDiv = document.querySelector('#box');
console.log(oDiv.classList);
// DOMTokenList ["text", value: "text"]

element.classList.add()

通过classList调用add()的方法可以添加一个或者多个class属性,多个用,隔开


// 添加fonts一个class属性
oDiv.classList.add('fonts');
// 同时添加fonts和red两个class属性
oDiv.classList.add('fonts', 'red');

element.classList.remove()

remove()移除,移除一个或者多个class属性,多个用,隔开


// 删除fonts一个class属性
oDiv.classList.remove('fonts');
// 点击删除fonts和red两个class属性
oDiv.onclick = function() {
    this.classList.remove('fonts', 'red');
}

element.classList.toggle()

在元素中切换类名。
toggle()中的第一个参数必须参数,当元素中存在该指定的class属性时,将移除该class属性,反之就添加。
第二个参数为强制添加(参数为true时)或移除(参数为false时)第一个参数指定的class属性。


oDiv.classList.add('red');
oDiv.onclick = function() {
    // 切换class
    this.classList.toggle('fonts');
}

 // 强制移除一个class为fonts的属性 
oDiv.classList.toggle("fonts", false);
// 强制添加一个class为red的属性 
oDiv.classList.toggle("red", true);

element.classList.contains()

检测元素是否包含某个class 返回布尔值


// 检测元素是否包含类名为 e 的这个属性
let bool = oDiv.classList.contains('e');
console.log(bool);
// false

// 检测元素是否包含类名为 text 的这个属性
let bool = oDiv.classList.contains('text');
console.log(bool);
// true

模拟单选


<body>
    <div class="wrap">
        <h2>模拟单选</h2>
        <div class="option">
            <a href="javascript:;" class="checked">男</a>
            <a href="javascript:;">女</a>
            <a href="javascript:;">保密</a>
        </div>
    </div>
    <script>
        // 通过css选择器获取div中的所有a元素,返回一个类数组
        let oBtns = document.querySelectorAll('.option a');

        // console.log(oBtns.length);
        // 
        for (let i = 0; i < oBtns.length; i++) {
            // console.log(i);

            // oBtns获取的是一组a的类数组,既然是伪数组,就可以使用下标去获取某一个值
            // 使用循环的数值,从0开始的 i 值,每一次拿到的都是不同的a,不同的添加事件
            oBtns[i].onclick = function() {
                // 每次点击时先消除其他元素上的class
                for (let j = 0; j < oBtns.length; j++) {
                    oBtns[j].classList.remove('checked');
                }
                // 然后给点击的元素添加上class
                this.classList.add('checked');
            }
        }
    </script>
</body>

DEMO展示

模拟复选


<body>
    <div class="wrap">
        <h2>模拟复选</h2>
        <div class="option">
            <a href="javascript:;" class="checked">油桃</a>
            <a href="javascript:;">菠萝</a>
            <a href="javascript:;">葡萄</a>
        </div>
    </div>
    <script>
        let oBtns = document.querySelectorAll('.option a');

        // console.log(oBtns.length);
        for (let i = 0; i < oBtns.length; i++) {
            oBtns[i].onclick = function() {
                this.classList.toggle('checked');
            }
        }
    </script>
</body>

DEMO展示


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <div id="box" class="box1">
        <a href="#">html</a>
        <a href="#">css</a>
        <a href="#">javascript</a>
    </div>
</body>

</html>

getElementById

通过id去获取元素


document.getElementById('box')

querySelector

可以使用它们的 id, , 类型, 属性, 属性值等来选取元素


// 使用id去选中
document.querySelector('#box')

// 使用class去选中
document.querySelector('.box1')

// 使用元素去选中
document.querySelector('div')

// 使用父子元素去选中的写法
document.querySelector('body div')
// 使用父子元素去选中div下的a元素时,querySelector只返回匹配的第一个元素
document.querySelector('.box1 a')

querySelectorAll

document.querySelectorAll()方法返回文档中与指定的CSS选择器或者标签等匹配的所有元素


// 获取页面中所有的 <a> 元素
document.querySelectorAll('a');

// 获取id为box元素下所有的 <a>  元素
let oAs = document.querySelectorAll('#box a');
console.log(oAs.length);

// 获取class为box1元素下所有的 <a>  元素
let oAs = document.querySelectorAll('.box1 a');
// 设置第二个a元素的字体颜色为白色
oAs[1].style.color = '#fff';