JS学习总结第五周
周一
1、保护对象:保护对象的属性和方法
1、每个属性都有四大特性:
{
value: '很多', //实际保存值的地方
writable: true, //开关,控制着这个属性是否可以被修改 - 默认值为true
enumerable: true, //开关,控制着这个属性是否可以被for in循环遍历到 - 默认值为true
configurable: true //开关,控制着这个属性是否可以被删除 - 默认值为true,总开关:一旦设置为
false,其他特性不可以再修改,而且他本身也是一旦设置为false,不可逆
}
修改四大特性:
1、
Object.defineProperty(对象名,"属性名",{
四大特性
})
调用一次方法只能保护一个属性的四大特性
2、
Object.defineProperties(对象名,{
"属性名":{四大特性},
...
})
至少方法只调用了一次,但是四大特性写着始终麻烦,甚至不能防止添加
2、三个级别:
//1、防扩展:防添加
Object.preventExtensions(obj);
//2、密封:防添加防删除
Object.seal(obj);
//3、冻结:防添加防删除防修改
Object.freeze(obj);
保护对象不重要:为什么说他垃圾?
1、如果你不用面向对象开发,那你也没有对象可以保护
2、前辈们都没有保护,我们也不用保护
3、别人一般来说都不可能知道你取得对象名字叫什么
***四大特性,其实应该叫六大特性 - 可以帮助我们做出动态数据,以后不会手动使用,只是明白Vue底层就是用到了set拦截操作
Object.defineProperty(lhl,"name",{
get:()=>{
console.log("获取数据会进行拦截操作");
},
set:v=>{
console.log("设置数据会进行拦截操作"+v);//v拦截到的数据
h1.innerHTML=v;
},
})
2、*对象的深浅拷贝:
1、浅拷贝:利用按值传递
var obj1={"name":"obj1"};
var obj2=obj1;
2、深拷贝:两者互不影响
var obj1={"name":"obj1"};
var obj2={...obj1};
3、*以后如何脱掉后传来的数据的衣服:
后端穿衣服:var JSONtxt=JSON.stringify(obj); - Node.js就是这句话,Node.js也是“js”,历史上第一次一门语言可以通吃前后端
前端脱衣服:var jsonObj=JSON.parse(JSONtxt);
此方法也能实现深拷贝
3、*Error对象:错误
1、以后工作/学习的目的:
1、快速找到错误
2、记住要防用户
2、***浏览器自带4种错误类型:可以快速找到自己的错误
1、语法错误:SyntaxError - 一定是你的符号/语法写错
2、引用错误:ReferenceError - 没有创建就去使用了
3、类型错误:TypeError - 不是你的方法,你却去使用了
4、范围错误:RangeError - 只有一个API会碰到:num.toFixed(d);//d取值范围:0~100之间
3、只要发生错误,就会报错,会导致后续代码终止(闪退),我们不希望
错误处理:就算发生错误,我们也不希望报错,而是给出一个错误提示,让后续代码依然可以继续执行!
语法:
try{
只放入你可能出错的代码
}catch(err){
发生错误后才会执行的代码
err形参就保存着错误的消息,只不过是英文的,中国人不一定看得懂,所以建议你添加上中文的错误提示
}
try...catch...的性能非常的差,几乎事所有代码里性能最差的,放在try中的代码效率都会被降到最低
*可以用一个技术代替他:分支技术!
*开发经验的累计:记住一切的客户端输入/用户输入都是坏人 - 但是你不担心,只要你做还要防护就不会出错(!isNaN、正则)
4、抛出自定义错误:只要是错误,后续代码都不会执行
throw new Error("自定义错误消息")
5、ES5:严格模式
开启:"use strict" - 写在任何一个作用域的顶部都可以
作用:
1、禁止了全局污染,使用变量之前必须先创建变量
2、将静默失败升级为报错
铺垫:以后我们用了gulp技术打包项目后,有的js会自动加上严格模式,我劝你把他删掉
4、柯里化函数:
function add(a){
return function(b){
return function(c){
console.log(a+b+c)
}
}
}
add(3)(5)(7);
周二
1、*匿名函数:没有名字的函数,有两种用法:
1、自调:只能执行一次,好处:函数中的没有用的变量是会自动释放的,它可以用于代替全局代码写法,两者
很相似,都只会执行一次,但是自调会释放没用的东西
(function(){
操作;
})();
2、回调:匿名函数不是自调,就是回调,所以回调函数,我们往往只需要学习如何使用即可
elem.on事件名=function(){}
arr.sort(function(){})
xxx.api(function(){})
var obj={
"方法名":function(){}
}
一切的回调函数,都可以简化为箭头函数
2、设计模式:不仅仅局限于前端,它是一种编程【思想】,越来越复杂,对于我们前端人来要求也会越来越高!
1、单例模式:也称之为单体模式,保证一个类仅有一个实例对象创建,并且提供一个访问它的全局访问点:为了
三阶段的Vue做准备:new Vue一个页面只写一次/一个!
如何实现:
最简单的单例模式:利用ES6的let不允许重复声明的特性,刚好就符合了单例的特点:
let obj={
"name":"袍哥1",
"getName":function(){return this.name},
}
不太推荐这种写法:
1、污染命名空间(容易变量名冲突,会报错)
2、维护时不易管控(搞不好就直接覆盖了)
推荐写法:
var h52302=(function(){
let state=null;
return function(name,age){
this.name=name;
this.age=age;
if(state){
return state;
}
return state=this;
}
})();
h52302.prototype.sayHello=function(){
console.log(this.name);
}
var x=new h52302("xxx",18);
var y=new h52302("yyy",19);
console.log(x);
x.sayHello();
console.log(y);
y.sayHello();
2、观察者模式:也有人称呼叫做发布订阅模式:为三阶段vue的bus总监用到的底层原理就是我们的发布订阅模式
现实举例:QQ空间,朋友圈,微博...
let obj={};
//创建订阅者
function on(id,fn){
if(!obj[id]){//判断有没有此id(有没有这个人),没有我就创建了一个空数组
obj[id]=[];
}
obj[id].push(fn);//obj["袍哥"]=[(msg)=>{console.log("小胡来了",msg)},(msg)=>
{console.log("小罗来了",msg)},(msg)=>{console.log("小向来了",msg)}]
}
on("xx",(msg)=>{console.log("小胡来了",msg)})
on("xx",(msg)=>{console.log("小罗来了",msg)})
on("xx",(msg)=>{console.log("小向来了",msg)})
on("xx",(msg)=>{console.log("小张来了",msg)})
on("xx",(msg)=>{console.log("小王来了",msg)})
on("xx",(msg)=>{console.log("小李来了",msg)})
//发布者的操作
function emit(id,msg){
obj[id].forEach(fn=>fn(msg));//obj["袍哥"].forEach(fn=>fn("一支穿云箭"))
}
btn.onclick=()=>{
emit("xx","一支穿云箭");
}
3、*事件轮询:js其实是单线程应用,代码必须是从上向下执行的,一步一步执行的,如果某一块代码非常耗时,可能会导致整个页面都卡住了,尤其如果你把js放在head之中,会看到页面是一个白板!
1、宏任务:不会再卡住我们的单线程应用,可以让后续代码先走,我们慢慢跟着来,但是问题在于,多个宏任务
同时存在,到底谁先执行,谁后执行,分不清楚
1、定时器:setInterval和setTimeout()
2、AJAX:
2、微任务:ES6提供了Promise对象 - 可以控制异步代码,依然是异步代码,但是可以控制执行的顺序了
function ajax1(resolve){
setTimeout(()=>{
console.log(1);
resolve();//放行函数
},Math.random()*5000)
}
function ajax2(){
return new Promise(resolve=>{
setTimeout(()=>{
console.log(2);
resolve();
},Math.random()*5000)
})
}
function ajax3(){
return new Promise(resolve=>{
setTimeout(()=>{
console.log(3);
resolve();
},Math.random()*5000)
})
}
new Promise(ajax1).then(ajax2).then(ajax3);
console.log("后续代码");
html5十大新特性:不单单只是由标签组成。h5其实是一个综合概念
1、新的语义标签(nav header section article aside footer)
2、增强性表单(表单2.0);
3、音频和视频(audio 和 video)
4、Canvas绘图 - 统计图,以前18年的大纲里有它,后来淘汰了(不是他不行,是你们不行,你画出来会很丑),
我们数据可视化使用echart.js
5、Svg绘图 - 小图标
6、地图 - 百度/高德
7、拖放API事件
8、web worker
9、web storage
10、web socket
周三
可能成为全栈的语言:
1、Java语言 - 里面有JavaWeb,但是不包含移动端(安卓)
2、JavaScript语言:
客户端 - 开发根本
服务器端 - Node.js 历史第一次一门语言可以通吃前后端(前端崛起的原因之一)
数据库 - mongoDB
移动端 - 网页/app(跨所有平台的:IOS/Andriod)/小程序/公众号
前端崛起的原因之一:三阶段你会学习混合开发框架:jQueryMobile/h5+plus/【uniapp】
- 只需要一个前端学一点点IOS/Andriod的语法就可以搞定了
前端的崛起导致IOS/Andriod开发者大量的失业:千万不能啃老本
1、基本内容:
服务器端概念:
简单来说就是一台电脑
生活中:微机
商业中/国家用:小型机(造价大概几十万好的上百万) + 中型机 + 大型机 + 超级计算机
拥有服务器的方式:
1、买 - 对中小型公司不友好
2、买一台配置好一点的微机 - 对于别的行业的公司也不太划算
3、租云服务器 - 腾讯云、阿里云、新浪云、百度云...配置咨询,配置越好,价格越高,按年收费
软件架构:服务器端很重要
C/S架构 - Client客户端/Server服务器端
举例:QQ、微信、大型网络游戏
优点:
1、用户体验感较好
2、运行稳定
3、对带宽的要求低
缺点:
1、占硬盘空间
2、更新过于麻烦 - 服务器端和客户端都要更新
B/S架构 - Browser浏览器端/Server服务器端
举例:网页版QQ、网页版微信、网页游戏
优点:
1、几乎不占用硬盘
2、更新简单 - 只需要更服务器端
3、电脑在垃圾都可以玩得起!- 不吃配置,代码都在服务器那边运行
缺陷:
1、用户的体验感较差(越来越好,尤其是现在出现了云平台,根本不用考虑你的电脑好不好,配置
如何)
2、对于带宽的要求高(还好现在的网速越来越快的)。
3、Node.js概述:不是JS,但是语法和JavaScript非常相似,他的竞争对手:Java、C++、C#、python、PHP...
功能绝对不是做特效的!做的事和服务器端其他语言是一致(和数据库进行交互,成为了一个前端到数据库的中间
桥梁)
目的:
1、使用代码搭建一个服务器&文件系统(服务器文件可以放在任何位置,但是不在你的电脑里,你也可以根据
网址来访问我的东西)
2、Node.js如何沟通前端和数据库(增删改查)
3、全栈项目:图书管理系统(HTML+CSS+JS+NODE+MONGO)
4、Node.js如何运行:3种
1、交互模式 - 临时测试
打开cmd输入:node回车,你就可以开始敲你的“js”代码
2、脚本/文件模式 - 正式开发中
1、先创建xx.js,里面书写自己的代码
2、打开cmd输入:node 文件的绝对路径
3、编辑器越来越强大了,安装插件:前提:至少前两个方法能够成功,才可以安装插件
vscode - 插件:code runner,对着代码处右键,第一个选项就是code runner,或者右上角
有一个开始按钮可以点击,有的同学(输出会乱码,可以百度找解决方案)
4、Node.js知识:
1、js和node的区别
相同点:都可以使用一切的ECMAScript(那11个)的东西,包含一切的API,都可以使用,在服务器端不存在
任何浏览器,所以不必担心兼容问题
不同点:
1、JavaScript:ES+BOM+DOM - 做特效的
2、Node.js:一切的BOM和DOM都没有,虽然没有BOM和DOM,但是他却又10万+个以上的模块等待我们学习
2、模块(module):每一个xx.js,都可以称之为是一个模块
1、模块化开发:如果以一个网站来说,我们可以按功能分为很多模块:商家模块、商品模块、促销模块、
用户模块、产品模块....
分工合作:将每个模块交给对应的人完成,最后再由【主模块】进行引入:
2、每一个模块都有一个操作,可以用于公开/暴露自己的成员
Node.js自带一个预定义变量:exports,可以直接使用,是一个对象,放在此对象里面的东西,就是
允许公开的东西
语法:
1、exports.属性名=值;
2、module.exports.属性名=值;
3、module.exports={
属性名:属性值,
...
}
错误导出法:
exports={
"name":"袍哥1",
"age":18,
hobby:"吃饭"
};
3、每一个模块(主模块)都有一个操作,可以用于引入/导入其他模块
Node.js自带一个预定义变量:require,可以直接使用,是一个函数,放在此函数里面的路径,就是
允许引入的模块文件
语法:
var x=require("./路径");
面试笔试题:exports和module.exports有什么区别?
1、语法、写法,用法不同
2、都是用于公开暴露自己的成员的
但是exports={},写法是错误的
其实Node.js底层有一句话:exports={}
其实真正做公开功能的是module.exports
如果你使用了 exports={};//你创建了一个新的空对象,把module.exports覆盖了,
所以不再具有公开的功能
3、模块的分类:
1、官方模块 - 今日的目标,大概有二十几个,但是重要的其实只有几个
2、第三方模块 - 在npm上放着的,多到数不清楚,提供了很多官方没有的东西,明天我在学习,可以上传也可以去下载
3、自定义模块
Node.js最大的特点:
1、快,非常快 - 以前最快的是php,js的速度是php的十六倍
2、为什么这么快
1、因为官方模块提供的东西少,甚至连操作数据的API都没有提供过
2、使用chrome浏览器的v8引擎
4、官方模块:不需要下载,在你安装node.js环境的时候就已经带上了,但是某的模块需要
引入,某的模块不需要引入
1、Global模块:不需要引入的,可以直接使用
提供了:
1、五个预定义变量,可以直接使用了
1、__filename - 获取到当前文件完整的绝对路径
2、*__dirname - 获取当前文件绝对路径,不包含文件的名字,何时:vscode的
某些同学可能不支持node.js上书写相对路径,只能书写绝对路径,但是
绝对路径全由自己写又很累,有了此变量我们可以直接拼接!
- 【文件系统】!
3、*exports - 空对象,可以用于公开暴露自己的成员
4、*require - 函数,可以用于导入其他模块
5、***module - 指代当前模块本身,甚至包含着以上4个操作
2、定时器(周期性、一次性、瞬间定时器):定时器不是当初
的定时器,只不过用法和当初一模一样!
3、console也不是当初的console,只不过用法和当初一模一样!
2、querystring模块:解析查询字符串,使其变成一个对象,可以获取到前端传到后端
的消息(前端传到后端的消息-请求消息)
需要引入:var qs = require('querystring');
作用:解析url中查询字符串部分的功能
var obj=qs.parse("查询字符串");
想要获得前端传来的每一个部分:obj.键名;
垃圾:如果前端传来的是一个完整的url网址,他就解析不了
3、***url模块 - 今日小重点
需要引入:var url = require('url');
作用:解析url中各个部分的功能
var objUrl=url.parse("完整的url",true);//支持第二个参数,是一个布尔值,默认为false,一旦
设置为true,就会自动使用querystring的parse方法去解析查询字符串部分
***真正的重点:
1、查询字符串/请求消息:objUrl.query.键名; - 前端form(GET)表单提交到后端的东西
2、路由/文件相对路径/请求地址:objUrl.pathname - 判断路由的不同,去读取不同的
HTML发送给我们的用户看!
4、Buffer模块:缓冲区,可以将数据变成一个16禁止的数字,你可以理解为是Node.js中的一种新的数据类型,
但是我们绝对不会手动使用,因为我们一眼看不懂!
但是后端的一些API可能会导致我们被动得到Buffer,但是你也别怕,因为Node.js中大部分
API,都是支持Buffer
5、*****fs模块 - 今日大重点:fileSystem文件系统
需要引入:var fs = require('fs');
*异步读取文件:
fs.readFile(文件路径,(err,buf)=>{
console.log(buf);->读取到了要干什么,必须放在这个回调函数里面!
})
异步写入文件:
fs.writeFile(文件路径,"新内容"/buf,(err)=>{
console.log("写入完毕后要做什么,必须放在里面")
})//会替换掉原来的东西
异步追加文件:
fs.appendFile(文件路径,"新内容"/buf,(err)=>{
console.log("写入完毕后要做什么,必须放在里面")
})//不会替换掉原来的东西
强调:只有异步才能更完美的发挥Node.js的特点(快)
周四
1、Node.js官方模块:
6、http模块 - 超级重点:搭建服务器&文件系统
var http=require("http");
var url=require("url");
var fs=require("fs");
//创建服务器应用
var app=http.createServer();
//为其绑定端口号
app.listen(80);
//为其绑定了请求事件:http:请求 - 响应模型,必须要有一个请求(前端),才有一个响应(后端)
app.on("request",(req,res)=>{//只要有人来请求,我就会触发
//req:request(请求)对象,他有一个属性叫做req.url,获取到前端传到后端的路由和请求消息,但是路由
和请求消息是融为一体,不方便我们获取某个部分,所以我们可以引入url,进行解析!分开两部分
var objUrl=url.parse(req.url,true);
//把路由保存了起来!
var router=objUrl.pathname;
if(router=="/"||router=="/index.html"){//判断路由的不同,读取不同的页面给用户看,引入fs文件模块
//res: response(响应)对象,他有一个方法叫做res.end("响应的内容"/buf) - 可以想应该给前端想要
看的东西
fs.readFile(__dirname+"/public/html/index.html",(err,buf)=>{
res.end(buf)
})
}else if(router.match(/html/)!=null){
fs.readFile(__dirname+`/public/html${router}`,(err,buf)=>{
res.end(buf)
})
}else if(router.match(/css|js|jpg|png|gif|woff|woff2|ttf2/)!=null){
fs.readFile(__dirname+`/public${router}`,(err,buf)=>{
res.end(buf)
})
}
})
扩展:字符串有一个API:match
var rs=str.match(reg);//几乎和indexOf一致,但是支持正则,我们不关心为什么,只关心为不为null
强调:一切的src和href都是一个请求都是一个路由,这个请求就需要后端来解析,根据不同的请求响应不同的
内容!
为什么有的模块引入要./有的又不用./?
自定义模块:分为两大类
1、文件模块:创建xx.js去公开了需要公开的内容,主模块引入,就必须写为require("./模块路径");
2、目录模块:3种
1、比如创建m1的文件夹,在其中创建index.js的文件,去公开了需要公开的内容,主模块引入,
就必须写为require("./m1");
2、比如创建m2的文件夹,在其中创建suibian.js的文件,去公开了需要公开的内容,主模块
引入,就必须写为require("./m2");
必须在创建一个必须名package.json的配置文件,写入:{"main":"suibian.js"}
3、创建一个文件夹必须名为node_modules,在在其中创建创建m3的文件夹,在其中创建
index.js的文件,去公开了需要公开的内容,主模块引入,就必须写为require("m3");
其实真实开发中,我们程序员用的最多的就是文件模块,目录模块的第三种方式其实根本不是给人用
的(第三方模块下载后会自动创建此文件夹)
3、如何下载第三方模块:
npm工具:Node Package Manager - Node.js的模块/包/软件管理器,专门用于管理第三方模块的,
作用:下载、更新、删除、维护包之间的依赖关系
检查npm是否安装成功:npm -v 如果能看到版本号,说明安装成功
打开网址:npm官网:[www.npmjs.com](http://www.npmjs.com)
搜索你需要用到的模块,尽量用带有完全符合标签的那个包,或者是 第一个包
在你的项目之中打开cmd
1、下载:npm i 包名
2、删除:npm un 包名
3、更新:npm up 包名
周五
mongo就是基于json的数据库:json就是JavaScript Object Notation - JS的一部分,所以用法和JS的用法都很像,都是用.去做操作
1、安装&启动:
1、解压我提供的mongodb-win32-x86\_64-2008plus-ssl-3.6.11.zip文件
2、打开bin文件夹,里面有:mongo.exe(客户端) 和 mongod.exe(服务器端)
3、如何启动:
在bin文件夹中打开cmd:输入:.\mongod.exe --dbpath=你想要保存的绝对文件夹路径 - 服务器开启
成功,而且那个文件夹就是保存着你以后要存储的所有的数据
千万不要关闭mongo服务器端的cmd
再打开一个cmd:输入:.\mongo.exe - 再上一个cmd可以查看我们是否连接成功 - 客户端开启成功
2、mongo的语法:都是在客户端cmd输入
1、数据库的操作
1、查询所有数据库:show dbs
2、创建/切割数据库:没有就创建,有了就切换:use 数据库名称
3、查看当前选中的数据库:db
4、创建数据表:db.createCollection("表名");- 没有限制,无限,一定要先创建数据表后,我们才能
查看到自己创建的数据库
5、删除数据库:db.dropDatabase(); - 一旦删除就不能恢复,不推荐,因为要坐牢,最好忘记
2、数据表的操作
1、创建数据表:db.createCollection("表名",{size:5242880,capped:true,max:5000}); - 最大
存储空间为5mb,最多存储5000个,意味着这个数据表做了限制,不推荐
2、查看目前所有的数据表:db.getCollectionNames();
3、删除数据表:db.表名.drop(); - 一旦删除就不能恢复,不推荐
3、*****数据的操作
1、增:db.表名.save({键值对,...}) - 一次只能插入一条数据
db.表名.save([{},{},{},{},....]) - 一次插入多条数据
举例:db.user.save({name:"paoge",pwd:"123123",age:18,email:"pg@qq.com",vip:1})
db.user.save([{name:"hujiayuan",pwd:"333333",age:17,email:"hjy@qq.com",vip:0},
{name:"luohongliang",pwd:"666666",age:16,email:"lhl@qq.com",vip:0},
{name:"zhaoxiao",pwd:"999999",age:64,email:"zx@qq.com",vip:1}])
2、删:db.表名.remove({}) - 不推荐,删除数据库中所有的数据
db.表名.remove({条件}) - 条件依然也是键值对,比如: db.user.remove({name:"paoge1"}) -
会删除数据表中name叫做paoge1的所有数据
3、改:db.表名.update({条件},{$set:{新内容}})
举例:db.user.update({name:"zhaoxiao"},{$set:{age:65,pwd:"222222"}})
4、查:db.表名.find(); - 找所有
db.表名.find({pwd:"666666"}); - 找到所有密码为666666的数据
db.表名.find({},{name:1,pwd:1}); - 找到所有的数据,但是只返回name和pwd(登录!)
db.表名.find().sort({age:1}); - 按age升序排列!
db.表名.find({age:{$gte:18}}) - 拿到所有age大于等于18的数据,gt大于 gte大于等于 lt小于
lte小于等于(获取成年人)
db.表名.find({name:/o/}) - 甚至可以用正则(模糊查询)
db.表名.find().skip(5).limit(5) - 跳过前5条,在拿5条数据,理解为5-10条数据(点击分页条
应该拿到哪些数据)
db.表名.find().count() - 获取到此表有多少条数据(做出分页条)
3、安装mongDBCompass软件:图形化界面,直观、好看、方便 - 仅仅用于我们方便查看
4、Node.js操作mongoDB - Node.js官方并没有提供过操作数据库的API
1、安装第三方模块:mongoose
2、使用步骤:
1、引入:var mongoose=require("mongoose");
2、连接数据库:mongoose.connect("mongodb://127.0.0.1/h52302");
3、创建出一个新的数据表的同时,设置数据类型的控制,防止用户乱输
var UserSchema=mongoose.Schema({
name:String,
pwd:String,
age:Number,
email:String,
vip:String
})
// 模型名随意的 数据的控制 表名,没有则为创建,有了则为选中!
var User=mongoose.model("User",UserSchema,"user")
4、增:2步
1、创建要插入的对象
var x=new User({
name:"袍哥1",
pwd:"123456",
age:"123",
email:"pg@qq.com",
vip:"1"
})
2、创建好的对象插入到数据表中
x.save().then(()=>{
console.log("插入完毕了,你要干什么,必须放在这个里面,因为他也是异步")
})
5、删:
User.deleteOne/deleteMany({条件}).then(()=>{
console.log("删除完毕了,你要干什么,必须放在这个里面,因为他也是异步")
})
6、改:
User.updateOne/updateMany({条件}).then(()=>{
console.log("修改完毕了,你要干什么,必须放在这个里面,因为他也是异步")
})
7、查:
User.find({条件}).then((rs)=>{
rs->查询到的数据
})
条件的写法和上午的写法是一模一样的!
目前:前端能传到后端的技术,只有一个:form表单,action属性可以随便自定义一个路由名称,后端解析
此路由就可以通过Object.query.键名得到前端传来的东西