- css写在哪
- 内联(行内):属性形式:style="样式属性:样式属性值"
- 内部:style双标签,包裹css样式
- 外部(外联):link单标签,的href属性,引入css文件的路径
- 知道啥叫公共样式不?
- 好几个页面都要用到的样式,叫公共样式
- 内联(行内):属性形式:事件触发
- ``
- 不建议使用,结构和行为的分离,优化项目,便于管理
- 为了测试方便
- 内部:script双标签,包裹js代码
-
- - 不太建议内部,结构和行为的分离,非公共行为部分,简单行为,可以放在当前页面
- 公共行为:好几个页面都要用到的行为,叫公共行为
- script标签可以放在哪?
- 可以放在任何位置
- 行业习惯:
- head标签内
- body后:内部的最后;外边的最后;没有区别
- script标签,放在不同的位置,执行顺序受到了影响。目前如果不是特殊要求,暂时将script标签写在body的后面
- 外部(外联):script双标签,通过**src**属性,引入js文件的路径
- 创建js文件,再在html文件中使用script双标签,通过**src**属性,引入js文件的路径
- script标签放在哪
- 任何位置
- 行业习惯:
- head标签内
- body后:内部的最后;外边的最后;没有区别
- script标签,放在不同的位置,执行顺序受到了影响。目前如果不是特殊要求,暂时将script标签写在body的后面
- 按需放置位置
- 注意:错误写法
```html
不允许在引入外部js的script标签内,写js代码,写了,也不会执行
- ECMAScript:语法,规定,规则,法律,规定了,以什么样的格式,写代码
- BOM:浏览器对象模型,提供了浏览器的操作
- DOM:文档对象模型,提供了网页的操作
- 关系:ECMAScript规定了,写什么样的代码,在BOM中操作DOM
- 交通法规,规定,以什么样的方式,在马路上开车
- 除非特殊说明,目前学习的大部分都是ECMAScript。后期,DOM和BOM会单独作为知识点讲解
- 什么叫打印信息,不是输出信息,是**打印**:
- 将计算机的执行结果或数据,给用户呈现出来
- 打印到浏览器的弹出框,操作的是BOM对象,浏览器
- `alert()`
- 打印到页面,操作的是DOM对象,页面
- `document.write()`
- 打印到浏览器的控制台,操作的是BOM对象,浏览器(操作的V8引擎)
- `console.log()`
单行注释
- // 单行注释
- 多行注释
- /* 多行注释,可以换行 */
分门别类,记录信息的方式
- 字符型(string):必须加引号:单''、双""、反``;任何数据,只要加了引号,就是字符!!!
- 数值型(number):29
- undefined(undefined):undefined,未赋值,不是未定义
- 布尔值(boolean):true、false
- 对象(object):标志是{},并不是绝对的
- 函数(function):标志是function,并不是绝对的
- 不是数学中的函数,不用担心,跟数学一点关系都没有
- null(object):null,不是空对象,空值,虚无
- 我说,见到了一个空的UFO。空:null
- 跟我来,来了,手指,指着地上的这个机器,告诉你说,这是一个空的UFO。空:undefined
- 注意:
- 描述,空的时候,除了null,其他都要加 类型
- 空 字符:""
- 空 对象:{}
- 空 函数:function(){}
- 空 数组:[]
- null:null
- undefined未赋值:undefined
通过typeof关键字,检测数据类型
-1 typeof 要检测的数据或变量
- `typeof 变量或数据`
-2 typeof(要检测的数据或变量)
- `typeof(变量或数据)`
-3 typeof的检测的结果的数据类型,必然是字符型数据
- `typeof typeof 变量或数据`
console.log(({}).toString()) /* [object Object] */
console.log(Object.prototype.toString.call({})) /* [object Object] */
console.log(Object.prototype.toString.call([])) /* [object Array] */
console.log(Object.prototype.toString.call(new Function)) /* [object Function]*/
console.log(Object.prototype.toString.call(new RegExp)) /* [object RegExp] */
console.log(Object.prototype.toString.call(new Error)) /* [object Error] */
console.log(Object.prototype.toString.call(new Set)) /* [object Set] */
console.log(Object.prototype.toString.call(new Map)) /* [object Map] */
function Person() {};
let p = new Person;
class Animal {};
let a = new Animal;
console.log(Object.prototype.toString.call(p)) /* [object Object] */
console.log(Object.prototype.toString.call(a)) /* [object Object] */
console.log(p instanceof Person) /* true */
console.log(a instanceof Person) /* false */
console.log(a instanceof Animal) /* true */
console.log(a instanceof Function, a instanceof Object) /* false true */
console.log(a.constructor == Person); /* false */
console.log(a.constructor == Animal); /* true */
console.log(a.constructor == Object); /* false */
console.log(p.constructor == Person); /* true */
console.log(({}).constructor == Object) /* true */
console.log(([]).constructor == Array) /* true */
/* 1、条件表达式 */
/* if() 里面的条件表达式的结果一定是布尔值 true | false */
/* false :null undefined "" 0 NaN*/
/* ! : 取反操作得到的一定是布尔值 */
console.log(1 + true) /* 把布尔值转换为数字1 == 2*/
console.log(1 + null) /* 把 null 转换为 0 == 1*/
console.log(1 + undefined) /* NaN 因为 undefined 无法转换为数字,得到NaN */
console.log(1 + {}); /* "1[object object]"*/
/* 逻辑:先调用valueOf()转换为数字,如果得到的仍然是对象,则继续调用 toString方法 */
console.log({}.valueOf()); /* {} */
console.log({}.toString()); /* "[object Object]" */
console.log(undefined == null) /* true */
/* 特殊的几种情况 */
console.log({} == {}) /* false 因为这是引用类型的数据 */
console.log({} == "[object Object]") /* true {}.toString() */
console.log([] == ![]); /* true */
当程序中,需要重复操作某些相同数据的时候,为了方便,可以将数据起个别名,通过这个别名,找到数据,使用,这个别名,就叫变量
- 语法
- 通过var的关键字,声明
- var a;
- 通过赋值的方式,将数据,存到变量中:一个等号赋值
- var a = "hello";
- 将等号右侧的数据,存在左侧的变量中(将等号右侧的数据,起了一个别名叫等号左边的单词)
- 关键字
- 被ECMAScript定义了功能的单词
- 保留字
- 暂时还没有被ECMAScript定义了功能,但是将来有可能被定义功能的单词
- - 必须以 `字母,_,$` 开头
- 不允许出现 `字母,_,$,数字` 之外的内容
- 不建议使用中文,有兼容,不仅浏览器有兼容,操作系统也会有兼容,在公司中,容易挨揍
- 尽量语义化
1. 词必达意
2. 建议使用当前数据类型的首字母作为前缀
3. 尽量使用驼峰式
- 小:从第二个单词的首字母开始大写,常用
- 大:从第一个单词的首字母开始大写,面向对象中,专用
- 不允许使用关键字或保留字
- 诀窍:如果担心是关键字或保留字,可以在单词前加前缀
- 注意
- 变量名,千万别加,引号!!!!!!
为什么要转换?
- 如果,用户给了一个数据,或者计算机给了一个数据,或者其他程序给了一个数据,不是咱们想要的数据类型
- 需要转成当前程序所需的数据类型,再进行运算
- 转换方法有哪些
1:- `parseInt(要转换的数据或变量)`
- 从左向右依次检测,遇到第一个非数字的字符,停止转换
- 忽略小数点后所有的内容,其实是将小数点识别成了非数字
- 如果第一位就是非数字,直接NaN
- NaN是什么?not a number
- 不是一个数字的数值型数据
- 非法的数值运算的结果
- 非法:不合法,不合规,本来不能转,非要转
2:`parseFloat(要转换的数据或变量)`
- 从左向右依次检测,遇到第一个非数字的字符,停止转换
- 可以识别小数点
- 如果第一位就是非数字,直接NaN
- NaN是什么?not a number
- 不是一个数字的数值型数据
- 非法的数值运算的结果
- 非法:不合法,不合规,本来不能转,非要转
3:- `Math.round(要转换的数据或变量)`
- Math.round不是专门做字符转数值的
- 专门做取整的,取最近的整数,顺带着给可以实现转换
- 严格转换:只要出现非数字,那么就是NaN
4:- `Number(要转换的数据或变量)`
- Number不是专门做字符转数值的
- 系统内置的构造函数,用来创建数值对象,后话...顺带着给可以实现转换,直接转换
- 严格转换:只要出现非数字,那么就是NaN
如何选择?
- 按需选择
- 当需要转换时,观察当前程序的运行情况,以及要转换数据的实际情况,对应实际规则,选择方法
- 不管选哪个,只要注意规则,都能灵活使用
- `数值变量.toString()`
- 直接转换,相当于加个引号
- `数值变量.toFixed(n)`
- 保留n为小数
- 其他转布尔
- 布尔转数值
- 其他转字符
- 隐式转换(被动转换,什么都没做,自动就转了)
1. 算数运算
- `+`号两边只要出现字符,结果必然为字符
- `-`,`*`,`/`,`%`的结果必然是数值
2. 关系运算
- `>`,`<`,`>=`,`<=`,`!=`,`==`两边只要出现数值,那么另一边也会转成数值,进行比较
- `+` 加号,加法
- 当加号两边都是数值型数据时,是数学的加法运算
- 任意一边是字符,那么就变成了拼接,拼接就是将两个数据,直接组合起来
- `-`,`*`,`/`,`%`
- 就是正常的数学运算
- 就算两边不是数值,也会默认转成数值,进行运算
- 如果某个数据不能转成数值,会得到`NaN`
关系运算符 - 的结果是布尔值
- `>`,`<`,`>=`,`<=`
- 只要有一边出现数值,都是数值的**比较规则**
- 如果都是字符,才是字符的**比较规则**:**逐位比较**,得到结果,就停止
- `!=`,`==`
- 会发生隐式类型转换,或者只比较大小,不比较类型
- `!==`,`===`
- 不会发生隐式类型转换,不仅比较大小,还比较类型
- 或
- ||:两边只要出现true,结果就是true,必须都为false,结果才是false
- 且
- &&:两边只要出现false,结果就是false,必须都为true,结果才是true
- 非
- !:取反
- `=`
- 将等号右侧的数据,存在左侧的变量中
- 把右边的内容,放在左边的变量中
- 如果左侧的变量,原本有值,那么会覆盖
- `+=`,`-=`,`*=`,`/=`,`%=`
- 先计算,再赋值(覆盖)
- 请参考:`+ - * / %`
- 自增
- `++`
- 增加1
- 前后之分
- 前自增`++n`:先计算,后使用
- 后自增`n++`:先使用,后计算
- 自减
- `--`
- 减少1
- 前后之分
- 前自减`--n`:先计算,后使用
- 后自减`n--`:先使用,后计算
1. 语法
- `条件 ? 条件为真,值1 : 条件为假,值2`
2. 注意
- 三目其实就是一种简写方式,如果不能简写,那就不用三目
- 三目是个表达式,表达式最终会计算出一个值
var n = 16;
var m = n>10 ? n.toString() : "0"+n;
console.log(m);
能用就用,不能用,老老实实的写if-else去
undefined,null,NaN
每一个NaN都是非法运算的结果,每一个NaN的来源都不一样
`NaN`:非法的数值运算得到的结果
- 特殊之处:
1. 是一个数值型的数据,但是不是一个数字
2. NaN不等于任何值,和任何数据都不相等,NaN不等于NaN
- 检测方法:`isNaN(要检测的数据)` 检查的数据如果是数字类型就是true 否则都是false
- true:检测结果为 NaN 或能转成 NaN
- false:检测结果不是 NaN 或不能转成 NaN
// 还会发生隐式类型转换
// 场景是:isNaN的小括号
// 规则:转成数值,严格转换,能识别小数点
// // 严格转换:只要出现非数字,就是NaN
/* 延伸:Object.is() */
/* 作用:基本上等同于全等 === ,但是有两点不同*/
/* [1] 可以比较 NaN */
console.log(NaN === NaN, Object.is(NaN, NaN)); /* false true */
/* [2] 比较-0 +0 */
console.log(-0 === +0, Object.is(-0, +0)); /* true false */
`undefined`是:未赋值,类型是undefined;`null`是:空,类型是object
- 特殊1:undefined和null在关系运算符两边隐式类型转换后,得到了一致的数据
- 特殊2:undefined被Number转成NaN,null被Number转成0
- 如何判断三大特殊的值,分别是谁?
- `NaN`可以使用`isNaN()`来判断
- isNaN(要判断的值或变量);
```js
var a = NaN;
console.log(isNaN(a)); // 结果是布尔值:true为是的,false为不是
`undefined`可以使用`typeof`判断
- typeof 要判断的值或变量
var b = undefined;
console.log( (typeof b) === "undefined" );// 结果是布尔值:true为是的,false为不是
`null`需要配合`typeof`和 关系运算符判断( && ),要判断的值或变量 == null
- typeof 要判断的值或变量 === "object"
var c = null;
console.log( (typeof c) === "object" && c === null);
- 顺序结构 - 每天
- 代码逐行执行,一行一行自上而下执行
- 分支结构
- 有选择了,十字路口的选择,只能选择一个,如果...否则...
- 循环结构 - 后话
- 重复,重复执行多次,起因:无聊,然后开始:吃,胖,心情不好,吃,胖....
分支和循环结构,需要配合一些专用代码才能实现,专用代码叫:语句
- `if`:单分支
- `if(条件){执行语句}`
- `if else`:双分支
- `if(条件){条件为true时,要执行的语句}else{条件为false时,要执行的语句}`
- 分支的嵌套(双分支模拟的多分支)
- 在执行体内,可以继续写其他分支
- `if(条件1){
}else if(条件2){
}else if(条件3){
}else......`
- if的小括号里面也会发生隐式类型转换规则
- 规则:其他转布尔
- 数值转布尔:非0为true,0为false
- 字符转布尔:非空字符,为true,空字符,为false
- 对象转布尔:对象为true
- 数组转布尔:数组为true
- 函数转布尔:函数为true
- 特殊数据转布尔:undefined,NaN,null都为false
var n = 2;
var msg = "";
switch(Number(n)){
case 0:
msg = "星期日";
break;
case 1:
msg = "星期一";
break;
...
default:
msg = "你输入的数字不对,请输入0~6之间的数字";
}
console.log(msg);
-
- 规则:
- 当要判断的值是固定的数据时,选择使用switch
- 如果要判断的值是范围时,选择使用if-else
- switch的case判断,不存在隐式类型转换
- 某些情况下,需要根据场景,选择是否需要主动转换
- 如果你不管上面的使用建议,非要使用switch判断范围,注定要多掉点头发
- 所有的隐式类型转换,仅仅发生在该数据被使用时,该数据还是原本的内容
- `||`
- 基础规则
- 或的两边只要出现一个true就是true
- 如果两边都是false,就是false
- 原理
- 如果左侧是true,那么就确定 或 的结果了,不再向右检测
- 如果左侧是false,不能确定结果,需要继续向右检测,不管右侧是啥,结果都停在右侧了
- `&&`
- 基础规则
- 且的两边只要出现一个false就是false
- 原理
- 如果左边是true,不能确定结果,向右检测;左边是false,确定结果,不向右检测
console.log(true && false); // f
console.log(0 && false); // 0
console.log(1 && false); // f
console.log(false && 0); // f
console.log( 1 && 2 ); // 2
console.log( 2 && 1 ); // 1
- `!`
- 规则:取反
- 灵活利用非,实现其他转布尔
1. 现象
- 明明只有一位小数,但是最后出来很多位
- 0.1 + 0.7 = 0.799999999999999
- 59.999999999999999 不小于 60
- 诸如此类问题
2. 原因
- 计算机最终执行或识别的符号只有0和1,二进制
- 计算机中有一套完善的转换机制,所有内容,不管是文字,字符,任何数据,图片,声音,视频,最终都会被解析成二进制
- 计算机对于小数的计算,会产生误差
3. 解决
- 主动保留n为小数,得到数据类型是字符
- ` num = num.toFixed(n); `
- 转成数值
- ` num = Number(num); `
1. 程序的三大结构
- 顺序:代码自上而下,按顺序执行
- 分支:根据指定的条件,选择不同的过程执行
- 循环:重复
2. 循环的意义
- 循环的意义是什么?
- 节省操作,减少代码冗余
3. 循环的三要素
- 计数器的创建
- 执行条件(停止条件)的设定
- 计算器的改变
4. 循环语句
- 配合指定的语句,这个语句,叫循环语句
while
var i = 0;
while( i<10 ){
document.write("hello world
");
i++;
}
do while
var i = 0;
do{
console.log(i);
i++;
}while(i < 10){
console.log("循环结束了");
}
do-while语句比while语句多执行一次
- 计数器的改变最好放在循环体的最后,除非特殊需要
- 如非特殊需要,千万不能在循环中**额外**改变计数器
- 循环,最好理解执行过程,不要硬记,因为还有循环的嵌套
- **while更适合不知道循环次数的需求
for(var i=0;i<=10;i++){
console.log(i);
}
- 特点
- 三要素,更集中,无需考虑计数器改变的位置,而影响程序结果
- 顺序不能变(计数器的初始值; 条件; 计数器的改变)
- 执行顺序
- 1:初始化计数器
- 2:条件,4:循环体,3:改变,2,4,3,.......
- break
- 立即结束循环,后面的任何代码都不再执行
- 虽然跟switch中的break长得一样,但是各有各的功能
- continue
- 跳过本次循环,继续下次循环的执行
- 死循环
- 无法通过自身控制结束的循环
- 特点:消耗大量的内存,浪费资源,程序崩溃
- 但是,可以利用死循环的思路,解决不知道循环次数的问题
- 记得在合适的时候,通过*控制关键字**停止
循环的嵌套,可以解决,多行多列的数据结构问题
// 外层循环控制行
// 内层循环控制列
// 页面打印出:
// *
// **
// ***
// 1.直接逐个字符打印
// document.write("*");
// document.write("
");
// document.write("*");
// document.write("*");
// document.write("
");
// document.write("*");
// document.write("*");
// document.write("*");
// document.write("
");
// 2.循环的意义,节省操作,减少代码冗余
// for(var i=0;i<1;i++){
// document.write("*");
// }
// document.write("
");
// for(var i=0;i<2;i++){
// document.write("*");
// }
// document.write("
");
// for(var i=0;i<3;i++){
// document.write("*");
// }
// document.write("
");
// 3.利用变量,将代码改造成完全一致
// var j=1;
// for(var i=0;i
// document.write("*");
// }
// document.write("
");
// j++;
// for(var i=0;i
// document.write("*");
// }
// document.write("
");
// j++;
// for(var i=0;i
// document.write("*");
// }
// document.write("
");
// j++;
// 4.进一步减少代码冗余
for(var j=1;j<=3;j++){
for(var i=0;i<j;i++){
document.write("*");
}
document.write("
");
}
for(var j=1;j<=9;j++){
for(var i=1;i<=j;i++){
document.write(i + "*" + j + "=" + i*j +" ");
}
document.write("
");
}
// 1~10的阶乘和
// 先计算每个数字的阶乘
// 然后再累加
// 1 + 每行都需要单独计算一个乘积
// 1*2 + 每行都需要单独计算一个乘积
// 1*2*3 + 每行都需要单独计算一个乘积
// 1*2*3*4 + 每行都需要单独计算一个乘积
// .....
// 外层循环控制行
// 内层循环控制列
var sum = 0; // 用来记录最终的和,所以只需要一个即可
for(var i=1;i<=10;i++){ // 控制行的时候,需要单独的变量
var cj = 1; // 根据行的切换,单独声明,这是个容器,用来记录每一行数字的乘积
for(var j=1;j<=i;j++){
cj = cj * j;
}
// console.log(cj);
sum = sum + cj; // 内层循环执行结束,拿到每个数字的乘积,累加到sum中
}
console.log(sum);
// ***
// *****
// *******
// *
// ***
// *****
// *******
// ***
// ***
// ***
// ***
// 1.分结构
// 两个三角形一个矩形组成
// 只要打出一个三角形,两个三角形都搞定了
// 矩形更不在话下
// 2.分三角形
// aaa*
// aa** *
// a*** **
// **** ***
// 2.1倒三角
// aaa
// aa
// a
// 2.2正三角
// *
// **
// ***
// ****
// 2.3正三角
//
// *
// **
// ***
// 3.逐个打印
// document.write("a")
// document.write("a")
// document.write("a")
// document.write("*")
// document.write("
")
// document.write("a")
// document.write("a")
// document.write("*")
// document.write("*")
// document.write("*")
// document.write("
")
// document.write("a")
// document.write("*")
// document.write("*")
// document.write("*")
// document.write("*")
// document.write("*")
// document.write("
")
// 4.减少代码冗余
// for(var i=0;i<3;i++){
// document.write("a")
// }
// for(var i=0;i<1;i++){
// document.write("*")
// }
// for(var i=0;i<0;i++){
// document.write("*")
// }
// document.write("
")
// for(var i=0;i<2;i++){
// document.write("a")
// }
// for(var i=0;i<2;i++){
// document.write("*")
// }
// for(var i=0;i<1;i++){
// document.write("*")
// }
// document.write("
")
// for(var i=0;i<1;i++){
// document.write("a")
// }
// for(var i=0;i<3;i++){
// document.write("*")
// }
// for(var i=0;i<2;i++){
// document.write("*")
// }
// document.write("
")
// 5.利用变量,将代码改成一致
// var j=0;
// for(var i=3;i>j;i--){
// document.write("a");
// }
// for(var i=0;i");
// j++;
// for(var i=3;i>j;i--){
// document.write("a")
// }
// for(var i=0;i")
// j++
// 6.最终的代码简化
for(var j=0;j<6;j++){
for(var i=6;i>j;i--){
document.write("a");
}
for(var i=0;i");
- 函数:由用户或自身控制,可以实现某个功能的 代码段(很多代码)
- 函数的特点:
- 忽略细节:在**使用过程**中,只需要关注其实现的功能,而不需要关注其内部原理
- 重复使用:多次使用
- 选择使用:按需使用
函数从哪来
- 内置(系统提供,公司发的)
- `parseInt()`
- `parseFloat()`
- `alert()`
- 自定义(自己写,自己给自己做)
- 声明式创建函数
- 需要配合关键字:`function`
- 语法:
function 函数名(){}
赋值式创建函数
需要配合关键字:`var`和`function`
var 变量名 = function(){}
函数其实就是一个变量,只不过内部存的是一段代码,这段代码还被一个容器包裹了
函数名()
通过事件执行
元素.事件 = function(){}
元素.事件 = 函数名
元素.事件 = function(){
函数|变量名()
}
根据写法分类
有名函数:
function 函数名(){}
var 变量名 = function(){}
无名函数:
function(){}
不允许直接存在于代码空间中,否则会报错
使用场景:
作为变量的值存在(赋值式创建函数时的值)
var 变量名 = function(){}
作为事件处理函数执行
btn.onclick = function(){
// 当事件被触发时要执行的内容...
}
匿名函数:
利用匿名函数解决全局耗性能,局部不方便的问题
;(function(){
})()
- 什么是参数
- 根据用户传入不同的参数,选择执行函数中不同的功能
- 参数的分类:
- 发:实参:函数执行时的参数
- 收:形参:函数定义时的参数
- 实参和形参的关系,赋值的关系,形参相当于变量,实参相当于值,一对一
- 数量对应关系
- 参数可以有很多个,语法上没有数量限制,但是行业有习惯,自定义函数,如非特殊需要,尽量不要超过3个
- 实参和形参数量一致:
- 按照顺序,一一对应
- 实参多:
- 没有形参接收,通过形参找不到
- 在函数内部有个神秘的空间(arguments),这个空间会将所有的实参全部保存,不论有没有被接收
- arguments是个对象类型的数据(类数组的数据)
- 长度(个数),表示接收到了几个实参
- `arguments.length`
- 索引(序号,编号),表示数组内部的数据位置,索引从0开始
- `arguments[索引]`
- 形参多:
- 多出来的形参是undefined
- 形参其实就是一个变量,实参是赋值,如果实参不够,表示没有赋值,undefined
/* 函数名.length 形参的数量 */
/* arguments.length 实参的数量*/
- 返回值概念
- 函数自身的处理数据或执行结果,需要被二次使用或其他程序调用时,需要将数据返回出来
- 如何拿到返回值
- 关键字:`return 要返回的数据`
- return的功能
- 可以让函数返回指定的**值**
- 可以立即结束当前函数
- 一个函数中可以写无数个,但是只能执行一次return,一次只能返回一个数据,不允许返回多个数据
- 返回到哪
- 返回到函数的执行语句
- 函数名(),既是在执行函数,也是在拿返回值
- **注意**
- 一个函数如果没有return,那么返回的是undefined;如果有return,那么返回值就是return后面的值
- 可以返回哪些数据
- 所有数据
- 当返回函数时,形成了闭包(后期概念)
- 什么时候需要返回值?
- 功能性函数(打印表格,改颜色)
- 可以有,但是没有必要有返回值
- 处理数据的函数(补零,计算器,计算圆的面积)
- 一般都有,返回数据
/ 鼠标类:
// 单击:click
// 双击:dblclick
// 按下:mousedown
// 抬起:mouseup
// 移动:mousemove
// 进入:mouseover / mouseenter
// 离开:mouseout / mouseleave
// 右键:contextmenu
// 键盘类:
// 按下:keydown
// 抬起:keyup
// 按下并抬起:keypress
// 表单类:
// 获取焦点:focus
// 失去焦点:blur
// 输入:input
// 内容改变:change
// 提交事件:submit
// 重置事件:reset
// 网页的特色事件
// 浏览器类:
// 加载:load
// 滚动:scroll
// 改变大小:resize
// 所有事件的绑定方式都是一致的
// 目前学习了一种:on绑定,赋值式绑定
// 元素.on事件名 = function(){}
- 谁作用的哪个区域
- 谁:数据(变量)
- 哪个:如何划分,函数就是一个区域
- 全局
- 不属于任何一个函数
- 全局作用域中的变量,叫全局变量
- 全局作用域中的函数,叫全局函数
- 生命周期:一直存在
- 耗性能,但是方便
- 少用全局
- 局部
- 任何一个函数内部都是局部作用域
- 局部作用域中的变量,叫局部变量
- 局部作用域中的函数,叫局部函数
- 生命周期:朝生暮死
- 节省内存,不方便
- 函数的参数(形参):是当前函数的局部变量
- 匿名函数
- 利用匿名函数解决全局耗性能,局部不方便的问题
- `(function(){})()`
- 当全局和局部的变量名重复时
- 读的规则:
- 向上级作用域查找,找到了,就使用,同时,停止查找;找到顶级作用域,都没有,**报错**
- 写(设置,赋值)的规则:
- 向上级作用域查找,找到了,就写入,同时,停止查找;找到顶级作用域,都没有,**会默认在顶级作用域声明这个变量,然后使用**
- 注意:声明变量时,必须加声明关键字,不加声明关键字,可能能执行,但是不规范
- 偏原理
- 可以不懂原理,只需要注意现象,可以正常写代码
- 懂原理,帮助你提升代码性能,优化;方便面试
- js是一门解释性语言
- 预先编译,再执行
- 先通读全文,在解释含义
- 找到var和function,做出对应提升
- 编译时
- **提升**
- 执行时
- 按照逻辑,结构正常执行
- var的提升
- 提前声明,=号的位置赋值
console.log(a); // undefined
var a = 10;
console.log(a); // 10
- ↑↑↑↑等价于↓↓↓↓
var a;
console.log(a); // undefined
a = 10;
console.log(a); // 10
/* window 和 全局作用域 */
/* (1) 默认全局作用域中所有的(var)变量和函数都会默认称为window的成员。 */
/* (2) 存在全局变量污染的问题,我们声明的全局变量可能在window中已经存在,而且它们有特殊的意义,会造成覆盖的问题。 */
- 整体提升
- 即提前声明,有提前赋值
- 如果var遇到function
1. 赋值式创建函数
var fn = fucntion(){}
- 提升的是var,不是function
2. 变量和函数重名
var a = "hello";
function a(){}
- var提升的更高,所以fnction占便宜,生效的是function
// 递:
// fn(5) = fn(5-1) + 1
// fn(4) = fn(4-1) + 1
// fn(3) = fn(3-1) + 1
// fn(2) = fn(2-1) + 1
// fn(1) = fn(1-1) + 1
// fn(0) = 0
// 归:
// fn(5) = 4 + 1
// fn(4) = 3 + 1
// fn(3) = 2 + 1
// fn(2) = 1 + 1
// fn(1) = 0 + 1
// fn(0) = 0
function fn(a){
// if(a === 1){
// return 1;
// }else{
// return a * fn(a-1);
// }
// }
// console.log(fn(10));
/* 构造函数创建对象:过程(细节) */
function Person(name, age) {
/* (1) 新创建空对象 */
/* let o = {} o.__proto__ -> Object.prototype */
/* (2) 设置(修改)该对象的原型对象 */
/* o.__proto__ = Person.prototype */
/* (3) 把 o 绑定给 this */
/* this = o */
/* (4) 通过 this 来给实例对象添加属性或者是方法 */
this.name = name || "张三";
this.age = age || 18;
/* (5) 默认总是会把内部新创建的实例对象返回 */
// return this;
/* 注意点: */
/* 如果没有写 return 语句,那么默认总是会把内部心创建的实例对象返回 */
/* 如果主动写 return 语句 */
/* A:return 值类型的数据 忽略*/
/* B: return 引用类型的数据 替换(覆盖) */
return [1, 2, 3, 4];
// return {};
// return 123;
}
let p = new Person("老王")
console.log(p);
/* 需求:要求自己实现函数 mockNew(Person,"老王",44); */
function mockNew(constructor) {
let args = Array.from(arguments).slice(1);
// console.log("args", args)
let o = {};
o.__proto__ = constructor.prototype;
let result = constructor.call(o, ...args); /* 修改函数内部的 this */
return result instanceof Object ? result : o;
}
let p1 = mockNew(Person, "老王", 44);
console.log("p1", p1);
- 其实就是一种**事物的描述**,在程序中对象是一种数据类型
- 描述水杯:
- 材质:塑料
- 容量:1000ml
- 颜色:白色
- 形状:圆形
- 功能:容器
- 把以上信息,组合打包用来表示一件事物,之后,就叫对象
- 程序中的对象主要用来:存储信息
- 字面量
var o1 = {}
- 构造函数
var o2 = new Object();
- 意义(功能)
- 存储数据(信息)
- 编程(面向对象编程)
- 本质
- 键值对
- 点语法(.)
- 对象.属性名
var o = {};
- 读
console.log(o.name);
- 写
o.name = "Admin";
o.age = 18;
o.sex = "男";
o.sayHello = function(){
console.log("你好,我叫:" + obj.name);
}
- 字面量创建对象时,可以很方便的立即写入初始属性
var obj = {
name: "Admin",
age: 18,
sex: "男",
sayHello:function(){
console.log("你好,我叫:" + obj.name);
}
};
- 注意:**任何两个对象都不相等**
- 如果相等了,意味着就是一个对象
用于不确定的属性名,当属性名是变量时
// 操作:
var obj = {
name:"admin",
age:18,
sex:"男"
};
// 点语法:.
// 只能访问固定的属性名,不能使用变量作为属性名
console.log(obj.name);
obj.name = "admin";
console.log(obj.name);
// 中括号语法:[]
// 属性名为变量时,属性名为不确定的值时
var attr = "name";
console.log(obj[attr]);
// 属性名为具体的值,不是变量时,也可以用[]语法,但是这个值必须用引号包裹
console.log(obj["name"]);
console.log(obj['age']);
console.log(obj['sex']);
for(var i in obj){
i就是obj中的所有属性名
思考:如何根据属性名获取属性值
提示:中括号语法
}
var obj = {
a:10,
b:20,
c:30,
name:"admin",
age:18,
sex:"男",
d:function(){},
e:true,
f:null,
g:{
a:"hello"
}
}
// for-in不是循环,是一个遍历语句,遍历对象
// 枚举对象所有的属性,根据枚举出的属性,获取属性值
for(var i in obj){
console.log(obj[i]);
}
// 小提示:数组也是对象
// for-in可以遍历对象,可不可以遍历数组?
// var arr = ["hello",4,5,6,"world"];
// for(var i in arr){
// // console.log(i);
// console.log(arr[i]);
// }
// 意味着数组的遍历,也多了一种方式,但是,建议,for-in一般用来遍历非数组对象
- 数据的组合,一组数据
- 当需要操作多个数据时,可以给数据打包,数组
- 数组其实也是对象,只是存储数据的形式不一样,但是类型是一样的
- 字面量
var arr1 = [];
- 构造函数
var arr2 = new Array();
- 区别
- 当字面量内只有一个数值型数据时,表示一个数据
- 当构造函数内只有一个数值型数据时,表示长度
- 注意区别,按需选择,顺手
- 数组是一个有序数据的集合
- 有序的序号,索引
- 从0开始
- 到哪结束
- 根据长度,得出,到length-1
- 数组的第一个:数组[0]
- 数组的最后一个:数组[数组.length-1]
- 增
- 增加数组的长度
- 给不存在的位置赋值
arr[arr.length] = "哈哈哈"
- 删
- 缩短数组的长度
// 原有长度是5
arr.length = 3;
- 改 ******
- 找到对应索引的数据,赋值(覆盖)
arr[要修改数据的索引] = "四";
- 查 ******
- 根据索引直接获取
arr[指定位置的索引]
https://www.jianshu.com/p/7e160067a06c
//1.push
push方法
1.功能:最后的位置新增
2.参数:要增加的数据,可以是多个
3.返回值:数组增加之后的长度
4.是否修改原数组:是
var res = arr.push("aaa","bbb")
console.log(res);
//2.unshift
unshift方法
1.功能:开始的位置新增
2.参数:要增加的数据,可以是多个
3.返回值:数组增加之后的长度
4.是否修改原数组:是
var res = arr.unshift("aaa","bbb")
console.log(res);
//3.pop
pop方法
1.功能:删除最后一位
2.参数:无
3.返回值:删除的数据
4.是否修改原数组:是
var res = arr.pop()
console.log(res);
//4.shift
shift方法
1.功能:删除第一位
2.参数:无
3.返回值:删除的数据
4.是否修改原数组:是
var res = arr.shift()
console.log(res);
//5.join
join方法
1.功能:将数组转成字符
2.参数:转成字符之后,每个数据之间的间隔符
3.返回值:转换结果
4.是否修改原数组:否
var res = arr.join("");
console.log(res);
console.log(typeof res);
字符的长度还没讲
//6.splice
splice方法
1.功能:删除并替换指定位置的数据
2.参数:
两个:1起始索引,2个数,不插入数据,只删除
两个以上:1起始索引,2个数,删除,并,后面都是要插入的数据
3.返回值:删除了的数据
4.是否修改原数组:是
var res = arr.splice(2,1); // 从第2个位置开始删除1个
var res = arr.splice(2,1,"aaa","bb","ccc"); // 从第2个位置开始删除1个后,插入后面的数据
var res = arr.splice(2,0,"aaa","bb","ccc"); // 从第2个位置开始删除0个后,插入后面的数据
var res = arr.splice(2,2); // 从第2个位置开始删除2个
console.log(res);
//7.slice
slice方法
1.功能:截取并拷贝出子数组
2.参数:
一个:表示从指定位置开始截取,到结束
两个:表示从指定位置到结束位置的前一个
3.返回值:截取并拷贝出来的新数组
4.是否修改原数组:否
var res = arr.slice(1,4);
console.log(res);
console.log(arr);
-----------------------
var arr = ["hello",3,4,5,"world"];
console.log(arr);
//8.concat
concat方法
1.功能:将数据合并到新数组并返回
2.参数:任何数据,如果是数组的话,会被展开再合并进去
3.返回值:合并之后的新数组
4.是否修改原数组:否
var res = arr.concat([4,5,6]);
console.log(res);
//9.reverse
reverse方法
1.功能:翻转数据
2.参数:无
3.返回值:翻转之后的数组,就是修改之后的原数组
4.是否修改原数组:是
var res = arr.reverse();
console.log(res);
console.log(res == arr); // true
console.log(arr);
-------------------
var arr = [7,4,328,6,1048,9];
console.log(arr);
//10.sort
sort方法
1.功能:排序;默认排序规则是字符的比较规则,升序
2.参数:函数:function(m,n){return n-m;} m-n数值升序,n-m数值降序
3.返回值:排序之后的数组
4.是否修改原数组:是
var res = arr.sort(function(m,n){
return n-m;
});
数值数组
var arr = [3,4,5,7,2,3];
字符数组
var arr = ["a","b","c"];
布尔数组
var arr = [true,false];
对象数组(json数组)
var objArr = [{name:"admin"},{name:"root"},{name:"liyang"}]
数组数组(二维数组)
var twoArr = [[3,5,6,7,4],["a",true,"b"],["hello","world"]];
访问方式(操作方式)
JSON数组
逐层解析
var objArr = [{name:"admin"},{name:"root"},{name:"liyang"}];
指定数据
console.log(objArr[1].name); // root
所有数据
for(var i=0;i<objArr.length;i++){
console.log(objArr[i].name);
}
二维数组
var twoArr = [[3,5,6,7,4],["a",true,"b"],["hello","world"]];
// 指定数据
// console.log(twoArr[2][0]);
// 所有数据
for(var i=0;i<twoArr.length;i++){
// console.log(twoArr[i])
for(var j=0;j<twoArr[i].length;j++){
console.log(twoArr[i][j]);
}
}
// 手动数组排序
// 实际用处不太大
// 因为数组有自己的排序方式
// 但是,逻辑思路很重要
// 数组的排序对应了排序算法
// 简单的排序
// var arr = [9,8,7,6,5];
// console.log(arr);
// 不用sort
// 自己写
// 升序
// 接下来我表示的是索引(下标)
// 0-1,1-2,2-3,3-4
// [8,7,6,5,9]
// // 比完之后,排了什么,排了最后一个必然是最大值
// 0-1,1-2,2-3
// [7,6,5,8,9]
// // 比完之后,排了什么,排了倒数第二个必然是倒数第二大的值
// 0-1,1-2
// [6,5,7,8,9]
// // 比完之后,排了什么,排了倒数第三个必然是倒数第三大的值
// 0-1
// [5,6,7,8,9]
// // 比完之后,排了什么,排了倒数第四个必然是倒数第四大的值
// 以下结构是比较次数和哪些索引进行比较
// 0-1,1-2,2-3,3-4
// 0-1,1-2,2-3
// 0-1,1-2
// 0-1
// 多行多列
// 循环的嵌套
// 外层循环控制行
// 内层循环控制列
var arr = [9,8,7,6,5];
console.log(arr);
for(var i=0;iar[j+1]){
var ls=arr[j];
arr[j]=arr[j+1];
arr[j+1]=ls;
}
}
}
console.log(arr);
// // 思路:拿第一位和后面所有作比较,找到最小的,放在第一位
// 0-1,0-2,0-3,0-4
// [5,8,9,6,7]
// // 第一轮结束后,第一个位置必然是最小的
// // 思路:拿第二位和后面所有作比较,找到最小的,放在第二位
// 1-2,1-3,1-4
// [5,6,9,8,7]
// // 第二轮结束后,第二个位置必然是第二小的
// // 思路:拿第三位和后面所有作比较,找到最小的,放在第三位
// 2-3,2-4
// [5,6,7,8,9]
// // 第三轮结束后,第三个位置必然是第三小的
// // 思路:拿第四位和后面所有作比较,找到最小的,放在第四位
// 3-4
// [5,6,7,8,9]
// // 第四轮结束后,第四个位置必然是第四小的
// 一共有5个数据,确定了前四个,最后一个不需要比了
// 以下结构是比较次数和哪些索引进行比较
// 0-1,0-2,0-3,0-4
// 1-2,1-3,1-4
// 2-3,1-4
// 3-4
for(var i=0;i arr[j]){
// ls里面的数据如果大了,换成小的
// 因为在找最小的
ls = arr[j];
// 如果ls里面的数据换了,lsIndex也跟着换
lsIndex = j;
}
}
// ls必然已经是最小的了
// 交换数组中的数据
// 先把真正的第一位拿走,否则会被覆盖
// 放到真正的最小值的位置
arr[lsIndex] = arr[i];
// 再把ls变量中,最小的值,放在第一位
arr[i] = ls;
}
// 按照从左到右的顺序,依次取出每个数据,后后面所有数据做比较,找到最小值,交换
// 选择排序
var arr = [9,8,5,6,7];
console.log(arr);
for(var i=0;iarr[j]){
ls=a[j];
lsIndex=j;
}
}
arr[lsIndex]=arr[i];
arr[j]=ls;
}
- 字面量
var str = "";
var str = '';
var str = ``;
- 构造函数
var str = new String();
- 构造函数创建的字符,类型是object,但是可以使用正常的字符操作
- 字符和数组一定要区分开来,压根就不是一回事,仅仅是操作类似
- 索引和长度
- length
- 下标,序号,编号
- 只能读,不能写
var str = "hello world";
console.log(str);
// 所有的字符,都可以叫字符串,每个字符的索引
// console.log(str[0]);
// console.log(str[1]);
// console.log(str[2]);
// console.log(str.length);
// for(var i=0;i
var str = "hello world";
//1.indexof
indexOf()
功能:根据指定子串,从左向右查询字符,查询索引
参数:1要查询的子串,2从哪个索引开始查询,可选
返回值:索引 或 -1(没有查找到)
是否改变原字符:否
var res = str.indexOf("w");
var res = str.indexOf("a");
var res = str.indexOf("w",7);
var res = str.indexOf("l",4);
var res = str.indexOf("l",2);
console.log(res);
//2.slice
slice()
功能:截取
参数:1开始的位置,2结束的位置(不包括),可选
返回值:截取到的子串
是否改变原字符:否
var res = str.slice(2,7);
var res = str.slice(2);
console.log(res);
//3.substr
substr()
功能:截取
参数:1开始的位置,2个数,可选
返回值:截取到的子串
是否改变原字符:否
var res = str.substr(2,7);
var res = str.substr(2);
console.log(res);
//4,substring
substring()
功能:截取
参数:1开始的位置,2结束的位置(不包括),可选
返回值:截取到的子串
是否改变原字符:否
var res = str.substring(2,7);
var res = str.substring(2);
console.log(res);
//5.split
split()
功能:分割字符成数组
参数:按照什么字符分割
返回值:分割后的数组
是否改变原字符:否
var res = str.split("o");
var str = "2020.4.30 14:30:50"
var str = "2020|4|30"
var res = str.split(".");
console.log(res);
//6.charAt
charAt()
功能:根据索引取字符
参数:索引
返回值:取到的字符,没有取到,就是空字符:""
是否改变原字符:否
var res = str.charAt(4);
var res = str.charAt(24);
console.log(res);
//7.lastInexof
lastIndexOf()
功能:从右向左查询字符,返回索引
参数:要走查找的子串
返回值:索引,或-1
是否改变原字符:否
var res = str.lastIndexOf("l");
console.log(res);
//8.concat
concat()
功能:合并字符
参数:要合并的字符
返回值:合并之后的字符
是否改变原字符:否
var res = str.concat("admin");
console.log(res);
//9.toUpperCase
toUpperCase()
功能:转大写
参数:无
返回值:转换之后的字符
是否改变原字符:否
var res = str.toUpperCase();
console.log(res);
//10.toLowerCase
toLowerCase()
功能:转小写
参数:无
返回值:转换之后的字符
是否改变原字符:否
var str = "HELLO 你好";
var res = str.toLowerCase();
console.log(res);
//11.repalce
replace()
功能:替换. 后续敏感词过滤
参数:1老字符,2新字符
返回值:替换之后的字符
是否改变原字符:否
var res = str.replace("o","啊");
res = res.replace("o","啊");
console.log(res);
//12.triem
作用:清除字符串前后的1个或者多个空格
内存
- 用来运行数据的控件,内部有区分了不同的存储方式
- 栈:一般用来存储变量名和地址,空间小,稳定,不可修改
- 堆:一般用来存储数据,空间大,可被修改
- 关系:一一对应,多对一,不能一对多
- 存取规则:
- 栈:先进后出:杯子
- 堆:先进先出:掉底的杯子
数据类型的分类
数据类型的存储形式:js中的数据类型的分类,只有两种。
// 改变新的不影响老的:基本(一般)类型(值传递的数据)
// 除了对象,函数
// 改变新的影响老的:引用(复杂)类型(引用传递的数据)
// 对象,函数
- 基本类型(值传递)
- 数据就在栈中
- 不存在深浅拷贝,默认就是深拷贝
- 引用类型(引用传递的数据)
- 栈中只保存了一个地址,地址指向堆中的某个数据
- 存在深浅拷贝,默认是浅拷贝
- 目前会有一些影响
- 如何实现深拷贝?
//浅拷贝
/* 对象的拷贝 */
// let o1 = {
// name: "zs",
// age: 18,
// car: {
// id: 666,
// color: "red",
// }
// };
// let o2 = {};
/* 浅拷贝:拷贝的时候只会拷贝一层,可能存在共享的关系 */
/* 深拷贝:拷贝的时候逐层拷贝,不存在共享的关系 */
/* 浅拷贝实现方式: */
/* (1) 遍历的方式逐个拷贝 */
// for (let key in o1) {
// o2[key] = o1[key];
// }
// o1.car.id = 888;
// console.log(o1, o2, o1.car === o2.car);
/* (2) Object.assign() 拷贝合并对象*/
/* Object.assign(target,source1,source2,source3...) */
/* 把source1 source2 source3... 对象成员都添加到target上面 */
// Object.assign(o2, o1, {
// address: "广州"
// });
// o1.car.id = 9999;
// console.log(o1, o2);
/* 深拷贝 */
/* (1) 利用 JSON.parse(JSON.stringify()) */
/* 问题1:因为JSON字符串中没有undefined 和 函数,所以如果拷贝的对象内部包含了undefined 值或者是函数 */
/* 问题2:如果拷贝的是正则表达式,那么拷贝完后得到的仅仅是{} */
/* (2) 封装函数deepCopy 递归 */
let o1 = {
name: "zs",
age: 18,
car: {
id: 666,
color: "red",
},
className: undefined,
show() {},
reg: /abc/,
};
/*JSON.stringify() 把对象转换为JSON字符串 (序列化) */
/*JSON.parse() 把JSON字符串转换为对象 (反序列化) */
/* JSON字符串主要用来进行网络通信 是数据的表示和传输的格式(XML | JSON)。 */
/* JavaScript提供JSON 对象,ES5提供(ECMAScript) */
// let json = JSON.stringify(o1);
// console.log(json);
// let obj = JSON.parse(json);
// console.log(obj);
let o2 = JSON.parse(JSON.stringify(o1));
console.log(o2);
o1.car.color = "#000";
console.log(o1, o2)
let deepClone = (val, wm = new WeakMap) => {
if (val == null) return val;
if (typeof val !== "object") return val;
if (val instanceof Date) return new Date(val);
if (val instanceof RegExp) return new RegExp(val);
if (wm.has(val)) return wm.get(val);
let _instance = new val.constructor;
wm.set(val, _instance);
for (let key in val) {
if (val.hasOwnProperty(key)) _instance[key] = deepClone(val[key], wm);
}
return _instance;
}
window
- 全局对象,所有的全局内容,都可以在window身上找到
- 一般情况下,window可以被省略
this
- 函数内的关键字
- 表示当前函数的执行上下文(执行对象)
- **谁执行了this所在的函数,this就是谁**
- 应用慢慢来,先记,规律,先测,规律
- 什么是ES5,ECMAScript5
- ES的版本更新,向下兼容,老版本并没有全部废弃,新版本只是在老版本的基础上新增
- 严格模式:更严格的开发模式
- js的代码规范非常不严格,所以严格模式的意义是:
- 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为未来新版本的Javascript做好铺垫
- 严格模式的开启方式
- 在作用域开始的位置,加上一行字符串:"use strict";
- 局部严格
- 安全,但不方便,麻烦
- 全局严格
- 不安全
- 配合匿名函数
- 利用父子作用域,本质是局部,但实现了全局的方便
#####
- 严格模式开启之后的变更
1. 声明变量必须加关键字(var)
2. 不允许参数名重复
3. 没有明确隶属对象的函数中的this(执行了)指向undefined
4. arguments的内容不会被形参的改变而影响
5. arguments.callee被禁止使用
- 记忆性知识点,改了就改了,没有商量的余地
forEach
功能:遍历数组
参数:函数,这个函数自带三个形参,1数据,2索引,3数组自身
返回值:undefined
是否修改原数据:否
var res = arr.forEach(function(val,idx,self){
console.log(val,idx,self);
})
console.log(res);
map
功能:1遍历数组,2修改数据
参数:函数,这个函数自带三个形参,1数据,2索引,3数组自身
返回值:数组,中的数据是:每次遍历到数组中数据时的返回值
是否修改原数据:否
var res = arr.map(function(val,idx,self){
console.log(val,idx,self);
return val *= 1.3;
})
console.log(res);
filter
功能:1遍历数组,2过滤数据
参数:函数,这个函数自带三个形参,1数据,2索引,3数组自身
返回值:数组,中的数据是:每次遍历到数组中数据时的返回值,为true时的值
是否修改原数据:否
var res = arr.filter(function(val,idx,self){
console.log(val,idx,self);
return typeof val === "number";
})
console.log(res);
some
功能:1遍历数组,2检测所有数据(只要有一个返回true,就是true,同时停止遍历)
参数:函数,这个函数自带三个形参,1数据,2索引,3数组自身
返回值:布尔值,遍历数组中数据时,只要有一个返回true,就是true,同时停止遍历
是否修改原数据:否
var res = arr.some(function(val,idx,self){
console.log(val,idx,self);
return val === 4;
})
console.log(res);
every
功能:1遍历数组,2检测所有数据(必须所有返回true,才是true)
参数:函数,这个函数自带三个形参,1数据,2索引,3数组自身
返回值:布尔值,遍历数组中数据时,必须所有返回true,才是true,只要有一个false,就是false,停止遍历
是否修改原数据:否
var res = arr.every(function(val,idx,self){
console.log(val,idx,self);
return true;
})
console.log(res);
reduce
功能:1遍历数组,2归并
参数:
1.函数,这个函数自带四个形参,1上一个值,2数据,3索引,4数组自身
2.指定默认情况下 的 上一个值↑;如果没有指定,上一个值,默认找数组的第一个数据
返回值:最后一个遍历的返回值
是否修改原数据:否
var res = arr.reduce(function(prev,val,idx,self){
console.log(prev,val,idx,self);
return "返回给了下次执行时的prev";
},"prev的默认值,如果没有,prev找数组的第一个数据")
console.log(res);
案例:利用reduce实现数组中所有数据的累加
var arr = [2,3,4,5,6,7];
var res = arr.reduce(function(prev,val,idx,self){
return prev + val;
})
console.log(res);
思想:调错思想
工具:打断点
1.程序有报错,结果没出来
1.观察报错
2.根据报错找到指定行号
3.观察哪错了
3.1不一定是报错行号的代码有问题,有可能是之前的问题,在此行暴露
3.1.1向上查找来源
3.1.2定位真正的问题所在
3.2找来源
4.修改正确
2.程序有报错,但结果出来了,可是不对
1.观察报错
2.根据报错找到指定行号
3.观察哪错了
4.找到最终结果
5.向前反推
6.观察数据的来源
7.根据数据的来源,计算规则
8.观察程序的执行过程和代码是否正确
9.修改正确
3.程序无报错,但结果出来了,可是不对
1.找到最终结果
2.向前反推
3.观察数据的来源
4.根据数据的来源,计算规则
5.观察程序的执行过程和代码是否正确
6.修改正确
4.程序无报错,结果没出来
1.重新写:
1.1至少可以将思路捋一遍
1.2再重新写
2.反推:要求对当前程序的了解程度非常高
...
观察工具:
判断当前位置的代码是否执行:console.log(1);
一定要在报错行号上面打印,因为报错会阻塞程序执行
判断当前变量或数据是否正常:console.log(变量或数据)
一定要在报错行号上面打印,因为报错会阻塞程序执行
逐行执行代码:
打断点,让代码逐行执行
1.关键字:debugger
2.利用浏览器的控制台
仅仅是让代码逐行执行,并不能告诉我们哪里错了,只是看到执行过程
根据自身对当前程序的了解,判断程序的执行
- 内置对象:
- ES提供可以直接被使用的对象,已经是一个具体的实例了,不需要创建
- Math对象,数学对象
- 本地对象:
- 其实只是ES提供的一种类方法,需要被实例化之后,才能使用
- 需要被new执行之后,才能使用
- String,Object,Array,Number,Boolean,RegExp,Date
- 宿主对象:
- 由浏览器或W3C提供的运行ES的环境,所带的对象
- BOM:window,DOM:document
补充关键字:delete,用来删除自定义对象的属性
- delete
- `delete 对象.属性名`;
- 只能删除自定义对象的属性,且一次只能删一个属性
- 建议:少用
Math数学对象,不需要数学知识支撑,使用这个对象直接得到想要的结果
- Math 是 js 的一个内置对象,提供了一堆的方法帮助我们操作数字
- 属性
- Math.PI
- 圆周率
- 方法
- Math.random()
- 随机数,随机产生0-1之间的数,不包括0,1
- Math.round()
- 取最近的整数
- Math.ceil()
- 向上取整
- Math.floor()
- 向下取整
- Math.max()
- 参数是多个数字,求最大数字
- Math.min()
- 参数是多个数字,求最小数字
- Math.pow(底数,指数)
- 求幂
- Math.sqrt()
- 开根号
- Math.abs()
- 求绝对值
- Math.sin(弧度)
- 正弦
- Math.cos(弧度)
- 余弦
- .....
- console.log(Math);
Math.floor(Math.random() * (max-min+1) ) + min
- 十进制是日常使用进制,是数值型数据
- 其他进制,如:十六进制中含有abcdef,所以需要用字符的形式表示
- 其实就是将数值转成字符
- num.toString(需要转成的进制)
var num = 234;
console.log(num);
var er = num.toString(2);
console.log(er);
var ba = num.toString(8);
console.log(ba);
var sl = num.toString(16);
console.log(sl);
- 其他都使用字符表示
- 其实就是将字符转成数值
- parseInt(要转换的数据, 作为哪个进制转换)
var str = "101010";
//第一个参数是需要转的字符,第二个参数是告诉你是 什么进制 转 十进制
console.log(parseInt(str, 2)); // 42
console.log(parseInt(str, 8)); // 33288
console.log(parseInt(str, 16)); // 1052688
console.log(parseInt(str, 10)); // 101010
console.log(parseInt(str)); // 101010
- 利用十进制做过渡
- u编码:得到的直接就是十进制,被系统自动转了
- 颜色值
Date日期对象,用来获取当前系统日期
是本地对象,本地对象的特点是不能直接使用,这仅仅是个类方法(类似于函数),需要new执行后才能使用
创建日期对象
系统的默认日期
var d=new Date();
var d=new Date();
var year = d.getFullYear();
var month = d.getMonth(); // 0~11
var myDate = d.getDate();
var day = d.getDay(); // 0~6
var hours = d.getHours();
var minutes = d.getMinutes();
var seconds = d.getSeconds();
var millS = d.getMilliseconds();
- 需求:计算北京奥运会距离今天过去了多少天?
- 过去的日期怎么拿?设置指定日期
- 如何设置
- 直接设置
- 简单粗暴,但必须整体设置
- `new Date(要设置的数据)`
字符:一个参数,直接设置,不允许日期溢出,否则会无效的日期,没有设置的部分,为0 月份1-12
var d = new Date("2008.8.8");
var d = new Date("2008/8/8");
var d = new Date("2008-8-8");
var d = new Date("2008,8,8");
var d = new Date("2008 8 8");
var d = new Date("2008.14.8 8:8");
var d = new Date("2008.8.8 8:8");
数值:多个参数,直接设置,月份从0开始,日期溢出,向前进1,没有设置的部分,为0 月份0-11
var d = new Date(2008,8,8);
var d = new Date(2008,7,8);
var d = new Date(2008,15,8);
var d = new Date(2008,15,8);
var d = new Date(2008,15,8,20,8,8);
通过方法设置,繁琐,但可以针对性设置,没有设置的部分,采取当前日期,月份从0开始,溢出部分,向前进1
d.setFullYear(2008);
d.setMonth(14);
d.setDate(8);
d.setHours(8);
d.setMinutes(8);
d.setSeconds(8);
d.setMilliseconds(666);
还可以独立设置时间戳
d.setTime(从1970.....到要设置的日期的毫秒数)
/* d.getTime() */
/* d.valueOf() */
/* Date.now() */
单独设置,采取日期对象的系列方法:set系列
没有设置的部分,采取当前日期,月份从0开始,溢出部分,向前进1
var d = new Date();
console.log(d)
d.setFullYear(2008);
d.setMonth(14);
d.setDate(8);
d.setHours(8);
d.setMinutes(8);
d.setSeconds(8);
d.setMilliseconds(666);
console.log(d)
console.log(d.getMilliseconds());
通过时间戳直接设置日期
var d = new Date();
d.setTime(1000000000000);
console.log(d);
1. 概念
- BOM:浏览器对象模型,是个模型,这个模型由一个对象window来体现(具象)
- 作用:
- 提供了ES和页面的运行环境
- 浏览器的一些规定,首先需要在ES的基础之上设置,但是最终生效时,以浏览器的标准为主
- 浏览器的规范没有涉及到的范围,使用ES的规范
- 宪法:ES,地方法规:浏览器的规定
- 兼容:
- 不是兼容问题的兼容问题:
- alert(1);
- 功能一致,没有兼容
- 每个浏览器显示的样式都不一样
2. window的具体功能和作用
- window:窗口
- window提供的窗口 或 窗口与窗口之间的操作
- 因为所有内容都运行在浏览器中,所以,window也是**浏览器的js**中的顶层(大boos)对象
- 所有的全局变量和函数,都属于window
- window在使用过程中可以省略
- 注意,严格模式下,全局函数如果省略window,会导致全局函数中的this指向undefined
- 弹出信息框:alert() // 弹出信息框
- 弹出对话框:prompt() // 弹出对话框 返回值:确定:输入的信息;取消:null
- 弹出选择框:confirm() //弹出选择框 返回值:确定:true 取消:false
- 注意原理,将来会使用html+css+js模拟
- open()
- close()
- 注意:
- 尽量配合行为适用,不要直接执行
- 而且某些浏览器还有兼容性
// 有兼容,某些浏览器不支持
// open(); // 打开指定地址的新窗口
// close(); // 关闭当前窗口
// 火狐浏览器要求:不允许关闭非脚本(js)打开的页面
// javascript就是一个脚本语言
// document.onclick = function(){
// open("http://www.baidu.com")
// }
// document.onclick = function(){
// if(confirm("你真的要关闭当前页面吗?")){
// close();
// }
// }
1. - 计时器(定时器)(重复执行)
- 开
- setInterval()
- 功能:每隔参数2的时间,执行一次参数1的函数
- 参数:参数1:函数;参数2:毫秒数
- 返回值:当前计时器的唯一标志,是个数值,只有一个作用:用来清除当前计时器!!!
- 是否改变原数据:否
var t = setInterval(function(){
console.log("hello");
}, 1000);
- 关
- clearInterval()
- 功能:用来关闭计时器
- 参数:要关闭的计时器的返回值 所在的变量!切记,变量!
- 返回值:无
- 是否改变:否
document.onclick = function(){
clearInterval( t );
};
- 延时器(延迟,一次)
- 开
- setTimeout()
- 功能:延迟 参数2的时间,执行一次参数1的函数
- 参数:参数1:函数;参数2:毫秒数
- 返回值:当前延时器的唯一标志,是个数值,只有一个作用:用来清除当前延时器!!!
- 是否改变原数据:否
var t = setTimeout(function(){
console.log("hello");
}, 5000);
- 关
- 功能:用来关闭延时器
- 参数:要关闭的延时器的返回值 所在的变量!切记,变量!
- 返回值:无
- 是否改变:否
clearTimeout()
- window浏览器事件
- load:加载
- window.onload不仅是页面的加载,还在等待资源的加载
- document.onload仅仅是页面的加载
- resize:改变大小
- scroll:滚动
- 语法:
- 事件源.on事件名 = 事件处理函数
- 如:btn.onclick = function(){}
- 如:window.onlaod = funciton(){}
- 如:onlaod = funciton(){}
// 获取页面尺寸:宽,高
// 可视区域的大小,可以配合resize使用
// console.log(document.documentElement.clientWidth)
// console.log(document.documentElement.clientHeight)
// 获取滚动条,滚动的距离(滚走的距离),可以配合scroll使用
// console.log(document.documentElement.scrollTop)
// console.log(document.documentElement.scrollLeft)
- 控制浏览器的**前进后退刷新**等于历史记录相关的功能
- 不方便在代码中临时测试,所以在浏览器打开其他页面测试
- 属性:
- 历史记录的个数:history.length
- 方法:
- 前进:history.forward()
- 后退:history.back()
- 前进或后退指定的步数:history.go(num); num为正前进,为负后退,0刷新
- 控制浏览器的**地址栏的内容**
- 不方便在代码中临时测试,所以在浏览器打开其他页面测试
- 属性:
- 既可以获取又可以设置:当前页面的地址,设置之后,页面会自动跳转
- js实现跳转的方式:
- location.href
- 既可以获取也可以设置:当前页面地址中向后台发送的数据部分(?后的部分),页面也会跳转
- location.search
- 既可以获取也可以设置:当前页面地址的锚点连接(哈希值,#后的部分),页面也会跳转
- location.hash
- 方法:
- 重新加载当前地址,意味着刷新了
- location.reload()
- 跳转方法,必须传参,空字符刷新,指定地址会跳转
- location.assign("")
- 以下测试是在Mac OS X 10_15_4系统的Chrome/81.0.4044.129浏览器进行的测试
- navigator.userAgent:浏览器信息
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
- navigator.appName:浏览器名字(废弃)
- "Netscape"
- navigator.appVersion:浏览器版本
- "5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
- navigator.appCodeName:浏览器内核
- "Mozilla"
- navigator.platform:运行系统
- "MacIntel"
需要配合iframe标签使用
<iframe src="http://www.baidu.com" width="500" height="300" style="border:solid 2px black;">iframe>
<iframe src="http://www.qq.com" width="500" height="300" style="border:solid 2px black;">iframe>
获取页面的可视(看得见的区域)区域的大小
获取滚走的了距离
/* window 和 全局作用域 */
/* (1) 默认全局作用域中所有的(var)变量和函数都会默认称为window的成员。 */
/* (2) 存在全局变量污染的问题,我们声明的全局变量可能在window中已经存在,而且它们有特殊的意义,会造成覆盖的问题。 */
/* 关键:window.name 是默认存在的,它的类型必须是字符串。 */
// var name = "zs"; /* 该行代码会覆盖window原先的name */
// console.log(name);
// name = [10, 20, 30]; /* [10,20,30].toString()->"10,20,30" */
// console.log(typeof name, name);
// name = {
// age: 18
// };
// console.log(name); /* {}.toString() "[object Object]" */
/* window.length 有特殊含义:iframe标签个数 */
// var length = 3;
// console.log(length, window.length);
js的三大组成部分的关系
- ECMAScript规定,如何在BOM中操作DOM
DOM文档对象模型,对象:document
- DOM(W3C机构)不属于BOM(浏览器厂商)
- window对象身上有提供document对象
- DOM,主要控制页面(html文件),所有的页面操作都需要通过DOM
- DOM的结构:html的结构:树形结构,包含结构,家族结构(父子级,兄弟级)
- html根元素:head,body
- DOM树形结构,的每个组成部分,都叫节点(元素,属性,注释,文本)
- 所有节点,都是对象
- js做交互,行为,页面(DOM),哪个元素,选择器,属性,内容,样式,元素等等
直接选择器
- id选择器:document.getElementById("id名")
- class选择器:document.getElementsByClassName("class名")
- tag选择器:document.getElementsByTagName("tag名")
- name选择器:document.getElementsByName("name名")
- ES5新增选择器:
- querySelector选择器:document.querySelector("css选择器")
- querySelectorAll选择器:document.querySelectorAll("css选择器")
- 总结:
- 返回单个元素:
- id,querySelector
- 返回数组:
- class,tag,name,querySelectorAll
- - 关系选择器:先有基准元素
- 父子关系(母女关系)
- 父选子:先拿到父
// 父选子:先拿到父
var olist = document.querySelector(".list");
// var olist = document.getElementsByClassName("list")[0];
console.log(olist);
// 第一个子:
console.log(olist.firstElementChild);
// 最后一个子:
console.log(olist.lastElementChild);
// 所有子:
console.log(olist.children);
// 其他的子:
console.log(olist.children[索引]);
- 子选父:先拿到子
// var oEm = document.querySelector("em");
var oEm = document.getElementsByTagName("em")[0];
// 子选父:一个!直接的父级!
console.log(oEm.parentNode);
console.log(oEm.parentNode.parentNode);
- 兄弟关系(姐妹关系)
// 先选择当前
var olist = document.querySelector(".list");
- 哥:谁的哥(上一个兄弟)
// 上一个(哥):
console.log(olist.previousElementSibling);
- 弟:谁的弟(下一个兄弟)
// 下一个(弟):
console.log(olist.nextElementSibling);
节点选择器(元素,属性,注释,文本)
元素,注释,文本,参与了父子或兄弟关系
- 利用关系选择
//父子关系
父元素节点.firstChild 第一个
父元素节点.lastChild 最后一个
父元素节点.childNodes 所有
// 兄弟关系
// 上一个兄弟节点
console.log(obox.previousSibling) // 现在是所有节点
// 下一个兄弟节点
console.log(obox.nextSibling)
- 节点的过滤属性:
// 节点的类型:nodeType
// 节点的名字:nodeName
// 节点的值:nodeValue
属性,没有参与这种家族关系,更像是元素身上的衣服
- 单独选择器
- 当前元素.attributes
var attr = obox.attributes;
console.log(attr);
console.log(attr.length);
// for(var i=0;i
// 节点的类型:nodeType
// 节点的名字:nodeName
// 节点的值:nodeValue
nodeType nodeName NodeValue
元素 1 大写标签名字 null
文本 3 #text 文本内容
注释 8 #comment 注释内容
根 9 #document null
节点选择器和节点的过滤属性,一般只用来做选择或过滤,不用来做修改等操作,有单独的操作方法
属性操作
- 可见属性
- 内置:只要是系统提供的,在标签身上直接写的,还具有功能,就是内置的可见属性
- 对象操作:1点语法;2中括号语法
console.log(obox.id);
console.log(obox["id"]);
- 也可以使用:getAttribute、setAttribute、removeAttribute
obox.getrAttribute("href");
obox.setAttribute("href","你好");
obox.removeAttribute("abc");
- 特殊的属性:
- class:要使用className操作
- style:样式,值是个对象 // obox.style.background = "pink";
- 非内置:在标签身上直接写的,但是不具有默认功能,就是自定义的可见属性
- 元素.getAttribute("要获取的属性名")
- 元素.setAttribute("要设置的属性名","属性值")
- 元素.removeAttribute("要删除的属性名")
- 内置的可见属性,有很多,其实就是html属性,不一一列出了(见9html属性介绍.html),只要记住如何操作即可
- 不可见属性
- 内置:不用写在标签身上,系统提供,具有功能
- 对象操作:1点语法;2中括号语法
- 非内置:放飞自我,看不见的自定义属性,其实就是将元素,作为一个对象数据,进行操作
- 元素是个对象,对象可以用来存储数据,多存储一些
- 对象操作
- 注意:小心点,别和内置的重复了
1. 样式操作
- 设置
-在js中设置的样式,都是行内样式!
-方式
- 可见的内置属性(html的属性):style
- 注意
```js
// 1.不允许出现中划线,改成小驼峰式
obox.style.fontSize = "100px";
// 2.样式的值,一般都是字符,某些属性可以写成数值
obox.style.opacity = "0.5";
// 3.样式中行高的设置,加不加单位,是不同的样式
obox.style.lineHeight = "20px";
// obox.style.lineHeight = "20";
// 4.style可以直接设置某个css,也可以通过cssText设置多个css,没有设置部分,为空
// obox.style.cssText = "width:100px;height:100px;"
// 5.注意css中的复合属性,如果只设置一部分,其他会被清空
obox.style.background = "red";
- 获取
- 行内:
- 可见的内置属性(html的属性):style console.log(obox.style.width);
- 不能获取非行内
// 注意:获取到的样式,都是字符,哪怕没有设置,获取到的是空字符
-非行内:
- 使用内置方法:getComputedStyle getComputedStyle(obox, false);
var s = getComputedStyle(obox, false);
console.log(s.width);
- 可以获取非行内,也能获取行内
- 有兼容
function getStyle(ele,attr){
if(ele.currentStyle){
return ele.currentStyle[attr];//ie
}else{
return getComputedStyle(ele, false)[attr];
}
}
console.log(getStyle(obox,"width"));
console.log(getStyle(obox,"height"));
- 使用习惯:
- 设置样式:使用style属性
- 获取样式:使用getComputedStyle及其兼容
- 如果,就是不想通过js设置行内样式,也有解决方案
- 可以通过修改class,id,实现样式切换
元素操作
- 元素是什么?标签操作
- 增:创建,通过js创建标签
- 创建
```js
var p = document.createElement("p");
- 插入到最后
```js
obox.appendChild(p);
```js
// 插入到指定的元素的前面
// 参数1:新元素
// 参数2:哪个元素之前
// obox.insertBefore(参数1,参数2)
obox.insertBefore(p,span)
```
- 一次创建只能得到一个元素,不会随着多次插入,出现多个元素
- 删:删除,通过js删除标签
- 要删除的元素.remove()
- 父元素.removeChild(要删除的子元素)
- 一次只能删一条,不能删多个,循环遍历
- 改:修改,把div改成span;没有这种需求,但是有这种技术。
- 获取或设置标签的全部内容,包括标签自身
- outerHTML
- 查:选择器就是查询(获取)元素
- 选择器
- 补充:
- 创建文本节点
- `var ot = document.createTextNode("文字");`
- obj.cloneNode()
- 克隆obj节点,可以传一个布尔值为参数,如果参数为true,连同obj子元素一起克隆
- obj.replaceChild(新添加的节点 , 被替换的节点)
- 替换子节点
2. 尺寸类信息的快捷获取方法
```js
console.log(obox.clientHeight); // cont + padding
console.log(obox.clientWidth); // cont + padding
console.log(obox.offsetHeight); // cont + padding + border
console.log(obox.offsetWidth); // cont + padding + border
console.log(obox.scrollHeight); // cont + padding + 可以滚动的距离
console.log(obox.scrollWidth); // cont + padding + 可以滚动的距离
console.log(obox.offsetLeft); // margin + position
console.log(obox.offsetTop); // margin + position
// 以上都是只能获取,不能设置
// 如果需要修改,得找设置样式
document.onclick = function(){
// 即可获取又可设置
obox.scrollTop = 666;
console.log(obox.scrollTop);
console.log(obox.scrollLeft);
}
## 1.事件的组成
事件源:obox,绑定事件的元素。注意:事件目标,不是任何时候都等同于事件源。一般情况下是一个。
- 绑定事件的方式:on,赋值式绑定
- 事件类型:click,行为方式
- 赋值:= ,赋值式绑定事件的标志之一
- 事件处理函数:function(){console.log("点了一下")},触发指定行为时,要做的事情
- 隐藏的部分:事件对象
## 2.事件对象
- 事件发生时产生的对象,用来记录事件发生时产生的信息
- 默认隐藏,需要主动获取
- 事件对象的获取
- 兼容
```js
obox.onclick = function(eve){
var e = eve || window.event;
console.log(e);
}
- 事件对象,事件的对象,没有事件,不会有对象,所以,只能在事件处理函数中才能拿到事件对象,事件结束后,事件对象被浏览器回收
- 每次开启事件,会产生不同的事件对象
事件对象身上的信息(属性)
1. 鼠标事件对象的坐标类
- 相对于**事件目标**的坐标
- e.offsetX/Y
- 相对于浏览器的可视区域的坐标
- e.clientX/Y
- 相对于页面
- e.pageX/Y
- 相对于显示器的坐标
- e.screenX/Y
2. 键盘事件对象的keyCode
- 获取任意按键的ASC码
- e.keyCode
- 获取功能按键的状态:布尔值
- e.ctrlKey
- e.shiftKey
- e.altKey
- 事件被触发的顺序
- 从里向外:事件冒泡:一个元素的事件被触发后,会依次向上触发**所有** **父**元素的**相同**事件
- 从外向内:事件捕获:一个元素的事件被触发后,会从根元素依次向内触发**所有** **关联子**元素的**相同**事件,直到发生事件的元素
- 当前真正触发事件的元素:目标元素,发生在目标元素身上的事件,叫目标事件
- 执行顺序
1. 捕获
2. 目标
3. 冒泡
- 事件捕获
- 一般不会被主动触发,也不会被默认绑定,而且,IE浏览器没有捕获状态,IE只有冒泡
- 所以如果想实现事件捕获,需要配合事件监听式绑定方法(addEventListener)
- addEventListener的用法,见下一个知识点
```
- 事件冒泡:一个元素的事件被触发后,会依次向上触发**所有** **父**元素的**相同**事件
不好:
- 根据需要,阻止事件冒泡
//兼容IE的住阻止冒泡
function stopBubble(e){
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;//ie
}
}
事件的绑定方式
- 事件绑定常见分为两种:DOM0级,DOM2级
- DOM0级:赋值式绑定,on绑定:
- 绑定方式:只能绑定一个事件处理函数,因为赋值会覆盖
- 元素.onclick = function(){}
- 删除方式:利用赋值,覆盖
- 元素.onclick = null;
- DOM2级:监听式绑定,长长的单词方法
- 绑定方式:可以重复绑定
- 元素.addEventListener(参数1, 参数2, 参数3)
- 参数1:事件类型,注意:没有on
- 参数2:事件处理函数
- 参数3:布尔值:true捕获,false冒泡
- 删除方式:
- 元素.removeEventListener(参数1, 参数2, 参数3);
- 参数1:要删除的事件类型,注意:没有on
- 参数2:要删除的事件处理函数,注意:必须得和绑定时的事件处理函数是一个
- 如果要删除,建议提前起名,不需要删除,无所谓
- 参数3:要删除的是在哪个事件流状态的事件。布尔值:true捕获,false冒泡
- 注意:addEventListener和removeEventListener在IE低版本浏览器下不支持
//兼容IE的dom2级
function addEvent(ele,type,cb){
if(ele.addEventListener){
ele.addEventListener(type,cb)
}else if(ele.attachEvent){
ele.attachEvent("on"+type,cb)
}else{
ele["on"+type] = cb;
}
}
// 作业:删除事件的封装
// ie:
// obox.detachEvent("click",clickFn1)
## 默认事件
- 没有主动写,系统默认有
- 可选,可不选
- 如果不要,阻止
- 通过事件对象身上的e.阻住
- e.returnValue = false // ie
- e.preventDefault()、 // 正常浏览器
封装,方便调用
function stopDefault(e){
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
}
- 文本域的默认行为,回车会换行
// 1发送信息之后的一瞬间,使用js主动取消焦点
// 工具方法,技巧性方法
// 元素.blur()
事件委托
- 将多个子元素的相同事件利用事件冒泡委托给共同的页面现存的父元素,通过事件目标找到真正触发事件的子元素,完成事件处理。的过程,叫事件委托
- 事件委托的好处:
1. 节省内存
2. 给页面上暂时不存在的元素绑定事件(给动态的html绑定事件)
事件源和事件目标
- 事件源:绑定事件的元素
- 必然可以通过this拿到
- 事件目标:触发事件的元素
- 必然可以通过事件对象拿到
- var target = e.target //标准|| e.srcElement//ie
事件对象身上属性
补充
- e.button
- 配合鼠标的按下事件测试:左,中,右
- e.metaKey
- 系统键
1. 概念和意义
- 概念:
- 正则表达式,正则对象,正确的规则,描述字符串的规则
- 正则一般都是配合字符串使用
- 可以对字符串进行:验证,替换,查询
- 意义:
- 快速的验证,查询,替换字符
- 除非极端情况,正则既可以节省操作,又可以节省性能
- 证明:6正则的意义.html
2. 如何创建正则
- 字面量
```js
var reg1 = /正则的内容/;
- 构造函数
```js
var reg2 = new RegExp();
字面量正则中不允许出现变量,构造函数可以,但是使用都是一致的
3. 如何使用
- 验证,替换,查询
- 正则的方法
- 验证:reg.test(str) ***
- 默认验证局部字符串(是否包含)
- 只要字符串中,有一部分符合,就符合
- 整体验证,需要标记开头和结尾
- 从第一位开始验证,验证到最后一位
- ^:开始
- $:结束
- 查询:reg.exec(str)
- reg.exec(str)
- 每次查询时,会在上次查询结束的位置继续查询
- 直到查询到最后,返回null
- 继续回到初始位置,开始查询
- 但其实,正则开始验证的位置,是可修改的
- 正则的属性:reg.lastIndex
- 表示查询到字符的某个位置的索引
- 字符的方法
- 替换:str.replace(reg,"newStr") ***
- 替换
- 查询:str.match(reg) ***
- 根据指定规则,查询字符串中符合的子串,放在一个数组中
- 查询:str.search(reg)
- 第一次出现的位置的索引
乱码"该怎么写,有什么含义
- 修饰符
- g:全局匹配
- i:忽略大小写
- 量词
- +:一个或以上
- *:零个或以上
- ?:零个或一个
- {n}:固定n次
- {n,}:至少n次,以上
- {n,m}:至少n次,最多m次
- 或:|
- 子集:()
- 范围符:-
- 中元符:[],用来标记范围,内部所有组成都是或的关系
- 转义符:
- \d,表示所有的数字,等同于[0-9]
- \w,表示所有的数字字母下划线,等同于[0-9a-zA-Z_]
- \s,表示空格,等同于:
- \D,表示除了数字,等同于[^0-9]
- \W,表示除了数字字母下换线,等同于[^a-z0-9A-Z_]
- \S,表示除了空格,[^\s]
- 非:^,必须在中元符内使用
正则的应用
- 表单验证
- 敏感词过滤
- 查询指定字符,返回成数组
## this
1. 函数的执行
- 作为函数调用(默认调用):函数名()
- 作为对象的方法(通过上下文调用):对象 . 方法名()
- 通过call或apply或bind方法间接调用():函数名 . call()
- 作为构造函数(通过new调用):new 函数名()
2. this的几种指向场景
- 当一个没有明确隶属对象的函数,被直接调用时。该函数内部的this指向window
- 隐式绑定:就是将没有明确隶属对象的函数,归属到某个对象,通过该对象执行函数。此时函数内部的this指向该对象。
1. 当对象的方法被变量引用时,如果该变量没有从属对象,通过该变量执行函数,那么this会丢失,捕获到window。
2. 当对象的方法,作为回调函数,传入另一个函数内执行时,this会丢失,捕获到window。
- 显示绑定:就是使用函数的方法,如:call,apply,bind等,可以强制改变this的指向
1. 显示绑定可以修复隐式丢失的问题
2. 在隐式执行之前,使用函数的方法,强行指定this的指向
- 构造函数绑定
3. 总结
- 默认绑定 ------------------------> 严格模式绑定到undefined,否则为全局对象window
- 隐式绑定(在上下文中调用) ----------> 绑定到当前函数的执行上下文对象
- 显示绑定(由call或apply或bind调用) -> 绑定到指定的对象
- 构造函数绑定(由new调用) -----------> 绑定到新创建的对象
0. 关于称呼
- 没有归属的函数,叫函数
- 有归属对象的函数,叫方法
1. 函数的方法
- 将函数作为一个对象,身上有属性,内存储了函数
- 通过函数名.方法名()执行
2. 方法
- call
- 语法:函数名.call()
- 功能:改变this指向
- 参数:参数1和后面所有参数
- 参数1:要改变的this指向
- 后面所有参数:作为实参传到当前这次执行的函数中
- 返回值:原函数的返回值
- apply
- 函数名.apply()
- 功能:改变this指向
- 参数:参数1和参数2
- 参数1:要改变的this指向
- 参数2:数组,被当前这次执行的函数中的arguments解析
- 返回值:原函数的返回值
- bind
- 函数名.bind()
- 功能:改变this指向
- 参数:参数1和后面所有参数
- 参数1:要改变的this指向
- 后面所有参数:作为实参传到当前这次执行的函数中
- 返回值:改变了this之后的**新**函数,和老函数长得一样,但不是一个
/* 1、call && apply 的区别 */
/* [1] 传递参数的方式不一样:call 以参数列表的方式传递,apply以数组的方式来传递*/
/* [2] call 和 apply 的形参(期望调用函数的时候传递的参数)个数不一样 */
/* [1] 修改函数内部的 this */
/* [2] 执行函数 */
原理的封装
Function.prototype.mockCall = function(context) {
context = context ? Object(context) : window;
context.fn = this;
context.fn(...Array.from(arguments).slice(1));
Reflect.deleteProperty(context, "fn");
}
Function.prototype.mockApply = function(context, arg) {
context = context ? Object(context) : window;
/* [1] 修改函数内部的 this */
/* [2] 执行函数 */
let fn = this; /* 获取函数本身 */
context.fn = fn;
if (!arg) {
context.fn();
} else {
context.fn(...arg);
}
Reflect.deleteProperty(context, "fn");
}
- 只要会用即可,但其实,妙用无穷
- 基础篇:https://www.jianshu.com/p/0a6655dbf420
- 扩展篇:https://www.jianshu.com/p/a6f26c3756fe
1. 简单说明
- ES6:ECMAScript6的版本的简称
- ES6有兼容,低版本浏览器不支持,其实兼容问题已经很小了
- ES6已经大面积流行使用,上线之前会利用工程化工具,将ES6的语法编译成ES5的语法
2. 新增声明关键字 - let,const
- let,const,export/import(ES6的模块化),class(类)
- let,const
- 基本上都可以替换var,但是要注意,自身的特性
- let的特性
- 不允许重复声明
- 没有提升
- 暂时性死区
- 块级作用域
- 全局没有给window
- const的特性
- 与let一致
- 标志着变量的地址不允许修改
- const只能保证,地址不被修改,保证不了值的改变
- 但是基础类型(值),地址就是值,值就是地址,所有都不能改
- 但是复杂类型(引用),地址就是地址,值就是值,所以值可以改,地址不能改
- 总结
- 所有的var都可以替换成let,但是要注意新特性
- 尤其是:块级作用域
- 箭头函数等同于无名函数,不能直接存在,必须作为值使用
- 有且只有一个参数时,小括号可以省略
```js
var fn = a=>{
console.log(a)
};
有且直接返回值,花括号和return也可以省略
var fn = a=>"hello "+a;
特点:
1. 没有自己的this,自动绑定上层函数的this
2. 省略花括号,并返回对象时需要给对象加小括号
3. 语义化极差
4. 简单,方便,体积小
5. 有且只有一个参数时,可以省略小括号
6. 有且直接返回数据时,可以省略花括号和return
7. 不能new
8. 箭头函数中没有 arguments , 不能直接使用
作为参数或返回值等小范围使用,非常舒服,如
[67,13,36,1,35sort((a,b)=>a-b);
在函数定义时的小括号中,可以给形参赋值,赋的这个值,就是当前参数的默认值
function fn(a="456"){
// a = a || "123";
console.log(a);
}
fn();
fn("hello");
1. - 解开结构,单独赋值
- 数组
- 数组是数据的有序集合,所以在解构赋值时,变量之间有顺序,从左向右依次解析,没有了,就是undefined
var [a,b,c] = ["hello","world",123];
- 对象
- 对象是数据的无序集合,所以在解构赋值时,变量之间没有顺序,找到对象中的key 了,就赋值,没有找到就是undefined
var {name,sex,age} = {name:"张三",age:18,sex:1}
- 字符,因为字符类似于数组
- 字符也算是数据的有序集合,所以在解构赋值时,变量之间有顺序,从左向右依次解析,没有了,就是undefined
var [a,b,c] = "hello";
1. - 回顾单双引号字符串的特点
- 不允许换行,如果要换行,必须每行都是完整的字符串,还得用+连接
- 字符串的新的表达方式:反引号:`
- 允许换行
- 可以不用+号拼接,在反引号内,使用${}包裹变量
- 也可以使用+号拼接,只是没必要了
- 如:
```js
var str = `
- "${name}"
- '${name}'
- ${name}
- ${1+1}
- ${fn()}
- ${false ? "hello" : "wrold"}
`;
console.log(str);
var obox = document.getElementById("box");
obox.innerHTML = str;
展开运算符必须在能够接收多个数据的位置使用
- 展开数组,要在能够接收多个数据时使用
- 传参,合并数组
// 快速实现数组合并
var arr2 = [2,3,4,arr];
var arr2 = [2,3,4,...arr];
console.log(arr2);
// 函数的参数
function fn(a,b,c){
console.log(a,b,c)
}
fn(...[3,4,5]);
展开对象,要在能够接收多个键值对时使用
var obj = {
name:"admin",
age:18
}
var obj2 = {
sex:"男",
...obj
}
console.log(obj2);
- 当对象的value是变量,且key和这个变量重名时,可以缩写
- 当对的value是函数时,可以直接:函数名(){}
var name = "admin";
var age = 18;
var obj = {
name,
age,
fn(){
console.log(this.name)
}
}
console.log(obj)
obj.fn()
0. 什么是动画
- 谁,动起来,频率,步长,什么时候结束
1. 动画的要素
- 运动源:正在运动的事物
- 频率:每个单位时间
- 步长:每个单位时间内做出来的改变
- 停止条件:什么时候结束
2. 频率的限制
- 人眼能识别的最少频率是24
- 一秒钟切换连续的24张图片,就是动画
- 毫秒数,多长时间切换一个效果
- 时间越短,效果越好
- 浪费的性能越多,页面也不一定能够响应
- 20~40
- 30
3. 动画
- 简单动画-匀速动画
- 缓冲动画-减速动画
- 刹车
Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组。
1.isArray
语法:Array.isArray(obj)
说明:判断一个对象是否是数组。
2.concat
语法:var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
说明:把多个数组串联成一个新数组
eg:
var alpha = ['a', 'b', 'c'];
var numeric = [1, 2, 3];
alpha.concat(numeric);
// result in ['a', 'b', 'c', 1, 2, 3]
3.includes
语法:
arr.includes(searchElement)
arr.includes(searchElement, fromIndex)
说明:判断数组是否包含指定的元素,第二个参数表示从哪个索引开始查询
4.entries
语法:arr.entries()
说明方法返回一个数组的迭代对象,该对象包含数组的键值对 (key/value),迭代对象中数组的索引值作为 key, 数组元素作为 value。
eg:
let arr[3,4,5,6];
arr.entries();
/* 符号类型的数据也可以作为对象的 key */
/* 特点:独一无二 */
/* 符号类型的数据写在对象中,意味着这个键值对是给自己使用的(私有的) */
let s1 = Symbol();
let s2 = Symbol();
console.log(s1, s2, s1 == s2) /* Symbol() Symbol() false*/
let s3 = Symbol("name");
let s4 = Symbol("age");
console.log(s3, s4) /* Symbol(name) Symbol(age) */
let obj = {
address: "广州",
class: "2002",
[s3]: "张三",
[s4]: 16
}
console.log(obj);
for (let key in obj) {
console.log(key, obj[key]);
}
console.log(Object.keys(obj)); /* 获取所有的 key ["address", "class"] */
console.log(Object.getOwnPropertyNames(obj)); /* ["address", "class"] */
console.log(Object.getOwnPropertySymbols(obj)); /* [Symbol(name), Symbol(age)] */
console.log(Reflect.ownKeys(obj)) /* ["address", "class", Symbol(name), Symbol(age)] */
/* 内部实现原理(细节) */
/* 当基本数据类型的值(数字\布尔值\字符串)需要访问属性或者调用方法的时候 ,JavaScript 语言内部默认会根据当前的基本数据类型值来创建一个包装类型的对象,然后通过该对象来访问属性或者是调用方法,执行完毕后这个新创建的对象会被释放。*/
let str = "Nice";
/* (1) let strObj = new String(str); */
/* (2) strObj.length -> 4 */
/* (3) strObj = null; */
console.log(str.length); /* 获取字符串的长度:4 */
console.log(str.slice(1))
/* 面试题: */
let s = "我是字符串";
/* (1) let strObj = new String("我是字符串"); */
/* (2) strObj.name -> undefined*/
/* (3) strObj = null; */
console.log(s.name); /* undefined */
/* (1) let strObj = new String("我是字符串"); */
/* (2) strObj.name = "张三"; */
/* (3) strObj = null; */
s.name = "张三";
/* (1) let strObj = new String("我是字符串"); */
/* (2) strObj.name */
/* (3) strObj = null; */
console.log(s.name); /* undefined */
/* in 关键字 ??? */
/* (1) for..in循环(主要遍历对象)*/
/* (2) 检查某个对象中是否存在指定的键值对 */
/* in关键字的注意点:在检查的时候会检查原型链,如果在原型链上面能够找到那么也返回true */
/* 方法:Object.prototype.hasOwnProperty() */
/* 用法:obj.hasOwnProperty("name") */
/* 作用:检查obj中是否存在name这个键值对(注意:只会检查自己不会检查原型对象) */
// let obj = {
// name: "zs",
// age: 18,
// };
// console.log("age" in obj); /* true */
// console.log("name" in obj); /* true 检查obj对象中是否存在name这个属性|方法 */
// console.log("address" in obj); /* false */
// /* Reflect 反射 */
// console.log(Reflect.has(obj, "name"));
// console.log(Reflect.has(obj, "color"));false
// let o = {
// name: "zs"
// }
// Object.prototype.xx = "我是xxx";
// console.log("xx" in o) /* true */
// console.log(o.hasOwnProperty("name")); /* true */
// console.log(o.hasOwnProperty("age")); /* false */
// console.log(o.hasOwnProperty("xx")); /* false */
1. js中的json,类似于数组和对象,只不过还需要遵守json的要求,js中有提供json和数组对象的转换方法
- 日常在js中,所谓的json数组,json对象,其实只是参考了json数据的名字,别名,起了个名字
- 自身其实就是编程语言中的数组或对象
2. php中的json,字符,只不过可以将php的数组和对象,通过一些方法转成json的格式
3. 任何一门编程语言中,都提供有将自身的某些数据,转成json的方法
- 不允许使用双引号包裹,必须是单引号或反引号(json文件中不需要,json文件自身就是文本文件)
- 如:
- 在html文件中写css需要style标签,在css文件中不需要
- 在html文件写js需要script标签,在js文件中不需要
2. json的格式,类似于js中的对象和数组
3. 键值对的key,必须使用双引号包裹
4. 在json中不允许出现函数、undefined、NaN,可以出现null
5. 不允许出现没有意义的逗号
## js对象和json的转换场景
1. json字符转对象:这个字符就得符合json的格式
- JSON.parse(str);
- 需要注意json的规则
2. 对象转json字符:这个对象只需要符合js中对象的规则即可
- JSON.stringify(obj);
- 需要注意js对象或数组的规则
- 函数,undefined被忽略
- NaN,被转成null
1. 拿到后端传过来的json数据后,将json数据转成js对象,方便前端js处理
```js
var o = JSON.parse('{"name":null}');
console.log(o);
2 如果需要将js对象传给后端使用,后端不能识别js对象,但可以识别json数据,需要将js对象转成json数据,发给后端
var s = JSON.stringify({name:"admin"})
console.log(s);
``
stringify方法使用说明
语法:JSON.stringify(Obj,[fn|arr],[space])
参数说明
第一个参数:Obj为要进行序列化操作的JavaScript对象
第二个参数:过滤器,可以是函数或者是一个数组
第三个参数:是否在生成的json字符串中保留缩进,用于控制缩进的字符
/* 高级用法 */
//对象的处理
// let json2 = JSON.stringify(o1, null, 4); /* 格式化处理:加4个空格 */
// let json2 = JSON.stringify(o1, null, 10);
// let json2 = JSON.stringify(o1, null, "####");
// console.log(json2);
// let json3 = JSON.stringify(o1, ["name","age"]); /* 仅仅处理name和age这两个字段 */
// console.log(json3);
// let json4 = JSON.stringify(o1, (key, value) => {
// if (key === "address" || key === "name") { /* 过滤:如果返回undefined表示忽略该键值对
// return undefined;
// } else if (key === "id") { /* 中间处理: */
// return value * 10;
// } else {
// return value;
// }
// });
// console.log(json4);
/* 002-数组的处理 */
// let arr = [{
// id: 1,
// name: "zs",
// age: 4
// }, {
// id: 2,
// name: "lw",
// age: 5
// }, {
// id: 3,
// name: "sr",
// age: 4
// }];
// let json5 = JSON.stringify(arr, ["name", "id"], 4);
// console.log(json5);
语法 JSON.parse(json,fn)
// let jsonA = `{"name":"zs","color":"red"}`;
// // let obj1 = JSON.parse(jsonA);
// // console.log(obj1)
// let obj2 = JSON.parse(jsonA, (key, value) => {
// if (key === "color") {
// return undefined;
// } else {
// console.log("value", value);
// return value;
// }
// });
// console.log(obj2)
面向对象的思维
1. 面向
2. 编程模式的发展
3. 对象的来源
4. 对象的优势
5. 面向对象的分析和设计
- 分解小模块:分工
- 按照模块之间的关系或执行顺序,相互协作
6. 面向对象编程
面向对象的设计:OOD
- 模式识别和抽象:
- 每道菜的做法,是否有规律可循
- 如果有规律,可以封装
- 每个模块之间的关系
- 功能排序
- 低耦合
1. 面向对象的编程:OOP
- 开发和执行:动手做,细节实现部分
2. 评估评价
- 总结,复盘,考虑代码的性能和合理性,下次做出改进
- 思考 -> 利用创建对象的语法,搭建结构(高内聚和低耦合) -> 完善每一个模块
- 内聚:一个对象的每个功能模块,都从属于当前对象
- 耦合:模块与模块之间的调用关系
封装
- 类似于函数,更大层次的封装
- 函数是一个功能的封装
- 对象是多个功能的封装
- 隐藏细节,让使用更简单
1. 继承
- 更灵活的扩展
2. 多态
- 动态的扩展
字面量
- var obj = {}
- 构造函数
- 构造内置函数
- var obj = new Object()
- 构造自定义函数
- var obj = new Fn();
1. 面向对象思维的实现方式
2. 创建对象
- ...
3. 工厂模式创建对象
- 自定义工厂模式,放弃,自己封装对象,返回对象
```js
function fn(n){
var obj = {};
obj.name = n;
return obj;
}
var o = fn("admin");
内置的工厂模式(自定义的构造函数),推荐,new执行函数
```js
function Fn(n){
// 自动创建的对象:通过this拿到
this.name = n;
}
var o = new Fn("root");
```
构造函数的缺陷
```js
function Fn(n){
// 自动创建的对象:通过this拿到
this.name = n;
this.show = function(){
console.log(this.name)
}
}
var o1 = new Fn("admin");
var o2 = new Fn("root");
console.log(o1.show === o2.show); // f
```
以上代码,会在内存中产生大量的冗余功能(show)
解决方式:不把show写给每个具体的对象(实例),写给父级数据
有技术短板
学习原型
## .原型的概念
原型的出现,就是为了解决 构造函数的缺点
可以让我们更合理、方便的给实例添加方法
否则构造函数只能给实例添加属性,不能合理的添加方法
- 原型是一种概念
- 在js中所有的对象(O),都一个内置属性:`__proto__`
- 是个指针,用来指向当前对象(O)的父级数据,必然是对象
- 在除了箭头函数之外的任何函数(F)身上,都有一个默认属性:`prototype`
- 是个对象类型的属性,用来作为当前函数(F)被new执行后,创建出来的对象,做父级对象使用
- 被new创建出来的对象的`__proto__`,被强行指向了new的函数的`prototype`
- 对象读取属性的原则
- 向上查找:顺着自身的`__proto__`属性,查找,找到了就使用,没找到,继续向上,到头还没找到,就抛出`undefined`,相当于报错
function Fn(n){
// 自动创建的对象:通过this拿到
this.name = n;
}
Fn.prototype.show = function(){
console.log(this.name)
// this=======实例
var that = this;
obox.onclick = function(){
// this======当前函数的执行对象obox
// that======实例
}
}
var o1 = new Fn("admin");
var o2 = new Fn("root");
console.log(o1.show === o2.show); // t
/* 001-每个构造函数默认都会有一个与之(相关联)的对象,这个对象被称为该构造函数的原型对象,默认该对象是空对象。 */
/* 002-关系:相互关联 */
/* 构造函数<->原型对象 */
/* 构造函数----prototype---> 原型对象 */
/* 原型构造----constructor-> 构造函数 */
/* 003-原型对象的特点 */
/* 特点:所有构造函数创建出来的实例对象都能够访问对应原型对象的成员 */
/* 原型对象上面的成员(属性+方法)可以被所有该构造函数创建出来的实例对象共享。 */
/* 构造函数:Person */
/* 原型对象:Person.prototype */
/* 实例对象:p1,p2 */
/* 004-如何访问原型对象(几种方式) */
/* [1] 构造函数.prototype */
/* [2] 实例对象.__proto__ */
/* [3] Object.getPrototypeOf(实例对象) */
/* [4] Reflect.getPrototypeOf(实例对象) */
/* 注意:静态成员只有构造函数自己可以访问 */
// p1.showClassName(); //Uncaught TypeError: p1.showClassName is not a function
// Person.prototype.showClassName();
// Person.showClassName();
/* 实例对象如何才能访问静态方法? */
// p1.__proto__.constructor.showClassName();
/* 概念: */
/* 构造函数: Person */
/* 原型对象: Person.prototype */
/* 实例对象: 通过构造函数创建出来的对象,p1 p2*/
/* 实例化: 通过构造函数创建实例对象的过程*/
/* 成员: 对象的属性 + 对象的方法 */
/* 实例成员: 实例对象的属性和方法*/
/* 原型成员: 原型对象的属性和方法*/
/* 静态成员: 构造函数自己的属性和方法,静态属性+静态方法, */
/* 私有成员: 在构造函数内部声明的变量和函数,外部无法直接访问 */
/* 特权方法: */
/* 原型链: */
/* 推导过程: */
/* 1、我们几乎可以认为所有的对象都是由构造函数创建出来的。 */
/* 2、每个构造函数都有一个相关联的原型对象,默认是空对象 */
/* 3、原型对象也是对象,因此原型对象也是由构造函数创建出来 */
/* 4、原型对象的构造函数也有相关联的原型对象,这个原型对象也有构造函数 */
/* 以上就会形成一种链式的访问结构,原型链。 */
/* 原型链顶点:Object.prototype */
/* Object.prototype.__proto__ == null; */
构造自定义函数,关键字new执行函数
new的执行原理
1. 创建一个新对象
2. 改变函数内的this指向,为这个新对象
3. 执行函数内的代码,并将新对象的__proto__指向该函数的prototype
4. 检查函数是否主动返回对象,如果没有,则返回这个新对象
- 在构造函数中的this,原型上方法中的this,都是将来的实例
- 如果在构造函数或原型上方法中,出现了新的函数,注意其内部this指向的改变
// 目前不能解决
// 严格要求自己,哪些是构造函数,哪些是正常函数
// 做个区分
// 如果是构造函数,要将函数名的首字母大写:大驼峰
// 正常函数,首字母小写:小驼峰
// 仅仅是行业规范,但不是语法
// 某个函数的首字母大写了,那么这个函数必然可以被new执行,这个函数就是构造函数,或 类
// 某个函数的首字母小写了,那么这个函数可以正常执行,这个函数就是正常函数
```js
class Tab{
constructor(n){
// 相当于老语法的构造函数部分
this.name = n;
}
// 以下方法都 相当于 被绑定到构造函数的原型对象上
show(){
console.log(this.name)
}
}
var t = new Tab("root");
console.log(t)
t.show();
- 跨时间页面存储数据
- cookie,storage
- 记住账号密码
- 在商品列表页面点击加入购物车,在购物车页面可以看到刚才点击的商品
- 登陆之后,关电脑,重新打开电脑,打开网站,还是登陆状态
- 本地:客户端的硬盘
- 两个客户端之间,无法互通
- 还需要依赖浏览器,跨浏览器都拿不到
- 甚至有些存储,跨网站都拿不到(跨域)
- 硬盘的哪个位置:
- 浏览器的缓存中
- 缓存:
- 保存浏览器每次打开网站加载的资源
- 还有一些本地存储的数据
- 只能存文本,字符
- 大小限制
- 没有加密,所以安全性要自己处理
- 存储:
- 一般情况下,只有服务器的数据库才可以存储数据
- 浏览器提供的,可以将一些信息存储在缓存中的技术
- 缓存,浏览器在硬盘中划分的独立区域,用来存储浏览器产生的资源
- 硬盘 -> 某个软件(浏览器) -> 缓存 -> 本地存储 -> localStorage
- cookie 老技术
- 指定有效期
- 不能跨域(浏览器,网站,路径)
- storage HTML5规范中新增的本地存储
- localStorage 只能永久
- sessionStorage 只能会话级(关闭浏览器自动清除)
### localStorage的介绍
### localStorage
- 只能存字符
- 有大小限制
- 没有时间限制:永久
- 是window的子对象
1- 对象的操作
- localStorage.a = "hello";
- localStorage.a = "world";
- console.log(localStorage.a);
- delete localStorage.a;
- 自身的API(方法) √√√
- 设置
- localStorage.setItem("key","val");
- 获取
- console.log(localStorage.getItem("key"))
- 删除
- localStorage.removeItem("key");
- localStorage.clear(); // 慎用
- 查看总数
- localStorage.length
2. 本地存储的应用
- localStorage
- 记住账号密码
- 友情提示:不要在公共区域勾选此项
- 记住拖拽元素的位置
3. 浏览器提供的查看本地存储的方式
- 控制台的application选项 -> storage -> local storage
- 刷新,删除一条,删除多条1
# 前后端交互
## 一、前端
- js:ajax或表单
## 二、后端(服务端语言)
1. 如何打造后端程序(后端环境)
- 服务器:运行后端程序的载体或平台
- 超级电脑:专用网络,专人维护,永不宕机,对外开放的全放
- 买:成本大,没有必要
- 假装(模拟):本地服务器
- 客户端模拟服务端的环境,必然要通过第三方软件的支持
- 数据库:数据的仓库,用来管理数据
- 通过数据库管理系统才能操作数据
- 安装数据库管理系统
- mysql
- ...
- 后端语言的支持
- php后端:php的语言支持
- java后端:java的语言支持
- ......
- 下载安装
2. 集成工具
- 集成了什么
- 本地服务器环境
- apache
- 数据库管理系统
- 后端语言的支持
- 如何安装
1. 获取方式(百度搜索:php本地服务器)
2. 下载
- 开始安装:以phpStudy为例
1. 打扫当前环境
- 确保电脑上没有安装其他类似软件
- 确保电脑上没有开启其他类似服务
2. 安装
- 解压
- 看说明
- 安装
- 注意路径
- 自动打开
3. 使用
- 启动对应服务
- apache(php服务器的环境)
- mysql(暂缓)
- 打开浏览器
- 输入:localhost或127.0.0.1
- 默认以服务器环境打开:/安装路径/www/index.html,这个路径
4. 切记:**********
- 如果需要使用服务器环境浏览页面:必须将页面放在,服务器根目录:如:/安装路径/www
- 如果需要使用服务器环境浏览页面:必须通过:localhost或127.0.0.1
- localhost或127.0.0.1,就表示服务器的根目录,如:www
- 如果在www文件夹内有子文件夹,逐层书写路径地址,如:
- http://localhost/page/drag.html
- http://localhost/index.html
- 在服务器路径中,尽量不要出现中文
3. 如何运行php
- 必须将php文件,放在服务器环境下
- 必须通过服务器的访问方式,打开php文件
- php文件的扩展名,为:.php
4. 如何书写php
- 创建
- 写代码
- 三、PHP书写和执行
- 通过服务器打开
1xx 100~199 100~101 Informational(信息性状态码) 接收的请求正在处理
2xx 200~299 200~206 Success(成功状态码)。 请求正常处理完毕
3xx 300~399 300~305 Redirection(重定向状态码)需要进行附加操作以完成请求
4xx 400~499 400~415 Client error(客户端错误) 服务器无法处理请求
5xx 500~599 500~505 Server error(服务器错误) 服务器处理请求出错
1. php的执行
- 执行方式
- php必须要通过php环境的服务器打开
- 浏览器无法直接解析php文件
- php并没有在浏览器中被打开,仅仅是被服务器解析之后,将php返回的数据,发送给了浏览器,浏览器呈现数据(转成字符)
- 前后端交互
- 前端
- 接收:浏览器默认接收
- 后端
- 发送:echo
- 将来我们在前端会使用ajax接收php的数据,要求php主动转成字符(json),不再默认转换了
2. php语法
- php是一门独立的编程语言,有自己的专属语法,和js是两回事
- 当遇到一些奇怪内容时,可以惊讶但要接受,因为这就是php的语法
- 文件:扩展名.php
- php默认结构:``
- php要求每行代码结束必须加分号
- php的变量不用声明,但必须使用$开头
- php的字符串支持换行,拼接使用:.
- php的数据类型:(注意,如果使用echo操作数据,那么echo会将数据转成字符,有可能会报错)
- 字符
- 整数
- 浮点数
- 布尔型
- NULL
- 对象(必须通过class创建)
- 数组
- 资源型:通过数据库获取到的数据
- php中的程序结构
- 顺序:代码逐行执行
- 分支:if,if-else,switch
- 循环:for,while,do-while
- php中的函数
- 定义:function
- 执行:函数名()
- php中的内置
- https://www.php.net/manual/zh/index.php
- 返回方式(php的发送)
- echo ********
- print
- print_r()
- 查看变量的方式
- var_dump()
- 查看数组的长度
- count()
- 转json的方法
- json_encode(要转换的php数组或php对象) ************
- json_decode(长的像数组或对象的json)
- 引入其他php文件
- include "要引入的文件路径"
3. 前后端交互 ************
- 前端
- 收:浏览器默认接收
- 发:form表单
- 后端
- 收:
- $_GET["要接收的数据的字段名"]
- $_POST["要接收的数据的字段名"]
- $_REQUEST["要接收的数据的字段名"]
- 在明确发送方式的情况下,不要使用$_REQUEST
- 发:echo
- 后端返回数据的格式
- 直接返回文本信息
- 使用状态码表示
- 返回json,json中包含状态码和信息 *******
- 为了方便的得到json
- 可以先实现php中的数组或对象,使用json_encode方法转换
- php中的数组
- 索引数据
- 按照索引查找数据
- Array ( [0] => hello [1] => 3 [2] => world )
- 转成json之后,是中括号的形式
- ["hello",3,"world"]
- 关联数组
- 按照键查找数据
- Array ( [name] => admin [sex] => 1 [age] => 18 )
- 转成json之后,是花括号的形式
- {"name":"admin","sex":1,"age":18}
4. php基础部分
- 理解php的执行和解析
- 能够实现登录验证效果
//form的action表示地址。可以是相对也可以是绝对,name的属性是对象的键值对的键
//get请求
//post请求
//file文件上传
/* 文件上传的注意点: */
/* (1) 请求路径 */
/* (2) 请求方法 */
/* (3) 请求参数 */
/* (+) 文件上传请求需要主动的告诉服务器,这是一个文件上传请求。 enctype="multipart/form-data"*/
# 先试着拿到这张图片
# var_dump($_POST); /* array(1) { ["fileName"]=> string(10) "peiQi.jpeg" } */
# 文件上传需要用到$_FIles
// print_r($_FILES);
/*
Array (
[fileName] => Array (
[name] => peiQi.jpeg 文件的名字
[type] => image/jpeg 文件的类型
[tmp_name] => /Applications/MAMP/tmp/php/phpJPzDeH 文件上传到服务器后的临时存储路径(临时)
[error] => 0 错误信息
[size] => 37597 ) 文件大小
*/
# sleep(3);
# 把用户上传的图片保存到file文件夹下面
/* 第一个参数:源位置 */
/* 第二个参数:目标位置 */
$pathA = $_FILES["fileName"]["tmp_name"];
// $pathB = "./file/PQ.jpeg";
$pathB = "./file/".$_FILES["fileName"]["name"];
move_uploaded_file($pathA,$pathB);
GET请求和POST请求的区别?
GET 请求路径 http://127.0.0.1/code/day21/code/server/05.server.php?user=zs&pwd=321
POST请求路径 http://127.0.0.1/code/day21/code/server/06.server.php
(1) 参数的处理方式不同,GET请求参数以查询字符串的方式跟在URL的后面,POST请求参数放在请求体中提交。
(2) GET请求相对安全性比较差,POST请求相对安全一些。 */
(3) GET请求提交参数的时候有大小和个数的限制(浏览器厂商对地址栏的URL路径有限制<2KB),POST请求没有限制。
文件上传(视频文件)2GB 发送的是POST请求。
1.Ajax技术简单介绍
Ajax是⼀⻔异步的⽤于发送⽹络请求的技术。
全称为:Async javascript and XML。
简单说明:Ajax 这个概念是由 Jesse James Garrett 在 2005 年发明的。它本身不是单⼀技术,是⼀串技术的
集合。
技术特点:通常情况下,每次提交表单的时候,都会刷新整个界⾯,⽽使⽤ajax发送请求可以实现异步发
送请求获取数据⽽不需要刷新整个⻚⾯。
监听请求状态
onreadystatechange的⼏种状态
(1)请求未初始化 - 0
(2)服务器连接已经建⽴ - 1
(3)请求已经接收 -2
(4)请求处理中 -3
(5)请求已经完成,且响应已经就绪 -4
判断请求结果
⽹络请求发送之后,可能成功,也可能失败。在代码中,我们可以通过响应状态码来判断请求成功还是失
败,并最终做出相应的处理。
(1)当请求完成的时候再进⾏处理,readyState == 4
(2)通过响应码判断请求成功还是失败,status == 200
(3)请求成功解析服务器返回的响应体:response.Text
请求超时
在开发中可能需要对请求的时间进⾏限制,例如要求设置⽹络请求的超时时间为10秒,如果超过了该时间
那么就提示⽤户检查⽹络。
在具体的代码实现中,该需求可以使⽤定时器配合abort⽅法来实现。
设置xhr.timeout 监听xhr.ontimeout
中⽂转码
在发送GET请求的时候,如果请求路径中存在中⽂,那么在发送⽹络请求之前应该先对请求路径进⾏中⽂
转码处理,使⽤ encodeURI ⽅法来完成。
缓存问题
问题说明:在IE浏览器中如果发送的是GET请求,只要URL没有发⽣变化,那么IE浏览器就会认为⽹⻚的内
容也没有发⽣变化,因此会优先使⽤缓存数据。
解决⽅式:如果在IE浏览器中想让数据实时更新(获取到最新的数据),那么 可以让每次请求的URL都不⼀样
(即每次请求的URL地址不⼀样) 。
具体思路:在开发中可以使⽤ 随机数因⼦ 或者是 时间戳 来添加⼀个额外的参数给url路径。
获取时间戳:var date = new Date();date.valueOf() date.now();
获取随机数因⼦ Math.radom()
补充说明
① 加随机数或者是时间戳的⽬的在于让每次请求的时候url的内容都不⼀样
② 参数变化的作⽤就是让每次发送⽹络请求的时候URL都不相同,以让服务器总是把最新的数据返回。
Ajax的优点
(1)不需要插件⽀持(⼀般浏览器且默认开启 JavaScript 即可);
(2)⽤户体验极佳(不刷新⻚⾯即可获取可更新的数据);
(3)提升 Web 程序的性能(在传递数据的时候不必整体提交);
(4)减轻服务器和带宽的负担(将服务器的⼀些操作转移到客户端);
Ajax 的不⾜
(1)不同版本的浏览器度XMLHttpRequest 对象⽀持度不同(⽐如IE5之前);
(2)前进、后退的功能被破坏;
(3)搜索引擎的⽀持度不够(引擎爬⾍还不能理解JS引起变化数据的内容);
(4)开发调试⼯具缺乏
get请求封装
<script>
document.onclick=function(){
ajaxGet("../server/get.php",{user:"zhu",psw:19},(res)=>{
console.log("成功"+res);
},(err)=>{
alert("失败"+err)
})
}
function ajaxGet(url,data,success,error,timeout){
let xhr=new XMLHttpRequest;
let arr=[];
for(let key in data){
arr.push(`${key}=${data[key]}`)
}
arr=arr.join("&");
if(!data){
url=url+"?t="+(new Date).getTime();
}else{
url=url+"?"+arr;
}
url=encodeURI(url);
xhr.open("get",url);
xhr.send();
xhr.timeout=timeout||10000;
xhr.onload=function(){
if(xhr.status==200){
success(xhr.responseText);
}else{
error(xhr.statusText);
}
}
xhr.ontimeout=function(){
alert("请求超时,请重新加载");
}
}
</script>
<script>
document.addEventListener("click",function(){
ajaxPost("../se2rver/post.php",{user:"zhu",psw:19},(res)=>{
console.log(res);
},(err)=>{
alert("请求失败,失败原因:"+err);
});
});
function ajaxPost(url,data,success,error,timeout){
let xhr=new XMLHttpRequest;
let arr=[];
for(let key in data){
arr.push(`${key}=${data[key]}`);
}
arr=arr.join("&");
xhr.open("post",url);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(arr);
xhr.timeout=timeout||10000;
xhr.onload=function(){
if(xhr.status==200){
success(xhr.responseText);
}else{
error(xhr.statusText);
}
}
xhr.ontimeout=function(){
alert("请求超时,请重新请求");
}
}
</script>
<script>
document.onclick=function(){
ajax({
url:"../server/ajax.php",
data:{user:"zhujunjie",psw:19},
success:(res)=>{
console.log(res);
},
error:(err)=>{
alert("请求失败,失败原因:"+err);
}
});
}
function ajax(options){
let {url,data,success,error,timeout,type}=options
let xhr=new XMLHttpRequest;
type=type||"get";
let arr=[];
for(let key in data){
arr.push(`${key}=${data[key]}`);
}
arr=arr.join("&");
if(type=="get"){
if(!data){
url=url+"?t="+(new Date).getTime();
}else{
url=url+"?"+arr;
}
url=encodeURI(url);
xhr.open("get",url);
xhr.send();
}else{
xhr.open("post",url);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(arr);
}
xhr.timeout=timeout||10000;
xhr.onload=function(){
if(xhr.status==200){
success(xhr.responseText);
}else{
error(xhr.statusText);
}
}
xhr.ontimetout=function(){
alert("请求超时,请重新请求");
}
}
</script>
FormData是 Ajax 2.0 -XMLHttpRequest Level 2 提供的一个接口对象,可以使用该对象来模拟和处理表单并
方便的进行文件上传操作。
ƒ FormData()
arguments: null
caller: null
length: 0
name: "FormData"
prototype: FormData
append: ƒ append()
delete: ƒ delete()
entries: ƒ entries()
forEach: ƒ forEach()
get: ƒ ()
getAll: ƒ getAll()
has: ƒ has()
keys: ƒ keys()
set: ƒ ()
values: ƒ values()
constructor: ƒ FormData()
Symbol(Symbol.iterator): ƒ entries()
Symbol(Symbol.toStringTag): "FormData"
__proto__: Object
__proto__: ƒ ()
[[Scopes]]: Scopes[0]
//01 创建空的formData实例对象
var data = new FormData();
//02 设置数据(添加)
data.set("age",18);
data.set("name","LiuY");
data.set("type","法师");
data.set("address","泉水中心");
//03 设置数据(修改和删除)
data.set("name","MiTaoer");
data.delete("address");
//04 设置数据(追加)
data.append("type","战士");
data.append("type","辅助");
//05 读取数据(指定key-one)
console.log(data.get("name")); //MiTaoer
console.log(data.get("type")); //法师
//06 读取数据(指定key-All)
console.log(data.getAll("type")); //["法师", "战士", "辅助"]
//07 检查是否拥有指定的key
console.log(data.has("age")); //true
console.log(data.has("email")); //false
//08 迭代器的基本使用(keys)
var keyIterator = data.keys() //获取迭代器对象
console.log(keyIterator.next()); //{done: false, value: "age"}
console.log(keyIterator.next()); //{done: false, value: "name"}
console.log(keyIterator.next()); //{done: false, value: "type"}
console.log(keyIterator.next()); //{done: false, value: "type"}
console.log(keyIterator.next()); //{done: false, value: "type"}
console.log(keyIterator.next()); //{done: true, value: undefined}
console.log("___________________");
//09 迭代器的基本使用(values)
var valueIterator = data.values(); //获取迭代器对象
console.log(valueIterator.next()); //{done: false, value: "18"}
console.log(valueIterator.next()); //{done: false, value: "MiTaoer"}
//10 迭代器的基本使用(entries)
console.log(data.entries().next()); //{done: false, value: ["age", "18"]}
//登入功能
"","data"=>"");
if($user!="zhujunjie"){
$arr["status"]="error";
$arr["data"]="账户不存在";
}else{
if($pwd=="123456"){
$arr["status"]="success";
$arr["data"]="成功";
}else{
$arr["status"]="error";
$arr["data"]="密码错误";
}
}
echo json_encode($arr);
?>
//某个网站的数据,
let lis = document.querySelector(".general").querySelectorAll("li");
let arr = [];
lis.forEach(li => {
let obj = {};
obj.src = li.querySelector("img").src;
obj.price = li.querySelector(".def-price").innerText;
obj.title = li.querySelector(".title-selling-point").innerText;
obj.dis = li.querySelector(".info-evaluate").innerText;
arr.push(obj);
})
//页面加载
window.onload = function() {
let oUl = document.querySelector("ul");
/* 2、根据商品数据来创建li标签渲染页面 */
$.getJSON("../server/sndata.json", (data) => {
let html = data.map(item => {
return `
¥${item.price}
${item.title}
${item.disCount}
${item.shopName}
`
}).join(""); //join连接所有数据成字符串
oUl.innerHTML = html;
})
}
/* 同源(相同的域):协议 + 端口号 + 主机相同 */
// 当前路径:http://127.0.0.1/code/day24/code/client/08-xxx.html
// 请求路径:http://127.0.0.1/code/day24/code/server/03.get.php
安全机制)
// 浏览器存在同源访问策略,就是我们在发送Ajax网络请求的时候,只有在同源的情况下才能成功,如果跨域了那么则无法处理(失败)
/* 跨域网络请求:浏览器因为安全机制的原因不允许我们直接发送跨域的ajax */
/* 但是在实际的开发中,我们确实有跨域的需求,那么我们可以使用某些方式来绕过这个同源策略 */
/* 我们发现在前端中,有一些标签是可以跨域,比如img 以及script*/
/* 特殊的标签 + json数据填充 = jsonP */
eg:
<script>
function jQuery324295843953403535390(obj) {
console.log(obj);
}
</script>
<script src="http://127.0.0.1/code/day24/code/server/04.jsonP.php?callBack=jQuery324295843953403535390">
</script>
## 四、数据库的介绍
1. 数据库的介绍(没法操作)
- 数据的仓库,专门用来存储和管理数据
- 其实任何一个能够存储数据的载体都叫数据库
- 但是根据数据库的操作和管理数据方式的不同,分类
- 关系型:mysql
- 非关系型:
2. mysql的介绍
- 关系型数据库**管理系统**
- 将数据按照表格的形式管理,如excel
- 所有的数据,按照行和列划分
- 行:记录(一条数据)
- 列:字段(表头)
- 多行多列组成了表(table)
- 多张表组成了数据库(database)
- 多个数据库被mysql管理
- mysql没有可视化操作界面(命令操作)
- 命令操作,不方便
- 第三方提供了,mysql的可视化操作工具(鼠标操作)
- 百度搜索关键字:mysql可视化操作工具 ********
- phpMyAdmin(网页版)
- SQL_front(客户端) 课上使用1
- navicat(客户端) 课上使用2
3. 第三方可视化操作工具(SQL_front)
- 下载
- phpStudy集成工具内下载
- 安装
- 自动安装
- 使用
- 打开
- 设置或选择登录信息,登录
- 登录成功后
- 左侧列表中,找到连接名,默认是:localhost
- 右键选择新建数据库
- 设置数据库名,点击确定(数据库名最好不要写中文)
- 在数据库名上右键新建表
- 设置表名,点击确定(表名最好不要写中文)
- 在表名上右键新建字段
- 输入字段名,点击确定(字段名最好不要写中文)
- 重复创建所需字段
- 对象浏览器中操作表字段
- 数据浏览器中操作数据
- 等同于Excel操作即可
- 点击右上角发布,保存信息
- 点击上方插入记录,添加信息
- 在要删除的信息上,右键删除
- 在要删除的字段上右键删除字段
- 在要删除的表上删除表
- 在要删除的数据库上右键删除数据库
4. 数据库的数据类型
- 数据库专门用来存储数据的
- 必然也会有数据类型
- 常用:
- 字符:
- 根据存储位置的长度,再次分为不同的类型
- CHAR 0~255
- VARCHAR 0~65535
- .......
- 整型:
- 根据数值的范围,再次分为不同的类型
- TINYINT 0~255
- SMALLINT 0~65535
# 零、端口
- 计算机端口,计算机相当于城堡,端口相当于不同的门
- 紫禁城,门相当多
- 每个门有不同的作用
- 计算机的每个端口都可以被赋予不同的功能
- apache默认是80端口
- mysql默认是3306端口
# 一、php操作mysql的语法
- 参考sql_front操作mysql的逻辑
0. 确认apache和mysql,都已经启动
1. 登录连接mysql,选择数据库
- $link = mysqli_connect(数据库地址,数据库用户名,数据库密码,要操作的数据库);
2. 对指定表中的数据进行增删改查了
- 向mysql发送sql命令的方法
- mysqli_query(sql命令);
- sql命令
- 增
- INSERT stu (name,age,cj) VALUES('王二','男','67')
- 删
- DELETE FROM stu WHERE id=6
- 改
- UPDATE stu SET name='李四' WHERE id>3
- 查
- SELECT * FROM stu
- 使用mysqli_query向mysql发送命令时,增删改,的返回值可以直接作为布尔值处理
- 但是查询操作,需要将返回值使用fetch系列方法解析,解析之后,才能得到数组或对象
# 二、常用网站的开发方式
1. 前后端分离:前端渲染页面 ***********
- 前端做前端的活,渲染页面
- 后端做后端的活,提供数据
- 后端提供**接口**,前端使用**ajax请求**接口,拿到数据,渲染页面
2. 前后端不分离:前端提前写好页面,由后端渲染到浏览器
- 前端负责页面排版,后端渲染页面
3. 在没有学习ajax之前,可以感受感受前后端不分离开发网站
4. 学了ajax之后,就可以前后端分离了
# 三、前后端不分离 实现 学生成绩管理系统
0. 项目逻辑
- 用户直接看到的得是个表单,采集信息(html)
- 提交到php,php拿到数据,操作数据库 和 逻辑(php)
- 数据库,做读写操作
- 逻辑,操作成功或失败后,做什么
- 注意每个操作之后的业务逻辑
- 成功了,要做什么
- 失败了,要做什么
1. 数据库的配合
- 数据库:nz2005
- 数据表:ScoreSheet
- 字段:name,sex,chinese,math,English
- 记录:张三,男,89,87,66
----
2. 如何使用php
3. 如何使用mysql
4. 如何使用php操作mysql
----
# 关于路径:
- 相对路径,一般用于当前服务器内的资源
- 绝对路径,一般用于其他服务器的资源
# 一些说明
- 学习ajax期间,仅仅会使用php做个简单的数据接收和返回,配合ajax
- 不要把已学的php和mysql荒废了
- 回到前端,回到老本行
#cookie
## 1. cookie的介绍
- 也是一种本地存储。
- 关于通信协议:
- 通信:传输信息
- 协议:约定
- 通信协议举例:
- IP:用来标记互联网上每台设备的唯一地址
- xxx.xxx.xxx.xxx
- xxx:0~255
- TCP:面向连接的协议(三次握手协议,可靠的通信协议)
- 通信之前,必须先建立连接
- 在么
- 在
- 我要发送数据了...
- 网上段子:你想听一个TCP的笑话么
- UDP:面向数据的协议(无连接协议,不可靠协议)
- 不用建立连接,直接发数据,也不确认
- 我是秦始皇,我穿越过来了,打钱,回头10倍奉还!卡号:XXXXXXXX,5000,马上!
- ......
- HTTP:超文本传输协议(网页传输协议,无状态协议)
- 连接之后,传输信息,信息传输结束,立即断开,忘掉所有内容
- 网购,整点秒杀
- 打开网站,登录
- 点击活动,登录
- 查看商品,登录
- 加入购物车,登录
- 付款,登录
- 记不住状态:登录状态,浏览记录,书签,播放记录.........
- 如果任由http记不住状态,会对用户造成极大的不便
- 所以,一种新的的技术应运而生
- cookie:会话跟踪技术
- 其实就是http每次连接的小秘书,帮助http记录每次连接产生的状态
- cookie:会话跟踪技术
- 可以记录浏览器每次连接产生的状态
- cookie记录到浏览器的缓存,所以,cookie也是本地存储的一种技术
- 所以,cookie会跟随http协议发往后台
- 意味着:cookie最好处于服务器环境中使用
## 2. cookie的特点
- 只能存文本
- 大小限制,大约4K
- 数量限制,大约50条
- 时间限制,默认:会话级(浏览器关闭);可以指定过期时间
- 不允许跨域,浏览器,网站,路径
- 注意:任何本地存储,都没有安全性,所以,不要在本地存储中直接存储账号密码,至少要加密
## 3. cookie的使用
- cookie是document的一个属性,这个属性值是个字符
- 通过给这个属性设置不同格式的字符,实现cookie的不同操作
- document.cookie
- 实现增删改查
- 有效期,路径
- 因为cookie用来记录http的状态,所以会跟随http发往服务器,最好将cookie放在服务器环境中使用
- 某些浏览器支持在本地环境使用cookie
Cookie:会话跟踪技术,可以用来存储少量的数据。
注意点:
[1] 存储大小限制(4KB)
[2] 存储数量限制(单个网页50个,网站200个)
[3] 有效期,默认有效期是当前会话(session-浏览器退出),我们可以通过代码来设置有效期。
[4] cookie数据不能够跨浏览器
[5] cookie数据不能够跨域的(相同的域,cookie数据可以共享)
Cookie和网络请求的关系和特点:
我们在发送网络请求的时候,默认总是会把Cookie数据一起提交服务器端。
<script>
/* ??? 假如我要取出某个特定的cookie值? */
// Cookie.getItem("className");
// Cookie.setItem("color","red");
// Cookie.setItem("id","red2324",7);
// Cookie.removeItem("color");
// Cookie.clear();
function getItem(key) {
let cookieSting = document.cookie; // "color=red; id=red2324"
let cookies = cookieSting.split("; "); //["color=red","id=red2324"]
for (let i = 0; i < cookies.length; i++) {
let currentItem = cookies[i]; //"color=red"
let temp = currentItem.split("="); //["color","red"];
if (key === temp[0]) {
return temp[1];
}
}
}
function setItem(key, value, day) {
if (typeof day === "number" && day > 0) {
let date = new Date();
date.setDate(date.getDate() + day);
document.cookie = `${key}=${value}; expires=` + date;
} else {
document.cookie = `${key}=${value}`;
}
}
function removeItem(key) {
let date = new Date();
date.setDate(date.getDate() - 1);
document.cookie = `${key}=""; expires=` + date;
}
function clear() {
/* 策略:先获取所有的cookie的key,遍历它们逐个删除 ["color","id"]*/
let keys = getKeys();
keys.forEach(key => removeItem(key));
}
function getKeys(key) {
let keys = [];
let cookieSting = document.cookie; // "color=red; id=red2324"
let cookies = cookieSting.split("; "); //["color=red","id=red2324"]
for (let i = 0; i < cookies.length; i++) {
let currentItem = cookies[i]; //"color=red"
let temp = currentItem.split("="); //["color","red"];
keys.push(temp[0]);
}
return keys;
}
// console.log(getItem("className"));
setItem("color", "red");
setItem("id", "red2324", 7);
// console.log(getItem("color"))
// removeItem("color");
</script>
1) 混入式继承(拷贝)
- 适用于单个的普通对象的情况(浅拷贝和深拷贝)
(2) 原型式继承(通过设置原型对象共享)
- 适用于两个构造函数创建实例对象的结构
- 核心:子构造函数.prototype = 父构造函数.prototype
- 解决:
- 在子构造函数的实例化对象中能够访问到父构造函数原型对象上面的成员
* 继承了父构造函数的原型成员
- 特点:
[√] 父类的原型成员
[x] 父类的实例成员
- 问题:父类的实例成员 && 存在共享的问题
(3) 原型链继承(借助原型链)
- 核心:设置子构造函数的原型对象指向父构造函数的实例对象
* 子构造函数.prototype = new 父构造函数
- 特点:
[√] 父类的原型成员
[√] 父类的实例成员
- 问题:
* 无法向父构造函数传递参数
(4) 借用构造函数实现继承
- 核心:在子构造函数的内容调用父构造函数并且绑定this为当前的实例对象
* Person.call(this, name, address);
- 解决
[√] 父类的实例成员,并且可以传递参数
[x] 父类的原型成员
(5) 组合继承
- 核心:借用构造函数继承 + 原型式继承
* Person.call(this, name, address)
* Boy.prototype = Person.prototype;
(6) class实现继承
/* (1) 混入式继承(拷贝) */
let o = {
name: "zs",
age: 18,
showName() {
console.log("name");
}
}
let t = {};
/* 浅拷贝 */
// for (let key in o) {
// t[key] = o[key];
// }
Object.assign(t, o);
console.log(t);
let Person = function(name, address) {
this.name = name;
this.address = address;
}
Person.prototype.showName = function() {
console.log("name", this.name);
}
Person.prototype.showAddress = function() {
console.log("address", this.address);
}
let Boy = function(name, address) {
this.name = name;
this.address = address;
this.sex = "男孩"
};
/* 原型式继承:核心是设置子构造函数的原型对象指向父构造函数的原型对象(原型对象共享) */
Boy.prototype = Person.prototype;
Boy.prototype.player = function() {
console.log("player");
}
let p = new Person("zs", "釜山");
console.log(p);
let b = new Boy("瓜瓜", "东莞");
console.log(b);
let Person = function(name, address) {
this.name = name;
this.address = address;
}
Person.prototype.showName = function() {
console.log("name", this.name);
}
Person.prototype.showAddress = function() {
console.log("address", this.address);
}
let Boy = function() {
this.sex = "男孩"
};
// Boy.prototype = Person.prototype;
/* 原型链继承:设置子构造函数的原型对象指向父构造函数的实例对象 */
Boy.prototype = new Person("小强", "东莞");
Boy.prototype.player = function() {
console.log("player");
}
let p = new Person("zs", "釜山");
console.log(p);
Boy.prototype.name = "小王";
let b1 = new Boy();
console.log(b1);
let b2 = new Boy();
console.log(b2);
let Person = function(name, address) {
this.name = name;
this.address = address;
}
Person.prototype.showName = function() {
console.log("name", this.name);
}
Person.prototype.showAddress = function() {
console.log("address", this.address);
}
let Boy = function(name, address) {
this.sex = "男孩";
/* call和apply方法 */
Person.call(this, name, address);
};
// Boy.prototype = Person.prototype;
// Boy.prototype = new Person("小强", "东莞");
Boy.prototype.player = function() {
console.log("player");
}
// let p = new Person("zs", "釜山");
// console.log(p);
let b1 = new Boy("小明", "东莞");
console.log(b1);
let b2 = new Boy("小张", "张家界");
console.log(b2);
let Person = function(name, address) {
this.name = name;
this.address = address;
}
Person.prototype.showName = function() {
console.log("name", this.name);
}
Person.prototype.showAddress = function() {
console.log("address", this.address);
}
let Boy = function(name, address) {
this.sex = "男孩";
/* call和apply方法 */
Person.call(this, name, address); /* 获取父构造函数的实例成员 */
};
Boy.prototype = Person.prototype; /* 获取父构造函数的原型成员 */
Boy.prototype.player = function() {
console.log("player");
}
let b1 = new Boy("小明", "东莞");
console.log(b1);
let b2 = new Boy("小张", "张家界");
console.log(b2);
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
showName() {
console.log("name", this.name);
}
showAge() {
console.log("age", this.age);
}
}
class Boy extends Person {
constructor(gf, name, age) {
super(name, age); /* 执行父类constructor方法并且生成一个this */
this.sex = "男";
this.gf = gf;
}
showGf() {
console.log("对象", this.gf);
}
showName() { /* 重写 , 也可以在子类的方法中调用父类的方法*/
super.showName();
console.log("姓名", this.name);
}
}
let b = new Boy("古力娜扎", "老王", 63);
console.log(b);
/* 实现继承关键:extends + 在子类的访问this前需要先调用父类 */
/* try...catch 异常捕获结构 */
/* 语法:try{ 多条语句 }catch(错误信息参数){ 出错后的处理方法 } finally{ 清理操作 }*/
/* 特点:当代码从上往下的执行的时候,如果出错了那么代码执行就会被终止,并且在控制台打印出错信息,后面的任务将不再执行。 */
console.log("1");
let likeArr = {
0: "name",
1: "age",
length: 2
};
console.log("2");
/* 特点:尝试执行try后面的代码,如果出错了那么就把错误信息传递给catch,并且在catch中进行错误的处理 */
/* 如果没有错误,那么就正常执行,catch中的代码将不会被执行 */
try {
// likeArr.forEach(item => console.log(item));
let b = 123;
} catch (e) {
console.log("代码执行出错了", e);
// throw "代码执行出错了"; /* 抛出异常:后面的代码就不会再执行。 */
// throw new Error("代码执行出错了:" + e);
} finally {
/* 不管try里面的代码是否出错,都会执行该代码块 */
console.log("finally");
}
console.log("3");
/* 单个任务的执行方式:同步执行和异步执行 */
/* 同步:必须要等当前任务执行完,才会执行后面的任务,如果当前任务没有执行完那么将一直等待(阻塞式)。 */
/* 异步:不必等当前任务执行完就可以执行后面的任务。 */
/* JavaScript代码是如何执行的? */
/* 串行:先执行任务1,再执行任务2,再执行任务3 有顺序的去执行谁先执行完取决于这个任务的具体情况(同步|异步|时间)。*/
/* 并行:多个任务同时执行。 */
/* Promise 承诺|保证 */
/* 1、Promise 本身是一个类(构造函数),在使用的时候需要通过new来调用 */
/* 2、Promise 存在三种状态:pending(等待态) resolve(成功态) reject(失败态) */
/* 3、状态切换:pending->resolve pending->reject */
/* 4、基本结构: 我们在实例化对象的时候,Promise接收一个函数作为参数,该函数又拥有两个参数(函数) */
/* resolve函数:当调用这个函数的时候,表明任务成功了,reject表明任务失败了 */
// let promise = new Promise((resolve, reject) => {
// setTimeout(() => {
// console.log("task1");
// /* 说明定时器异步任务已经结束了(成功|失败) */
// /* 在异步任务中,我们应该根据任务的执行情况来主动告诉Promise当前任务成功了还是失败了 */
// /* 如果成功,那么应该调用resolve(),如果在调用的时候有数据需要传递,那么就直接以参数方式传递 */
// /* 如果失败,那么应该调用reject(),如果在调用的时候有数据需要传递,那么就直接以参数方式传递 */
// // resolve("成功的原因:我的任务很简单!!!");
// reject("失败的原因:我不够帅!");
// }, 1000)
// });
// /* promise.then(successCallBack,failCallBack) */
// promise.then((data) => {
// console.log("success-data", data);
// }, err => {
// console.log("error-err", err);
// })
new Promise((resolve, reject) => {
setTimeout(() => {
console.log("task1");
/* 说明定时器异步任务已经结束了(成功|失败) */
/* 在异步任务中,我们应该根据任务的执行情况来主动告诉Promise当前任务成功了还是失败了 */
/* 如果成功,那么应该调用resolve(),如果在调用的时候有数据需要传递,那么就直接以参数方式传递 */
/* 如果失败,那么应该调用reject(),如果在调用的时候有数据需要传递,那么就直接以参数方式传递 */
// resolve("成功的原因:我的任务很简单!!!");
reject("失败的原因:我不够帅!");
}, 1000)
}).then((data) => {
console.log("success-data1", data);
}, err => {
console.log("error-err1", err);
})
.then((data) => {
console.log("success-data2", data);
}, err => {
console.log("error-err2", err);
}).then((data) => {
console.log("success-data3", data);
}, err => {
console.log("error-err3", err);
})
* 存在多个异步任务(A,B,C),我们要求ABC这三个异步一起执行,要等着三个任务都执行完再执行后面的操作 */
/* 请求A name */
/* 请求B age */
/* 请求C email */
/* 请求A && 请求B && 请求C 都完成后,把他们的结果组成到一个对象中 {name:"zs",age:12,email:zs@126.com} */
let p1 = new Promise((resolve, reject) => {
$.ajax({
url: "./server/1.php",
success(data) {
console.log("1成功了", data);
resolve(data)
}
})
});
let p2 = new Promise((resolve, reject) => {
$.ajax({
url: "./server/2.php",
success(data) {
console.log("2成功了", data);
resolve(data)
}
})
})
let p3 = new Promise((resolve, reject) => {
$.ajax({
url: "./server/3.php",
success(data) {
console.log("3成功了", data);
resolve(data)
}
})
})
// Promise.all([p1, p2, p3]).then(data => {
// console.log("所有的任务都成功了", data)
// }, err => {
// console.log("任务失败了", err);
// })
/* */
Promise.race([p1, p2, p3]).then(data => {
console.log("最快的已经来到了这里,其他的任务我已经不关心了", data)
}, err => {
console.log("任务失败了", err);
})
/* Promise.all | Promise.race */
/* Promise.resolve() Promise.reject() 快速包装一个Promise对象 */
// new Promise((resolve, reject) => {
// setTimeout(() => {
// console.log("task1");
// // resolve("成功的原因:我的任务很简单!!!");
// // reject("失败的原因:我不够帅!");
// }, 1000)
// }).then((data) => {
// console.log("success-data1", data);
// }, err => {
// console.log("error-err1", err);
// })
// Promise.resolve(123).then((data) => {
// console.log("success-data1", data);
// }, err => {
// console.log("error-err1", err);
// })
pwd [Print Working Directory]
作用:查看当前目录
cd [Change Directory]
作用:切换目录
示例01:cd 目录 进入到指定目录
示例02:cd ../ 返回上一层目录
$ cd Desktop/
$ cd /Users/文顶顶/Downloads/jquery-master
ls [List]
作用:查看当前目录下内容
参数:usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]
示例01:ls 列出当前目录下面的所有文件
示例02:ls -a 列出当前目录下面的所有文件(包含隐藏文件)
示例03:ls -l 列出当前目录下面的所有文件(列表方式),包含文件的创建者和时间等信息
示例04:ls -s 列出当前目录下面的所有文件(打印文件的大小)
示例05:ls -t 列出当前目录下面的所有文件(按照时间来排序)
示例06:ls -S 列出当前目录下面的所有文件(包括子目录递归)
mkdir [Make Directory]
作用:创建目录
参数:usage: mkdir [-pv] [-m mode] directory ...
示例01:mkdir Demo 创建Demo文件夹(目录)
示例02:mkdir -v demo 创建demo文件夹并输出提示信息
示例03:mkdir -p test/sub1 创建test文件夹并在该目录中创建sub1文件夹
touch
作用:创建文件
示例01:touch index.html 在当前目录中创建index.html文件
wc [Word Count]
作用:获取文件的字数信息统计
参数:usage: wc [-clmw] [file ...]
示例01:wc a.text 获取a.text文件的字数统计信息
示例02:wc -c a.text 获取a.text文件的字数统计信息(统计字节数)
示例03:wc -l a.text 获取a.text文件的字数统计信息(统计行数,从0开始计数)
示例04:wc -m a.text 获取a.text文件的字数统计信息(统计字符数)
示例05:wc -w a.text 获取a.text文件的字数统计信息(统计单词数)
echo
作用:输出字符串
示例01: echo "123" > a.text 向a.text文件中输入123字符串(替换)
示例02: echo "123" >> a.text 向a.text文件中输入123字符串(追加)
vim
vim c.txt 编辑这个文件
按下键盘上面的i这个按键,文件就进入到了插入(INsert)状态,编辑文件的内容,编辑完成后
esc + shift + : + wq
cat [Concatenate files and print on the standard output]
作用:查看|创建|合并文件
补充:
示例01:cat index.html 打印并查看index.html文件的内容
示例02:cat > b.text 新建文件b.text并输入内容,需保存
示例03:cat a.text b.text > c.text 合并两个文件的内容给c.text
示例04:cat -n a.text 输出a.text文件的内容并显示行号(空行会被编号)
示例05:cat -b a.text 输出a.text文件的内容并显示行号(空行不被编号)
示例06:cat -n b.text >> a.text 对b.text文件的内容加上行号然后追加到a.text文件中
示例07:cat -n b.text > a.text 对b.text文件的内容加上行号然后替换a.text文件的内容
rm[remove]
作用:删除文件 Recurve(递归)
参数:usage: rm [-f | -i] [-dPRrvW] file ...
示例01: rm a.text 删除a.text文件
示例02: rm -i a.text 删除文件前会逐一询问确认,输入YES表示删除
示例03: rm -f a.text 强制删除a.text文件不会询问确认
示例04: rm -r test 删除test文件夹以及该目录下面所有文件
示例05: rm -r * 删除当前目录下面所有的文件
示例06: rm -rf /* 递归删除所有文件(不提醒)
rmdir (Remove Directory)
作用:删除文件夹,只能删除空文件夹,不常用
示例01:rmdir a 删除文件夹a
clear 清屏操作
mv [move]
作用:移动文件或重命名
示例01:mv index.html ./demo/index.html
示例02:mv index.html a.html
cp [copy]
作用:复制文件
示例01:cp index.html ./demo/index.html
history 查看操作历史
curl 发送网络请求
who am i 查看当前用户信息
tab 自动补全,连按两次会将所有匹配内容显示出来
项目托管工具
Git历史
1991年,Linus创建了开源的Linux操作系统项目,一直到2002年,开源项目团队都还是通过diff的方式来管理Linux操作系统项目。
2002年,Linus选择BitKeeper版本控制工具来管理Linux项目源码,BitMover公司出于软件自由的精神授权Linux社区免费使用这个版本控制系统。
2005年,开源项目团队成员 Andrew试图破解BitKeeper的协议,被BitMover公司后要求收回Linux社区的免费使用权。
2005年,Linus自己使用C语言写了一个分布式版本控制系统,这就是Git!随后,Git迅速成为最流行的分布式版本控制系统。
git 开源的版本管理工具 ---- github公司全球的代码托管网站,内部使用版本管理工具(git)
林纳斯 (殿堂级别的人物) Linux
三大区的概念
Workspace:工作区,就是你平时存放项目代码的地方
Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息
Repository:仓库区|版本库(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本
Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换
文件的四种状态
[1] Untracked:
未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.
[2] Unmodify:
文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件
[3] Modified:
文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改
[4] Staged:
暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified
工具软件
github桌面工具 https://desktop.github.com/
sourceTree工具
关键:
git add 把修改或者是更新提交到暂缓区
git commit 把暂缓区 的更新提交到版本库
git init 初始化仓库
git config --global user.name 名字
git config --global user.email 名字
git status 查看状态
git add 把文件的更改提交到暂缓区
git commit -m "注释"
git log 打印提交日志信息
git log --oneline | wc -l 提交次数统计
git log --stat 显示commit历史,以及每次commit发生变更的文件
git log -p [file] 显示指定文件相关的每一次diff
git diff 现实暂存区和工作区的差别
git log --graph 以图形化的方式显示提交历史的关系
git clean -df 移除所有没有跟踪的文件(-d表示包含目录,-f表示强制清除)
git reflog
git branch 查看所有的分支(绿色表示当前正在工作)
git branch developer 创建(开启)新的分支
git checkout developer 切换当前工作的分支
git merge developer 合并分支(把其他的分支合并到master主干)
git branch -d developer 删除分支(注意不能删除当前分支)
git reset --hard 哈希值 版本回退
git clone [url] 下载git仓库到本地
git push 将本地分支的更新,推送到远程主机
git pull 取回远程主机某个分支的更新,再与本地的指定分支合并
git tag // 查看当前仓库的 tag 信息,如果当前没有版本则显示为空
git tag -l "v1.0.*" // -l命令可以使用通配符来过滤 tag 版本
git tag v1.0.0 // 新建 tag 版本
git tag // 查看查看当前仓库的 tag 信息
git tag -a v1.0.1 -m "版本v1.0.1" // -a参数可以在创建 tag 的时候添加备注信息由-m指定
git show tagName // 用于查看指定版本的详细信息
git push origin [tagName] // 将 tag 同步到远程的服务器
git push origin --tags // 推送本地所有的 tag
git checkout tagName // 切换tag , 可以切换 tag 并基于该 tag 来创建分支
git tag -d tagName // 删除 tag
git push origin :refs/tags/// 删除远程的tag
解决方案:
在公司的局域网服务器上面初始化共享版本库,并且进行配置。 (要求比较高)
把项目托管在第三方的网站上面(gitHub OSChina-码云 GitLab coding.net)。
步骤:
1.新创建仓库。
2.命令行切换到www文件夹下面
3.把github上面的仓库下载到本地(wwww)
4.命令行要切换到这个目录 cd ttttt/
5.把我们的项目拷贝到当前的目录中
tttt
.
├── LICENSE
├── README.md
├── .git
└── 项目
├── client
└── server
3 directories, 2 files
6.把项目文件添加到暂缓区 git add .
7.把暂缓区的内容添加到本地的版本库 git commit -m "初始化"
8.把本地版本库更新提交到远程版本库 git push
9.需要输入用户名和密码(github帐号-密码)
每天 commit 十几次,push 两三次 (没有bug)
$ git add .
通常每做完一个功能模块那么就commit一次
$ git commit -m "创建两个文件"
$ git push
SSH Key 的配置:github允许两种登录方式:帐号和密码 + SSH (非对称加密算法) [先生成一个密钥对(公钥-私钥),把公钥保存到github网站上面]
1.先通过命令行来生成密钥对(路径使用默认-不设密码 敲三个回车键)
$ ssh-keygen -t rsa -b 4096 -C "wendingding@vip.com"
2.打开指定路径中保存的id_rsa.pub文件,拷贝这个文件的内容
3.在gitHub网站上面https://github.com/settings/keys点击New SSH key把拷贝的内容粘贴到此处即可。
4.以后在clone仓库的时候,通过SSH路径克隆即可。