谷歌浏览器的控制台(F12/Fn+F12)
按照相关的JS语法,去操作页面中的元素,有时还要操作浏览器里面的一些功能
变量:可变的量,在编程语言中,变量就是一个名字,用来储存和代表不同值得东西
//ES3
var a = 12;
a = 13;
console.log(a); //=>输出的是a代表的值12
//ES6
let b =100;
b = 200;
const c = 1000;
c = 2000; //=>报错: CONST创建的变量,储存的值不能被修改(可以理解为叫做常量)
//创建函数也相当于在创建变量
function fn(){}
//创建类也相当于创建变量
class A{}
//ES6的模块导入也可以创建变量
import B from './B.JS';
//Symbol创建唯一值
let n=Symbol(100);
let m-Symbol(100);
let Test=100;
console.log(test);//=>无法输出,因为第一个字母小写了
let $box;//=>一般用JQ获取的以$开头
let _box;//=>一般公共变量都是_开头
let 1box;//=>不可以,但是可以写box1
let studentInformation;
let studentInfo;
//常用缩写:add/insert/create/new(新增)、update(修改)、delete/del/remove/rm(删除)、sel/select/query/get(查询)、info(信息)···
当下有特殊含义的是关键字,未来可能会成为关键字的叫保留字()
var let const function···
//=>必须养成良好的写代码习惯,具有极客精神
包含:常规数字\NaN
not a number:不是一个数字,但它属于数字类型
NaN和任何值(包括自己)都不相等:NaN!=NaN,所以我们不能用相等的方式判断是否为有效数字
检测一个值是否为非有效数字,如果不是有效数字返回TRUE,反正是有效数字返回FALSE
在使用isNaN进行检测时,首先会验证检测的值是否是数字类型,如果不是,先基于Number()这个方法,把值转换为数字类型,然后再检测
所有用单引号、双引号、反引号(撇 ES6模板字符串)包起来的都是字符串
let a = 10 + null + true + [] + undefined + '珠峰' + null + [] + 10 + false ;
console.log(a);
结果是:'11undefined珠峰null10false'
- 分析: 10 + null -> 10
10 + true -> 11
11 + [] -> 11 + '' -> '11' 空数组变为数字,要先经历变为空字符串,遇到字符串,啥都不要想,直接变成字符串拼接
'11' + undefined -> '11undefined'
···
结果为:'11undefined珠峰null10false'
- 把引用数字类型转化为数字,先把他基于toString方法转换为字符串,然后再转化为数字
把字符串转化为数字,只要字符串中包含任意一个非有效数字字符(第一个点除外)结果都是NaN,空字符串会变成数字零
console.log(Number('12.5'));//=>12.5
console.log(Number('12.5px'));//=>NaN
console.log(Number('12.5.5'));//=>NaN
console.log(Number(''));//=>0
//布尔转换为数字
console.log(Number(true));//=>1
console.log(Number(false));//=>0
console.log(isNaN(false));//=>false
console.log(isNaN(true));//=>false
//null->0 undefined->NaN
console.log(Number(null));//=>0
console.log(Number(undefined));//=>NaN
console.log(Number({name:'10'}));//=>NaN
console.log(Number({}));//=>NaN
//把引用数字类型转化为数字,先把他基于toString方法转换为字符串,然后再转化为数字
//{}/{xxx:'xxx'}.toString() =>"[object object]"=>NaN
console.log(Number([]));//=>0
//[].toString() -> ''
console.log(Number([12]));//=>12
//[12].toString() -> '12'
console.log(Number([12,23]));//=>NaN
//[12,23].toString() -> '12,23'
console.log(Number(Symbol(13))); //=>Cannot convert a Symbol value to a number
只有两个值 true/false
只有 0、NaN、’’、null、undefined 五个值转换为FALSE,其余都转换为TRUE(而且没有任何特殊情况)
null和undefined都代表的是没有
null:意料之中(一般都是开始不知道值,我们手动先设置为null,后期再给予赋值操作)
let num = null;//=>let num = 0; 一般最好用null作为初始空值,因为零不是空值,在栈内存中有自己的存储空间(占了位置)
···
num=12;
- undefined:意料之外(不是我能决定的)
let num;//=>创建一个变量没有赋值,默认值是undefined
···
num = 12;
/* 对象的属性名不能是引用数据类型值 */
// =====基于 对象[属性名] 的方式操作,需要保证属性名是一个值(字符串/数字/布尔等都可以),如果不是值而是一个变量,它会把变量存储的值作为对象的属性名进行操作
// =====基于 对象.属性名 的方式操作,属性名就是点后面的
/* let n = 100;
let obj = {
1: 100
};
// console.log(obj[1]);
// console.log(obj.1); //=>Uncaught SyntaxError: missing ) after argument list 基于点的方式操作有自己的局限性,属性名不能是数字的,不能 对象.数字属性,此时只能用 对象[数字属性]
// console.log(obj[1]);
// console.log(obj['1']); //=>其它非字符串格式作为属性名和字符串格式没啥区别
// obj.n = 200; //=> {n:200} n是属性名(数据格式是字符串)
// obj['n'] = 200; //=> {n:200} 和上面的情况一样
// obj[n] = 200; //=> {100:200} => obj[100]=200 n本身是一个变量(n和'n'的区别:前者是一个变量,后者是一个字符串的值),它代表的是所存储的值100(是一个数字格式)
// obj[m] = 200; //=>Uncaught ReferenceError: m is not defined m这个变量没有被定义
// obj[true] = 300; //=>{true:300}
// obj[undefined] = 400; //=>{undefined:400}
console.log(obj); */
/* let n = {
x: 100
};
let m = [100, 200];
let obj = {};
obj[n] = "珠峰"; //=>obj[{x:100}] 但是对象不能作为属性名,需要把其转换为字符串 =>{"[object Object]":"珠峰" }
obj[m] = "培训"; //=>obj[[100,200]] =>{ "100,200":"培训" }
console.log(obj);
//=>如果非要让属性名是个对象,只能基于ES6中的新数据结构 Map 处理
{[key]:[value],…}任何一个对象都是由零到多组键值对(属性名:属性值)组成的(并且属性名不能重复)
数组是特殊的对象数据类型
以图片的和例子的形式呈现
下面贡献一道例题,采用画图的形式呈现出来:
- 例题1
let n = [10,20];
let m = n;
let x = m;
m[0] = 100;
x = [30,40];
x[0] = 200;
m = [50,60];
m = x;
m[1] = 300;
n[2] = 400;
console.log(n,m,x);
- 再来一道阿里的面试题
let a = {
n : 1
};
let b = a;
a.x = a = {n:2};
console.log(a.x);
console.log(b);
JS中的数据类型检测
console.log(typeof 1); // 输出 =>"Number"
//比如下面一个小例子,就可以体现出你是否理解这个知识并判断你是否具有极客精神
console.log9(typeof typeof typeof []); // => "string"
//分析如下:
//typeof [] => "object"
//typeof "object" => "string"
// 因为typeof检测的结果都以字符串形式输出,所以只要两个和两个以上同时检测,最后结果必然"string"
条件成立干什么?不成立干什么?
1.if/else
if(条件){
条件成立执行
}else if(条件2){
条件2成立执行
}
···
else{
以上条件都不成立
}
let a = 10;
if(a <= 0) {
//条件可以多样性:等于、大于、小于的比较/一个值或者取反等 => 最后都是要计算出是true还是false
console.log('哈哈');
}else if(a>0 && a<10){
console.log('呵呵');
}else if(a == 10){
console.log('嘿嘿');
}else {
console.log('嘻嘻');
}
2.三元运算符
三元运算符:简单的IF/ELSE的特殊处理方式
语法:条件?条件成立处理的事情:条件不成立处理的事情;
1.如果处理的事情过多,可以用括号包起来,每一件事情用逗号分隔
2.如果不需要处理事情,可以用null/undefined占位
下面引用一个例子说明三元运算符
let a = 10;
if(a > 0){
if( a < 10){
a++;//=>a+=1 a=a+1 =>自身累加1
} else {
a--;;//=>a-=1 a=a-1 =>自身累减1
}
} else {
if(a > -10){
a += 2;
}
}
a > 0 ? ( a < 10 ? a++ : a--) : ( a > -10 ? a+=2 : null);//三元运算符形式表达
3.switch case
//===========================switch case :一个变量在不同值得情况下的不同操作
//1.每一个case结束后都要加上break,不加break,当前条件执行完成后,后面条件不论是否成立都要执行,直到遇到break为止(不加break可以实现变量在某些值时做相同的事情)
//2.default等价于else,以上都不成立干的事情
//3.每一个case的比较都是用===“绝对相对”
/* let a = 10;
switch(a){
case 1:
console.log('haha');
break;
case 1:
console.log('hdada');
break;
case 1:
console.log('mimi');
break;
default :
console.log('wuwu');
} */
下面是一个案例具体讲基于JS如何实现业务需求
点击切换详情显示
购物车
重复做某些事情就是循环
/*
*1.创建循环的初始值
*2.设置(验证)循环执行的条件
*3.条件成立执行循环体中的内容
*4.当前循环结束执行步长累计操作
*/
/* for(var i =0;i<5;i++){
console.log(i);
} */
//循环体中的两个关键词
//continue:结束当前这轮循环(continue后面的代码不再执行),继续执行下一轮循环
//break:强制结束整个循环(break后面代码也不再执行),而且整个循环啥也不干直接结束
for(var i=0;i<10;i++){
if(i>=2){
i+=2;
continue;
}
if(i>=6){
i--;
break;
}
i++;
console.log(i);
}
console.log(i);
//属性名:属性值(放的如果是变量也是把变量存储的值拿过来做属性值)
var name = '兄贵'//变量名=变量值
var obj = {
name: name//属性名:变量名
//name, ES6的写法(当属性名和属性值同名时)
age: 1 === 1 ? 100 : 200//先计算出值再传给属性名
}//=>兄贵
下面是老师讲的例子
var name = 10;
var obj = {
name: '珠峰培训'
};
//获取OBJ对象NAME属性对应的值
console.log(obj.name);//=>珠峰培训
//一个对象的属性名只有两种格式:数字或者字符串(等基本类型值)!!!!!!!!理解的关键点,非常重要
console.log(obj['name']);//=>珠峰培训
//obj[name变量代表的值] => obj[10] =>undefined
console.log(obj[name]);
现在开始理解循环:
for in循环是用来循环遍历对象中的键值对的(continue和break同样适用)有限循环数字属性名(从小到大)
语法:for(var 变量(key) in 对象)
对象中有多少组键值对,循环就执行多少次(除非break结束)
let obj = {
name: 'shaokang',
age: 24,
friends: 'me,xuxu,zhaomin',
1: 20,
2: 50
};
for (var key in obj) {
//每次循环key变量循环的是当前对象的属性名
console.log(key);//=>1,2,3,name,arg,friends
//获取属性值:obj[变量名(变量存的值也就是属性名)] => obj[key]
console.log('属性名:' + key + '属性值' + obj[key]);
函數就是一個方法或者一個功能体,函数就是把实现某个功能的代码放到一起进行分装,以后想要操作实现这个功能,只需要把函数执行即可 => “封装”:减少页面中的冗余代码,提高代码重复利用率(低耦合 高内聚)
洗衣机就是一个函数,生产洗衣机就是封装一个函数(把实现某些功能的代码封装进来),生产时不知道用户洗衣服时不知道用户放什么水、衣服等,我们需要提供入口(提供的入口在函数中叫做形参,执行的时候具体放的东西叫做实参),洗完衣服需要拿出来,洗衣机提供一个出口(在函数中叫做返回值:把函数处理后的结果能够返回给外边用)
/**
* 任意数求和
* 1.传递的实参个数不定
* 2.传递的值是否为有效数字不定
* => 把传递的有效数字进行求和
*
* arguments:函数内置的实参集合
* 1.类数组集合,集合中存储着所有函数执行时,传递的实参信息
* 2.不论是否设置形参,arguments都存在
* 3.不论是否传递实参,arguments也都存在
* arguments.callee:存储的是当前函数本身(一般不用,JS严格模式下禁止使用这些属性)
*/
function sum() {
let total = null;
for (i = 0; i < arguments.length; i++) {
//获取的每一项的结果都要先转换为数字(数学运算)
let item = arguments[i];
//非有效数字不加
if (isNaN(item)) {
continue;
}
total += item;
}
return total;
}
//=>ES5老方式
function[函数名]([形参变量1],···){
// 函数体:基于JS完成需要实现的功能
return [处理后的方法];
}
[函数名]([实参1],···);
// 求两个数的和,算完后乘10再除以2
// =>sum是函数名,代表这个函数
// =>sum()是让函数执行,代表的是
// =>n,m是形参,也是变量,用来存储执行函数时传递的实参
/* function sum(n, m) {
let result = n + m;
result *= 10;
result /= 2;
console.log(result);
}
//10,30就是传递给形参变量的值(实参)
sum(10, 30);*/
/*
let n = 10 + 10;
n = n * 10;
n = n / 2;
*/
//====================形参的细节
// 创建函数的时候,我们设置了形参变量,但如果执行的时候并没有传递对应的形参值,那么形参变量默认的值是:undefined
/* function sum(n, m) {
// 形参默认值处理:如果没传递形参值,给予一个默认值
if (n === undefined) {
n = 0;
}
if (typeof m === 'undefined') {
m = 0;
}
let result = n + m;
result *= 10;
result /= 2;
console.log(result);
}
sum();// =>NaN
sum(10);// =>NaN
sum(10, 20);// =>150
sum(10, 20, 30);// =>150 */
//=====================函数中的返回值
//函数执行的时候,函数体内部创建的变量我们是无法获取和操作的,如果想要获取内部的信息,我们需要基于RETURN返回机制,把信息返回才可以
/* function sum(n, m) {
let result = n + m;
//RETURN的一定是值:此处是吧RESULT变量存储的值返回给外面
return result;// =>30
}
let AA = sum(10, 20);
console.log(AA);
//console.log(result);//Uncaught ReferenceError: result is not defined
*/
//没有写RETURN,函数默认返回值是undefined
/* function sum(n, m) {
let result = n + m;
}
let AA = sum(10, 20);
console.log(AA); // =>underfined */
function sum(n, m) {
if (n === undefined || m === underfined) {
//函数体中遇到RETURN,后面代码就不再执行了
return;
}
let result = n + m;
}
sum(10, 20);
//=======================匿名函数
//匿名函数之函数表达式:把一个匿名函数本身作为值赋值给其他东西,这种函数一般不是手动触发执行,而且靠其他程序驱动触发执行(例如:触发某个事件的时候把它执行等)
document.body.onclick = function () { }
setTimeout(function () { }, 1000); // => 设置定时器,1000s后执行匿名函数
//匿名函数之自执行函数:创建完一个匿名函数,紧接着就把当前函数加小括号执行
(function (n) {
// =>100
})(100);
下面引出一个选项卡的小案例,其中包括一些列知识
=============================首先创建一个HTML的格式==========================
選項卡
编程使我快乐
读书使我明智
运动使我健康
================================下面是CSS文件==================================
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
#tabBox {
box-sizing: border-box;
margin: 20px auto;
width: 500px;
}
#navBox {
/* 只要把容器设置为FLEX弹性盒子容器,那么容器中的子元素默认在容器主轴(X轴)水平靠左排列 */
display: flex;
/* 相对于自己之前的位置向下移动一个像素 */
position: relative;
top: 1px;
}
#navBox li {
box-sizing: border-box;
margin-right: 10px ;
padding: 0 10px;
line-height: 35px;
border: 1px solid #999;
cursor: pointer;
}
#navBox li.active{
border-bottom-color: #ffffff;
}
#tabBox>div {
display: none;
box-sizing: border-box;
padding: 10px;
height: 150px;
border: 1px solid #999;
}
#tabBox>div.active{
display: block ;
}
================================下面是JS文件以及其中的问题=================================
var tabBox = document.getElementById('tabBox');
var tabList = tabBox.getElementsByTagName('div');
var navBox = document.getElementById('navBox');
var navList = navBox.getElementsByTagName('li');
/*=============解决办法一:自定义属性解决 =============== */
//循环三个li,给每个li都绑定点击事件
for (var i = 0; i < navList.length; i++) {
//navList[i]:当前循环下我们要操作的li(i变量储存的值使我们需要获取指定元素的索引)
//在循环给每个LI绑定点击事件的时候,我们给没一个LI(元素对象)设置一个自定义属性MY-INDEX,属性值存储的是当前LI的索引
navList[i].myIndex = i
navList[i].onclick = function () {
//console.log(i); => 3
//我想点击的是LI的索引,但是I不是
//THIS是当前点击这个元素的LI,this.myIndex获取的是之前绑定在元素自定义属性上的索引值
changeTab(this.myIndex);
}
}
/* =============其他方式================ */
//闭包解决方案
/* for (var i = 0; i < navList.length; i++) {
navList[i].onclick = (function (i) {
return function(){
changeTab(i);
}
})(i);
}
*/
//ES6中的LET解决方案
/* for (let i = 0; i < navList.length; i++) {
navList[i].onclick = function () {
changeTab(i);
}
} */
/*==================不能执行及其原因====================*/
/* for (var i = 0; i < navList.length; i++) {
navList[i].onclick = function () {
changeTab(i);
}
} */
/*只有JS代码加载完成才能看到页面,只有用户看到页面才能点击
*加载到循环这个代码了 i=0 i<3 i++
*i=0 navList[0].onclick = function () {···}绑定事件的时候方法没执行,点击第一个LI才执行 i++
*i=1 navList[1].onclick = function () {···} i++ => 2
*i=2 navList[2].onclick = function () {···} i++ => 3
*3<3 不通过,循环结束,此时i已经是3了
*
*循环结束看到页面,用户点击了页面,接下来执行绑定方法,方法中遇到一个I,但是I已经是循环结束后的3了
*/
//封装一个函数实现选项卡切换
//clickIndex:创建函数的时候还不知道是谁,所以定义一个入口clickIndex(点击这一项的索引),执行这一方法的时候把点击这一项的索引传进来即可
function changeTab(clickIndex) {
//1.先让所有的LI 和DIV都没有选中样式
for (var i = 0; i < navList.length; i++) {
navList[i].className = '';
tabList[i].className = '';
}
//2.点击的是谁就给谁加选中的样式类
navList[clickIndex].className = 'active';
tabList[clickIndex].className = 'active';
}
为了便于深入理解自定义函数这种方法,下面附上三张图片用来更好的理解这个知识点:
函数运行的底层原理
选项卡的原理:
====================================================================
swich case中的比较是绝对相等===
let i='10';
i=i+1 / i+=1 => '101'
i++ => i=11 i++是纯粹的数学运算
i++和++i都是数学运算中的累加1,区别是计算的顺序 i++是先运算,然后再给i+1;++i是先给i+1,再进行计算
下面是两个练习
1.变态基础知识练习题
1.!(!"Number(undefined)"); => True
2.isNaN(parseInt(new Date())) + Number([1]) + typeof underfined; => "2undefined"
3.Boolean(Number("")) + !isNaN(Number(null)) + Boolean("parseInt([])") + typeof!(null); => "2boolean"
4.parseFloat("1.6px") + parseInt("1.2px") + typeof parseInt(null); => "2.6number"
5.isNaN(Number(!!Number(parseInt("0.8")))); => false
6.console.log(1 + "2" + "2"); => "122"
7.!typeof parseFloat("0"); => false
8.Number(""); => 0
9.typeof"parseInt(null)" + 12 +!!Number(NaN); => "string12false"
10.!typeof(isNaN("")) + parseInt(NaN); => NaN
11.typeof !parseInt(null) + !isNaN(null); => "booleantrue"
总结:1.!!表示转换成布尔类型
2.引号里都是字符串,布尔类型中除了(0’’\false\null\undefined)其余都是1,所以布尔类型里出现字符串只要不是空字符串就是1
3.typeof检测出的数据类型是以字符串形式表示出来
4.parseFloat\parseInt 从左往右依次检测数字,直到遇到非数字则把之前的数字按照相应类型输出,如果没有遇到数字则输出NaN
2.做一个点击body换肤,用了两种思路
换肤