赞
踩
var point = 30;
function play() {
//就近原则:从内部开始寻找,如果找不到再去外层作用域查找
var point2 = 20;
alert(point);
}
play();//30
function fn(a) {
console.log(a);//function(){} 优先级高
var a = 2;
function a() { }
console.log(a);//2
}
fn(1);
// 优先显示function a() { }
for(var i=1;i<=3;i++){
//定时器异步执行,等外部代码全部执行完毕再执行自己
setTimeout(function(){
alert(i);
},0)
}
for(let i=1;i<=3;i++){
//let 在每次循环的时候,创建了一个变量副本, 并且保留下来
setTimeout(function(){
alert(i);
},0)
}
// 输出,4 4 4 1 2 3
//let:新增了块级作用域,就是大括号 function play(){ let a=10; if(1==1){ let a=20; { let a = 30; console.log(a); } console.log(a); } console.log(a); } function run(){ //不能在初始化之前去访问let修饰的变量:暂时性死区 console.log(x); //Cannot access 'x' before initialization let x=66; } var global_name = 'frank' let global_age = 19 //用let定义的全局变量,不属于window,用var定义的全局变量是属于window的 console.log(window.global_name); console.log(window.global_age); // 拿不到 run(); // 报错 play(); // 30,20,10
//常量:定义的时候就得初始化它的值,且后面不能再修改
const IP_ADDRESS = '172.168.2.1';
// IP_ADDRESS="127.0.0.1"; 错误的
//如果要将const当成局部变量去使用,则特点和let一样的
if(1==1){
const ONE=1;
}
console.log(ONE); //报错:ONE is not defined
console.log(3)
setTimeout(function(){
console.log(1)
},0)
console.log(4)
setTimeout(function(){
console.log(2);
},0)
console.log(5)
//3,4,5,1,2
//如果用const定义一个对象,那么是可以修改对象内部属性的
const OBJ={name:'jackie',age:30};
OBJ={};
OBJ.name='rose';
IIFE(立即执行函数表达式)
语法:
(function([形参列表]){ //函数体(立即执行的JS代码) [return] })([实参列表])
作用:
早期模块化解决方案,避免了命名冲突
防止外部代码来访问我内部的一些变量,提高了安全性
注意:连续写多个IIFE会报错,请使用分号隔开
var fn = (function(){ var num=10; return function(){ num++; console.log(num); } })() //闭包:函数嵌套函数,内部函数可以访问外部函数的局部变量,闭包环境是内部函数和外部函数沟通的桥梁 //在外部执行fn,不论执行多少次,num变量一直存在,从未还原过 //好处:num既有了全局变量的常驻内存不销毁的特点,并且num又不会和外部名称重名 //坏处:用多了之后,增加了内存消耗,容易造成内存泄漏 //num为什么不会被num垃圾回收器收走: //这个变量一直被内部函数(fn)所使用,所以num不会被垃圾回收器收走 fn();//11 fn();//12 fn();//13 //如何让GC回收掉num呢? //将fn设置为null,没有地方用num了,自然就被GC收走了 fn=null; //没有任何地方使用的变量,会被垃圾回收器收走(释放内存空间) var s="jackie";
//点击LI,弹出LI的下标
let lis = document.querySelectorAll('li')
for(var i=0;i<lis.length;i++){
(function(s){
lis[s].onclick=function(){
alert(s);
}
})(i)
}
var name = "The Window"; let object = { name: "My Object", getNameFunc: function () { console.log(this); var that = this;//that就是object return function () { console.log(this);//此时this已经变化为window了,所以不要用this return that.name;//object.name }; //独立的创建一个函数,不论写在哪,都属于window function play(){ console.log("play 里面的this是谁呢?",this);//window } var run =function(){ console.log("run 里面的this是谁呢?",this);//window } run(); play(); } }; object.getNameFunc()();
var obj = {
start:function(){
console.log(this);
}
}
obj.start();//obj
var fn = obj.start;
fn();//windows
this指向问题
this指向window
function 函数名(){}
var 函数名=function(){}
this指向当前这个对象
var obj = {
函数名:function(){}
}
this指向当前这个btn按钮
btn.onclick=function(){}
//slice截取的时候,找的是 this
let args = [7,8,9].slice();//还是7,8,9 从原数组截取的
let args = [7,8,9].slice.call([1,2,3]);//1,2,3,因为修改了this指向,所以从后面这个数组截取的
function sum(){
//调用slice方法,但是把slice里面的this改成arguments,然后产生一个新数组
let args = [].slice.call(arguments);//1,3
function exec(){
args.push(...arguments);// args = [1,2,3,4]
return exec;
}
exec.calc=function(){
return args.reduce(function(total,current){
return total+current;
})
}
return exec;
}
function sum(){ //调用slice方法,但是把slice里面的this改成arguments,然后产生一个新数组 let args = [].slice.call(arguments);//1,3 function exec(){ args.push(...arguments);// args = [1,2,3,4] return exec; } exec.calc=function(){ return args.reduce(function(total,current){ return total+current; }) } return exec; } // console.log(sum(1,3)(2,4)(100)(1)); var exec1 = sum(1,3); var exec2 = exec1(2,4) var exec3 = exec2(100) var exec4 = exec3(1); console.log(exec4.calc());
function a(){
var arr=[];
var play = function(num){
arr.push(num);
console.log(arr);
return play;
}
return play;
}
var play = a()
var play2 = play(1);
var play3 = play2(2);
var play4 = play2(3);
function sum(){ //1.第一层函数只用来收集参数的,参数10给的是外层函数 //将伪数组转换为普通数组 //调用普通数组的slice方法,然后截取的是arguments的值,最终返回一个新数组 var args = [].slice.call(arguments);//args=[10,1] return function(){ //2.参数20给的是内层函数,并且将10和20合并起来 args.push(...arguments);//args=[10,1,20,30,40,50] var total=0; for(var i=0;i<args.length;i++){ total+=args[i] } return total; } } console.log(sum(10,1)(20,30,40,50));
//普通函数写法 function validate(reg,str){ return reg.test(str); } console.log(validate(/^\d{1,3}$/,"v88")); //柯里化函数写法(一个函数只接收一个参数) function currying(reg){ return function(str){ return reg.test(str); } } var validPhone = currying(/^\d{11}$/) var validEmail = currying(/^d2d2d@d$/) validPhone("123123123") validPhone("23533") validEmail("12323")
var str = "1*2+3";
document.write(eval(str));
// 太过强大,不建议使用
执行上下文【代码的执行坏境】
执行上下文调用栈【代码的执行流程】【先进后出】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7iKqDl4y-1634128183206)(images/20210907111232.png)]
var i=1;
function play(){
i++;
if(i==1000){
return;
}
console.log(i,Math.random())
play();
}
play();
递归
1. 函数调用函数,执行传递的动作;
2. 确定最后一次的终止条件,执行回归的动作
function ji(n) {
if(n == 1) return 1; //确定边界,回归
var j = ji(n - 1); //传递
return n * j;
}
ji(10)
刨析图
let arr=[4,7,3,20,11,2]; function quickSort(list){ if(list.length==0){ return list; } //1.找基准值,就是第一个值 let basic = list[0]; let left_arr=[]; let right_arr=[]; if(list.length==1){ return basic; } //2.遍历数组,从基准值的下一个开始 for(let i=1;i<list.length;i++){ if(basic<list[i]){ //3.放右边 right_arr.push(list[i]) } if(basic>list[i]){ //4.放左边 left_arr.push(list[i]) } } return [].concat(quickSort(left_arr),basic,quickSort(right_arr)); } console.log(quickSort(arr));
递归面试题二【快速排序】
分析思路:
在数据集之中,选择一个元素作为”基准”
所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。
对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。
案例模拟:
4,7,3,20,11,2
基准:[3,2],4,[7,20,11]
[3,2]
基准:2,[3]
[3]
[7,20,11]
基准:7,[20,11]
[20,11]
基准:11,20
代码实现:
var a = 123;
var b = { name: 'jack' }
function show(x, y) {
x = 456;
y = { name: 'rose' } //更改为新对象的内存地址
y.name = 'rose' //修改原对象内部属性
}
show(a, b)
console.log(a, b)
就是存储的值,还是地址的问题
//浅拷贝:复制出来的对象做修改时对原对象造成了影响 var a ={ name:'jack',age:30,work:['写代码','开滴滴','跑摩的'] } var b = a; //复制了引用的地址而已【浅拷贝】 b.name='rose'; console.log(a.name);//rose // 虽然c是新创建的一个对象,c不等于a, //但是:展开符只能展开一层,但是a里面还有一个对象,就是work数组 var c = {...a}; c.name='peter' //c和a是不同的两个对象,但是c和a他们俩共用同一个work c.work[0]='项目经理' console.log(a.work);//['项目经理','开滴滴','跑摩的'] var x ={}; var y={code:'XA003',list:[1,2,3]} //将y的全部内容复制到x里【浅拷贝】 var result = Object.assign(x,y); console.log(x); x.list.push(4,5,6); console.log(y);
对象深拷贝
概念:复制出来的对象和源对象无任何关系,不会再互相影响,在堆内存中独立存储
写法:
方式一:
JSON.stringify(源对象)、JSON.parse(源对象JSON字符串)
缺点:undefined的值、函数无法拷贝
方式二:
递归深拷贝
function deepCopy(target,source){ for(let i in source){ if(typeof source[i]=='object'){ let p=null; if(source[i].length){ //数组 p=[]; }else{ //对象 p={}; } target[i] = deepCopy(p,source[i]) }else{ target[i]=source[i]; } } return target; }
前提:有序数组
思路:
计算出中间值,然后和要查找的数字比较是在中间值的左侧还是右侧
缩短查找范围,再重新计算中间值,继续判断
直到要查找的数字就是中间值为止
代码:
//1.循环数组,逐个比较 //2.数组.indexOf(300) //3.二分查找法(折半查找法):前提是有序数组 //寻找数字5的下标是多少? var arr =[1,2,3,4,5,6,7,8,9,10,11,12,13,14]; function binarySearch(arr,num){ //1.找出中间值 var start = 0; var stop = arr.length-1; var middle = parseInt((stop+start)/2) //2.比较中间值和要查找的数字 while(arr[middle]!=num && stop>start){ if(arr[middle]<num){ //说明我要找的值在右侧 start = middle+1; }else{ //说明我要找的值在左侧 stop = middle-1; } //3.每次循环要重新计算中间值 middle = parseInt((stop+start)/2) } return arr[middle]!=num?-1:middle; } console.log(binarySearch(arr,5));
代码:
//滚动时,调用的其实是debounce里面返回的匿名函数 window.onscroll=debounce(); function debounce(){ var timer=null; //每次滚动的时候,先清除上一次还未执行的定时器,然后再启动新的定时器 //高频次的滚动,不断的清除定时器,减少了函数的执行次数 return function(){ clearTimeout(timer); timer = setTimeout(function(){ var top = document.documentElement.scrollTop || document.body.scrollTop; console.log(top); },100) } }
代码:
//滚动时,调用的其实是throttle里面返回的匿名函数 window.onscroll=throttle(500); function throttle(delay){ var start=0;//初始化第一次执行的时间点 return function(){ //每次滚动时调用内部函数 var now = Date.now(); //用当前时间 - 上次执行的时间 var sub = now - start; //计算看是否超过了500毫秒 if(sub>delay){ //如果超过了500毫秒,去执行一次代码 var top = document.documentElement.scrollTop || document.body.scrollTop; console.log(top); //执行完业务代码之后,将当前时间作为下一次执行的开始时间 start=now; } } }
代码:
//如果写在全局,则全局都是严格模式,如果写在函数内,则函数内代码是严格模式 //一定要写在第一行 "use strict"; //x="123"; 必须使用变量修饰符,否则报错 function play(){ console.log(this);//this不再指向全局对象了(window) } play(); var obj = { sub(){ //不能使用arguments.callee console.log(arguments.callee); } } obj.sub();
ES6【ES2015】
解决2个问题:
变量和字符串连接的问题,不需要再用加号拼接
多行字符串不需要再用多组+拼接
案例:
var name="科比"
//模板字符串
//解决2个问题:
//1.变量和字符串连接的问题,不需要再用加号拼接
//2.多行字符串不需要再用多组+拼接
var str = `${name}是NBA最好的得分手之一,突破、投篮、罚球、三分球他都驾轻就熟
几乎没有进攻盲区,单场比赛81分的个人纪录
就有力地证明了这一点。除了疯狂的得分外,
${name}的组织能力也很出众,经常担任球队进攻的第一发起人。
另外${name}还是联盟中最好的防守人之一,贴身防守非常具有压迫性。`
document.write(str);
【…】
函数中应用:
形参arr的前面写三个点,就代表这个数组的长度是不一定的,你传递的实参数组个数多少都无所谓
function changeParam(…arr){
console.log(arr);
}
changeParam(“a”,”b”,”c”);
changeParam(123,456);
changeParam([“a”]);
如果还想传别的参数,要记得把可变参数放最后
function changeParam(num,...arr) {
console.log(arr+"<br>");
}
changeParam(2,["a", "b", "c"]);
changeParam(3,[123, 456]);
changeParam(4,["a"]);
对象中应用:
展开对象的最外层结构
let z = { a: 3, b: 4 };
let n = { ...z };
数组中应用:
//数组转序列
console.log(...[1, 2, 3]); //1 2 3
console.log(1, ...[2, 3, 4], 5); //1 2 3 4 5
//伪数组转化为数组
var oDiv = document.getElementsByTagName("div");
console.log([...oDiv]); //[div, div, div]
//数组复制
var arr2=[…arr1]
//求最大值
Math.max(...array)
//旧的默认参数写法 function sum(x,y){ x = x || 0; y=y || 0; return x*y; } console.log(sum()); //ES6的默认参数写法 //如果传递了参数,则使用传过来的参数;如果没传参数就用默认值 0 function multiple(x=0,y=0){ return x*y; } console.log(multiple()); console.log(multiple(1,3)); //如果传递了参数,则使用传过来的参数;如果没传参数就用默认值 function show(name = "some people", sex = "man", age = "18") { //你的骚操作 } show(); show("jackie","woman",33)
//字符串:"how are you doing?" 将每个单词放在一个单独的变量里 var str = "how are you doing?" ; [one,two,three,four] = str.split(" ") console.log(one); console.log(two); console.log(three); console.log(four); //可以在对应位置留空来跳过被解构数组中的某些元素 [,,u,] = str.split(" ") console.log(u); //结合“扩展运算符”来捕获数组中的所有尾随元素 [x,...y] = str.split(" ") console.log(x);//how //y这个变量是否是Array类型的实例 console.log(y);//Array //typeof只能检测出来:string,number,boolean,function,undefined,object //instanceof console.log(y instanceof Date);//false console.log(new Date() instanceof Date);//true //面试题:不利用第三个变量交换a和b的值 var a = 1; var b = 3; a=a+b;//a=4,b=3 b=a-b;//a=4,b=1 a=a-b;//a=3,b=1 console.log(a,b); var a = "Cat"; var b = "Dog"; [b,a]=[a,b] console.log(a,b); //对象的结构 var animal={ type:'猫科动物', color:'黄色', age:3, name:'小黄' } let {type,color} = animal; console.log(type); console.log(color); //对象当参数的结构 function hunt({name}){ console.log(name); } hunt(animal);
含义:一种无序、值必须唯一的数据集合
创建Set集合:可接收数组或类似数组的对象、字符串作为参数
var myset=new Set([可选参数]);
//1.创建Set集合 const myset = new Set(); //2.给集合添加值 myset.add(true) myset.add("Frank") myset.add("Rose") myset.add(123) myset.add({}) //3.判断某个值是否存在 console.log(myset.has("Frank")) //4.删除 myset.delete("Frank") console.log(myset.has("Frank")) //5.keys()和values()返回所有的数据集合 console.log(myset.keys()); console.log(myset.values()); //6.清空 // myset.clear(); // console.log(myset) //遍历 myset.forEach(item=>{ console.log(item); }) //新增加的for-of遍历语法:这里的i不是下标,而是值 for(let i of myset){ console.log(i); } for(let i of [55,66,77,88,99]){ console.log(i); } //面试题:数组去重 var list = ["jack","rose","Frank","Peter","Tim","rose","Frank"]; var myset2 = new Set(list) //Array.from()可以将伪数组,Set 转换为普通数组 console.log(Array.from(myset2)) //iterable 可以被遍历的对象
含义:采用key-value的键值对形式存储数据,key不能重复
创建Map集合:
var maps=new Map();
//1.创建map实例 var m = new Map(); //2.给map添加数据 m.set("name","jackie"); m.set(100,10000); m.set(false,true); //3.根据key获取value console.log(m.get(100)); //4.删除 m.delete(false) //5.根据key来判断value是否存在 console.log(m.has(false)); //6.返回map里所有的key console.log(m.keys()); //7.返回map里所有的value console.log(m.values()); //8.返回map里所有key-value数据对 console.log(m.entries()); //9.遍历 m.forEach(function(value,key){ console.log(key,value); }) //10.遍历 for(let i of m){ console.log(i) } //清空 m.clear();
Array | 有序集合 | 下标唯一,值可重复,下标是有序的 |
---|---|---|
Set | 无序集合 | 没有下标,值是唯一 |
Map | 无序集合 | 键值对存储键唯一,值可重复 |
意义:使用对象时,只关注对象提供的功能,不关注其内部细节
创建:
//字面量方式创建对象:
var obj = {
'sex':'女', //1.添加属性 描述
//2.添加方法 行为
buy:function () {
console.log('买搓衣板');
}
}
//实例创建对象:(代码冗余)
var obj = new Object();
//1.添加属性
obj.name = '小华';
//2.添加方法
obj.skill = function () {
console.log('敲代码');
}
//工厂模式创建对象:(缺点:结构不明确)
function createObject(name) {
var obj = new Object(); //1.创建对象
obj.name = name; //2.添加属性
obj.skill = function () { //3.添加方法
console.log('敲代码');
}
return obj; //4.返回创建好的对像
}
//构造函数创建对象:(缺点:浪费内存) //函数名首字母大写(类名),使用this添加属性和方法,调用的时候前面必须加new function Student(name,sex,age) { this.name = name; this.study = function () { console.log("good"); } //在构造函数中不用this,用普通的函数创建和变量创建是私有的,在外部无法直接访问 //私有成员【需要更高的安全性】 var lan=""; function intro(){} } var stu = new Student(属性序列); stu.属性 stu.函数();
含义:每个函数都有一个 prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。
语法:
//创建一个Student构造函数
function Student() {}
//1.通过原型添加属性和方法(共享)
Student.prototype.name = "小红";
Student.prototype.study = function () {
console.log("good good study,day day up!!!!");
}
构造函数名.prototype 和 实例对象.proto 是完全相等的
function Student(){};
var oldW = new Student();
oldW.__proto__ === Student.prototype // true
原型属性与函数的使用
Phone.prototype={
call(){},
message(){},
internet(){}
}
//获取原型上面的属性和方法时,不需要加 __proto__,直接写名字即可
var p = new Phone('iPhone12','gysz12b110@xx','white')
p.call();
//当我们想修改原型上的内容时,才需要通过__proto__
p.__proto__.call=function(){}
//创建一个没有原型的纯粹的对象
var obj = Object.create(null);
//创建一个带有原型【{run:function(){}}】的对象
var obj2 = Object.create({run:function(){}})
构造函数方式和原型方式对比
prototype原型的好处:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3n7o8I6V-1634128183214)(images/20210909162829-16311862689372.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VPE0PYgh-1634128183215)(images/20210909162842-16311862822904.png)]
//工厂函数(在函数内部创建对象,且return出来给外部使用)
//好处:外部无需关注工厂函数里面具体是怎么实现的【隐藏细节】
function factory(name,age){
var obj = new Object();
obj.myName=name;
obj.myAge=age;
return obj;
}
console.log(factory("frank",20))
console.log(factory("rose",10))
//构造函数->类 function Animal(type,name,age,sex){ this.myType=type; this.myName=name; this.myAge=age; this.mySex=sex; var mySize="2米"; //私有的方法,虽然写在Animal里面,但是它是属于window的,本质上和Animal没有关系 function introduce(){ console.log("我身长"+mySize); } this.eat=function(food){ console.log(this.myName+"吃"+food) } this.sleep=function(){ introduce(); console.log("睡觉") } } //创建一个Animal类的实例 var tiger = new Animal("爬行","壁虎",1,"母") //在构造函数中只要是用this点出来的属性和方法都是 public的【公开】 tiger.eat("蚊子"); // tiger.sleep=function(){ // console.log("我不睡觉") // } //在外部又创建了一个公开的属性,也叫mySize tiger.mySize="3米"; console.log(tiger.mySize) tiger.sleep(); //如何设计一些私有的private的属性和方法呢? //在构造函数中不要用this,就用普通的函数创建和变量创建就是私有的了 //手机 //品牌:brand //型号:type //屏幕:4.7 //打电话、发短信、拍照、上网、GPS
//1.每个对象都有__proto__属性
function Person(name){
this.name=name;
}
var p = new Person("frank");
var arr = new Array();
console.log(arr.__proto__);
console.log(p)
console.log(p.__proto__);
function Student(name){ this.name=name; } //prototype原型的好处: //给构造函数上挂载一个原型prototype,目的是为了减少某些函数去重复创建 //原型上的内容创建一次就行 //以后不论创建出来多少个对象,大家都共用 //prototype的作用:函数与属性共享的 Student.prototype.study=function(){ console.log("学习") //这个方法是共享函数(所有Student的实例共享) } //构造函数名.prototype Student.prototype.school="蜗牛学院" var smallW = new Student("小王"); var oldW = new Student("老王") oldW.study(); //实例对象.__proto__ oldW.__proto__.school='家里蹲' console.log(smallW) console.log(oldW) //构造函数名.prototype 和 实例对象.__proto__ 是完全相等的 console.log(oldW.__proto__ === Student.prototype);
function Student(name) { this.name = name; } //给Student设置一个原型,就是{},{}的原型是Object Student.prototype = { study:function(){}, love:function(){} } console.log(new Student("X子文")) //对象默认的原型是 Object,Object是根 console.log({name:'rose'}); //创建一个没有原型的纯粹的对象 var obj = Object.create(null); console.log(obj); //创建一个带有原型【{run:function(){}}】的对象 var obj2 = Object.create({run:function(){}}) console.log(obj2);
//手机 //品牌:brand //型号:type //屏幕:4.7 function Phone(type,iCloud,color){ this.type=type; this.iCloud=iCloud; this.color=color; } Phone.prototype={ call(){ console.log(this.type) }, message(){}, internet(){} } //打电话、发短信、拍照、上网、GPS var p = new Phone('iPhone12','gysz12b110@xx','white') //获取原型上面的属性和方法时,不需要加 __proto__,直接写名字即可 p.call(); //当我们想修改原型上的内容时,才需要通过__proto__ p.__proto__.call=function(){ console.log("重置。。。。") }
//程序员,老师,学生 function Coder(name,age){ this.name=name; this.age=age; } Coder.prototype.code=function(){ console.log("coding.....") } function Teacher(name,age,subject){ this.name=name; this.age=age; this.subject=subject; this.tech=function(){ console.log("授课") } } Teacher.prototype = new Coder(); function Student(name,age,major,sex,tel){ this.name=name; this.age=age; this.major=major; this.sex=sex; this.tel=tel; this.study=function(){ console.log("学习") } } Student.prototype=new Coder(); var s = new Student("小王",20,'Web','男',1110); console.log(s); s.study(); s.code();
原型模式的执行流程: (就近原则)
function Fn() {
this.a = '这是私有属性a';
this.b = function() { alert('这是私有方法b'); }
}
Fn.prototype.a = '这是公共属性a';
Fn.prototype.b = function() { alert('这是公共方法b'); }
var f = new Fn();
alert(f.a); f.b();
如何判断属性是在构造函数的实例里,还是在原型里
<ul> <li>111</li> <li>22</li> <li>33</li> <li>44</li> </ul> <script> var obj = { name:'jack', age:30 } var arr = ["A","B","C",'D'] for(var i in obj){ console.log(i,obj[i],obj.hasOwnProperty(i)) } for(let i in arr){ console.log(i,arr[i]) } var liList = document.getElementsByTagName("li"); console.log(liList) for(let i in liList){ console.log(i,liList.hasOwnProperty(i)); } function Person(name,age){ this.name=name; this.age=age; } Person.prototype.sex="女" var p = new Person("rose",20); console.log(p.hasOwnProperty("name"))//true表示name是Person构造函数里定义的 console.log(p.hasOwnProperty("age"))//true表示age是Person构造函数里定义的 console.log(p.hasOwnProperty("sex"))//false表示sex是原型上面定义的 </script>
在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)
Person.prototype.constructor === Person //true function Person(){} // Person.prototype.name="jack" Person.prototype = { constructor:Person, name:"Nicholas", age:29, job:"Software Engineer", sayName:function(){} } var p1 = new Person(); var p2 = new Person(); console.log(p1) console.log(p1.constructor);//对象.constructor 【对象所在的类(构造函数)】 console.log(Person.prototype.constructor);//构造函数名.prototype.constructor 【构造函数】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hBGfJiIW-1634128183216)(images/20210910110205-16314192388592.png)]
含义:原型与原型之间进行继承,形成了一个链条,称为原型链
语法:子元素.prototype = 父元素实例
Student.prototype = new Person(); SmallStudent.prototype = new Student(); //类:人、学生、小学生、一年级学生、一年级一班学生 function Person(){ this.name="人" } function Student(school){ this.school=school } function SmallStudent(name,age,school){ this.age = age; } //原型与原型之间进行继承,形成了一个链条,称为原型链 Student.prototype = new Person(); SmallStudent.prototype = new Student("学生--"); //给原型上添加constructor,形成双向链条 Student.prototype.constructor = Student; SmallStudent.prototype.constructor = SmallStudent; var s = new SmallStudent("小明",2,"蜗牛") console.log(s); console.log(s.role); console.log(s.name);
对象冒充的原理:调用父类函数时改变this指向,定义子类的属性和方法
在子类型中:父类型.call(this,参数1,参数2…);
可以解决传参的问题,但是不能继承父类型原型中的属性和方法
function Person(name){ this.name=name; } function Student(name,school){ Person.call(this,name) this.school=school } function SmallStudent(name,age,school){ //创建子类之前,先调用父类,将父类里的this改成SmallStudent,给SmallStudent添加学校 Student.call(this,name,school); this.age = age; } //好处:1.提取了多个类的共性做成一个父类,把共性的属性和方法都放父类里面 //2.子类里面只设计属于自己的属性 function HighStudent(name,height,school){ Student.call(this,name,school); this.height=height; } var s = new SmallStudent("小明",3,"蜗牛") var h = new HighStudent("小红",180,'蜗牛') console.log(s.school,s.name,s.age) console.log(h.school,h.name,h.height)
混合继承 对象冒充+原型链继承
对象冒充:继承父类型构造函数中的属性和方法
原型链继承:继承父类型原型对象中的属性和方法
//混合继承: //对象冒充:构造函数的动态参数 //原型链:把父类的方法放进原型中 function Person(name,age){ this.name=name; this.age=age; this.eat=function(){ console.log("Person.吃饭") } } function Student(name,age,_class){ Person.call(this,name,age); this._class=_class; } Student.prototype = new Person; Student.prototype.constructor = Student; function SmallStudent(name,age,_class){ Student.call(this,name,age,_class) this.play=function(){ console.log("玩耍") } } SmallStudent.prototype = new Student; SmallStudent.prototype.constructor = SmallStudent; var stu = new Student("班长大人",40,"3班"); console.log(stu); stu.eat(); var stu2 = new SmallStudent("小明",10,"3班"); stu2.eat(); stu2.play(); console.log(stu2)
动物类案例:
class Animal{ //通过new运算符在创建对象时才会调用的构造函数 constructor(name,age){ this.name=name; this.age=age; } hunter(){ console.log(捕猎); } //get和set访问器中,访问属性时要加下划线,防止出现无限递归问题 get name(){ return this._name; } set name(value){ this._name=value; } } new Animal("x",2).name;//当获取name值的时候,实际上是调用了 get name() new Animal("x",2).name="j"//当给name赋值的时候,实际上调用了set name()
案例:
//语法糖 class Phone{ constructor(brand,price,contact){ this.brand=brand; this.price=price; this.contact=contact; } //属性访问器:set、get set contact(newContact){ console.log("set contact",newContact) if(newContact.length>0){ this._contact = newContact; } } get contact(){ this._contact = this._contact.map(item=>{ //substr(从哪里开始截取,截取几个) substring(从哪开始截取,截取的结束位置-1) return "**" + item.tel.substring(2) }) return this._contact; } } var p = new Phone("MI",2999,[{name:"小明",tel:"12312"},{name:"小红",tel:"678"}]); p.contact=[]; console.log(p.contact); p.contact=[{name:"小王",tel:"998282"},{name:"小绿",tel:"736338"}]; console.log(p.contact);
//手机(父类) class Phone{ constructor(brand,price,contact){ this.brand=brand; this.price=price; this.contact=contact; } } //智能手机(子类) class SmartPhone extends Phone{ constructor(brand,price,contact,OS){ //调用父类构造函数 super(brand,price,contact) this.OS = OS; } } var p = new SmartPhone("MI",2999,[{name:"小明",tel:"12312"},{name:"小红",tel:"678"}],'Android'); console.log(p);
HTTP状态码【服务器给客户端的】※
1xx:请求中
2xx:成功范畴
3xx:重定向
4xx:客户端出错
5xx:服务端报错
100:请求
200:OK
301:永久重定向
302:临时重定向
304:当前资源来自于缓存
400:客户端语法错误
401 :客户端没权限
403:服务的拒绝客户端的请求
404:资源没找到
500:服务的代码报错
503:服务端繁忙
关于HTTP的缓存※
流程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a75Bc2Ie-1634128183217)(images/Snipaste_2021-09-14_09-42-33.png)]
HTTP的端口号
http协议默认端口号:80端口
https协议默认端口号:443端口
http端口号范围:1-65536之间,1-1024被系统占用
推荐端口号:8080,8081,8082,8083
传输方式:
数据内容首先以对称加密方式(公钥)加密,传输过程再由非对称加密方式(私钥)加密的双重加密方式
对称加密:
发送方和接收方都用的同一个密钥 加密解密都是同一个密钥 从始至终只需要保存一个密钥就行
非对称加密:
发送方和接收方使用一对密钥,即公钥和私钥。一般私钥是保密不能被泄露的,公钥可以对外传播。
super关键字
super关键词指向当前对象的原型对象
super()指代父类的构造方法
super.函数名()可以调用父类函数
案例:
class Student extends Person{
constructor(name,age,major){
//调用父类的构造函数,并传参,且一定要写在第一行
super(name,age);
this.major=major;
}
//子类重写(覆盖)了父类函数:父类函数内容太广泛太笼统,不具体,并不能完成体现子类的特点
work(){
//用super.xxx 可以获取父类的成员
super.work();
console.log("学生的工作就是学习")
}
}
static关键字
被static修饰的方法与属性:
不需要new对象,它在class创建的时候就一并产生
在创建class的时候它也就随之创建一次
用类名调用,而不是对象调用
class Person{ constructor(name,age){ this.name=name; this.age=age; } } class Student extends Person{ constructor(name,age,major){ super(name,age); this.major=major; } static role='kid' static getMyName(){ console.log('getMyName : ' + this.name);//返回当前类名:Student } } var s = new Student("jack",30,'Web'); //1.被static修饰的成员,通过类名调用的,不是对象调用 Student.getMyName(); //2.被static修饰的成员归属于类的,不归属于对象 //3.被static修饰的成员是该类创建时也一起创建的 //平时用过的静态成员(大多是工具函数) console.log(Date.now()); console.log(Math.PI);
ES6中定义私有成员
私有属性
必须先在constructor之前定义一下;普通属性不用预先定义
class Animal{
a;
#b;
constructor(a,b){
this.a=a;
this.#b=b;
}
run(){
console.log("this.#b : " + this.#b)
}
#stop(){
console.log("stop")
}
}
异常处理/异常捕获
//语法错误 // war s = "123"; //逻辑错误:调试找到错误 //难以预料:try(试试)-catch(捕获) try { //1.将有可能出错的代码放在try里面 console.log('试一试') alertn(123); } catch (error) { //2.如果真的出错了,就会进入catch里面 console.log('出错啦 :',error) } //3.用了try-catch之后,即使报错也不会影响后续的代码执行 console.log("执行完毕")
//主动抛出异常(主动报错)
function play(){
throw "当前函数不可用"
}
含义:指一种创建交互式网页应用的网页开发技术
作用:可以在不重新加载整个网页的情况下,对网页的某部分进行更新
代码:
/** * url 访问地址 * method 请求方式:GET、POST * data 传递给后端的数据(POST才用) * callback 回调函数(将异步的结果放进去) */ function ajax(url,method,data,callback){ //1.创建XMLHttpRequest对象:xhr let xhr = new XMLHttpRequest(); //2.打开通道 xhr.open(method,url); if(method.toUpperCase()=='POST'){ xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); } //3.发送请求 xhr.send(data); //4.通过事件来获取响应结果 xhr.onreadystatechange=function(){ //5.readyState=4说明整个请求已经完成了 if(this.readyState==4){ //6.获取HTTP状态码,如果是200则成功 if(this.status==200){ let res = JSON.parse(this.response) if(res.errcode){ alert(res.errmsg) return; } //将结果传给回调函数 callback(res); }else{ //7.如果状态码不是200,我们就打印状态文本,例如:404 文本就是 Not Found console.log(this.statusText) } } } }
多层回调函数嵌套,使得程序变得难以维护,可读性差
setTimeout(function() {
console.log('Yay!');
setTimeout(function() {
console.log('Yahoo!');
setTimeout(function(){
//回调地狱
},1000)
}, 1000)
}, 1000);
ES6推出了Promise语法结构来解决回调地狱问题。
这也就表达了将来会执行的操作,代表异步操作。
三种状态:
pending(进行中)、fulfilled(已成功)和rejected(已失败)
状态改变的过程:
pending->fulfilled
pending->rejected
一旦变成了成功或失败状态,状态就不会再变化。
创建Promise实例:
const promise = new Promise((resolve, reject) => {
// do something here ...
if (success) {
resolve(value); // fulfilled
} else {
reject(error); // rejected
}
});
//通过then方法,分别指定resolved状态和rejected状态的回调函数
promise.then(function(value) {
// success
}, function(error) {
// failure
});
用Promise改造Ajax:
/** * url 访问地址 * method 请求方式:GET、POST * data 传递给后端的数据(POST才用) */ function ajax(url,method,data){ return new Promise((resolve,reject)=>{ //1.创建XMLHttpRequest对象:xhr let xhr = new XMLHttpRequest(); //2.打开通道 xhr.open(method,url); if(method.toUpperCase()=='POST'){ xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); } //3.发送请求 xhr.send(data); //4.通过事件来获取响应结果 xhr.onreadystatechange=function(){ //5.readyState=4说明整个请求已经完成了 if(this.readyState==4){ //6.获取HTTP状态码,如果是200则成功 if(this.status==200){ let res = JSON.parse(this.response) if(res.errcode){ alert(res.errmsg) return; } //将结果传给回调函数 resolve(res); }else{ //7.如果状态码不是200,我们就打印状态文本,例如:404 文本就是 Not Found reject(this.statusText) } } } }) } let url = 'http://yapi.smart-xwork.cn/mock/91220/user/list' ajax(url,"GET",null).then(result=>{ if(result instanceof Array){ //遍历结果 result.forEach(item=>{ //创建LI标签 let li = document.createElement("li"); li.innerHTML = item.name +":"+ item.sex; //将LI追加到UL中 document.getElementById("parent").appendChild(li); }) } },error=>{ console.log("失败:" +error); })
方式一:
ajax(‘GET’,’api/seller.do’,’username=jackie’).then((data)=>{ console.log(data);//成功获得结果 },(err)=>{ console.log(err);//获取错误信息 }
方式二:
ajax(‘GET’,’api/seller.do’,’username=jackie’).then((data)=>{ console.log(data);//成功获得结果 }).catch(err=>{ console.log(err);//获取错误信息 })
/** * url 访问地址 * method 请求方式:GET、POST * data 传递给后端的数据(POST才用) * callback 回调函数(将异步的结果放进去) */ function ajax(url,method,data,callback){ //1.创建XMLHttpRequest对象:xhr let xhr = new XMLHttpRequest(); //2.打开通道 xhr.open(method,url); if(method.toUpperCase()=='POST'){ xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); } //3.发送请求 xhr.send(data); //4.通过事件来获取响应结果 xhr.onreadystatechange=function(){ //5.readyState=4说明整个请求已经完成了 if(this.readyState==4){ //6.获取HTTP状态码,如果是200则成功 if(this.status==200){ let res = JSON.parse(this.response) if(res.errcode){ alert(res.errmsg) return; } //将结果传给回调函数 callback(res); }else{ //7.如果状态码不是200,我们就打印状态文本,例如:404 文本就是 Not Found console.log(this.statusText) } } } } // let url = 'http://yapi.smart-xwork.cn/mock/91220/user/list' // ajax(url,"GET",null,function(result){ // if(result instanceof Array){ // //遍历结果 // result.forEach(item=>{ // //创建LI标签 // let li = document.createElement("li"); // li.innerHTML = item.name +":"+ item.sex; // //将LI追加到UL中 // document.getElementById("parent").appendChild(li); // }) // } // }); let url = 'http://yapi.smart-xwork.cn/mock/91220/user/add'; //Content-Type: //纯文本 text/plain //JSON application/json //form表单 application/x-www-form-urlencoded //文件上传 multiple-form let params = new URLSearchParams(); params.append("name","Jerry") params.append("age","2") params.append("sex","男") params.append("phone","110120119114") ajax(url,"POST",params,function(res){ console.log(res); }) ajax('./data.json',"GET",null,function(res){ console.log(res); })
var promise = new Promise(function(resolve,reject){ //ajax请求 console.log('1.发起ajax请求'); var random = Math.random(); console.log("2.产生随机数:" +random) if(random>0.5){ //走成功那条路 resolve("success") }else{ //走失败那条路 reject("fail") } }) promise.then(function(res){ //成功的处理 console.log(res); },function(err){ console.log(err); //失败的处理 })
//要求等待1秒后弹出”Yay”,然后再等1秒弹出”Yahoo”,再等1秒弹出“God” new Promise((resolve,reject)=>{ setTimeout(function(){ console.log("Yay") resolve("Yahoo") },1000) }).then(function(res){ setTimeout(function(){ console.log(res) },1000) }).then(function(){ setTimeout(function(){ console.log("God") },1000) })
//要求等待1秒后弹出”Yay”,然后再等1秒弹出”Yahoo”,再等1秒弹出“God” function p(str){ return new Promise(resolve=>{ setTimeout(function(){ resolve(str) },1000) }) } var promise = p("Yay") var promise2= promise.then(function(res){ console.log(res); return p("Yahoo") //再次调用p方法,实际上是重新new了一个Promise对象,赋值给promise2 }) var promise3= promise2.then(function(res){ console.log(res); return p("God") //再次调用p方法,实际上是重新new了一个Promise对象,赋值给promise3 }) promise3.then(res=>{ console.log(res); })
/** * url 访问地址 * method 请求方式:GET、POST * data 传递给后端的数据(POST才用) */ function ajax(url,method,data){ return new Promise((resolve,reject)=>{ //1.创建XMLHttpRequest对象:xhr let xhr = new XMLHttpRequest(); //2.打开通道 xhr.open(method,url); if(method.toUpperCase()=='POST'){ xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); } //3.发送请求 xhr.send(data); //4.通过事件来获取响应结果 xhr.onreadystatechange=function(){ //5.readyState=4说明整个请求已经完成了 if(this.readyState==4){ //6.获取HTTP状态码,如果是200则成功 if(this.status==200){ let res = JSON.parse(this.response) if(res.errcode){ alert(res.errmsg) return; } //将结果传给回调函数 resolve(res); }else{ //7.如果状态码不是200,我们就打印状态文本,例如:404 文本就是 Not Found reject(this.statusText) } } } }) } let url = 'http://yapi.smart-xwork.cn/mock/91220/user/list' ajax(url,"GET",null).then(result=>{ if(result instanceof Array){ //遍历结果 result.forEach(item=>{ //创建LI标签 let li = document.createElement("li"); li.innerHTML = item.name +":"+ item.sex; //将LI追加到UL中 document.getElementById("parent").appendChild(li); }) } },error=>{ console.log("失败:" +error); })
//传统做法:回调函数来得到异步结果 function a(num,str,bol,callback){ callback(); } a(12,"hello",true,function(){ console.log("66666666") }); //Promise的出现就是为了干掉回调函数这种传统写法 function a(num,str,bol){ return new Promise(resolve=>{ resolve("66666666") }) } a().then(res=>{ console.log(res) })
var promise = new Promise(function(resolve,reject){ //ajax请求 console.log('1.发起ajax请求'); var random = Math.random(); console.log("2.产生随机数:" +random) if(random>0.5){ //走成功那条路 resolve("success") }else{ //走失败那条路 reject("fail") } }) // promise.then(成功的回调,失败的回调) // promise.then(function(res){ // //成功的处理 // console.log(res); // },function(err){ // console.log(err); // //失败的处理 // }) //promise.then(成功回调).catch(失败的回调) promise.then(res=>{ console.log(res) }).catch(err=>{ console.log(err); })
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
var p1 = new Promise(function (resolve,reject) {});
var p2 = new Promise(function (resolve,reject) {});
var p3 = new Promise(function (resolve,reject) {});
var p = Promise.all([p1,p2,p3]);
p的状态,由p1,p2,p3决定,全部实例对象为resolve,p的状态才会resolve,所有对象的返回值组成一个数组,传递给p的回调函数。任何一个对象为rejected,p的状态就变成rejected
同时启动多个Promise实例,返回多个结果[允许有的成功,有的失败]
Promise.allSettled([
Promise.resolve('a'),//创建了一个成功状态的Promise对象
Promise.reject('b'),//创建一个失败状态的Promise对象
]).then(arr => console.log(arr))
//只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
//那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
var p =Promise.race([p2(),p1(),p3()]);
p.then(res=>{
console.log(res)
})
async:作为一个关键字放到函数前面,用于表示函数是一个异步函数,因为async就是异步的意思, 异步函数也就意味着该函数的执行不会阻塞后面代码的执行。
async function timeout() {
return 'hello world';
}
console.log(timeout()); //返回一个Promise对象
console.log('虽然在后面,但是我先执行');
timeout().then(result => {
console.log(result); // 用这个对象.then才能获取结果 hello world
})
await:等待的意思,它后面跟着一个返回promise 对象的表达式,注意await 关键字只能放到async 函数里面。
async function show(){
return 123;
}
async function play(){
var res =await show();
console.log(res); //123
}
play();
function p1(){ return new Promise(resolve=>{ resolve("success") }) } function p2(){ return new Promise((resolve,reject)=>{ reject("fail") }) } function p3(){ return new Promise(resolve=>{ resolve("success") }) } function start(){ //如果三者都返回成功,最终结果就是成功;如果三者有一个返回失败,最终结果就是失败 Promise.all([p1(),p2(),p3()]).then(res=>{ console.log(res); }).catch(err=>{ console.log(err) }) } start();
//Promise的三种状态 //还没出结果的时候:pending //成功结果:fulfilled //失败结果:rejected //pending->fulfilled 或 pending->rejected (只能是从没结果到成功,或失败) //fulfilled->rejected (不会出现从成功变成失败,或从失败变成成功) //同时启动多个Promise实例,返回多个结果[允许有的成功,有的失败] function start(){ Promise.allSettled([ Promise.resolve("111"), //创建了一个成功状态的Promise实例 Promise.reject("222"),//创建了一个失败状态的Promise实例 Promise.resolve("333"), //创建了一个成功状态的Promise实例 ]).then(res=>{ console.log(res); }) } start();
function p1(){ return new Promise(resolve=>{ resolve("success1") }) } function p2(){ return new Promise((resolve,reject)=>{ reject("fail") }) } function p3(){ return new Promise(resolve=>{ resolve("success2") }) } function start(){ //race:比赛 //只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。 //那个率先改变的 Promise 实例的返回值,就传递给p的回调函数 var p =Promise.race([p2(),p1(),p3()]); p.then(res=>{ //最终结果就是执行最快的那个Promise,如果没有时间上的差异,就是按先后顺序 console.log(res) }) } start();
//给函数前面加async关键字,函数的返回值就会变成一个Promise对象 //如果我们手动在函数里面return了一个值,则这个值就是Promise对象里面的value,通过then可以取出 async function show(){ return 123; } // 相当于写了下面的代码 // function show(){ // return new Promise(resolve=>{ // resolve(123) // }) // } //也相当于下面的代码 // function show() { // return Promise.resolve(123); // } show().then(res=>{ console.log(res);//123 })
//async - await:能让我们的异步代码看起来像是同步代码 async function show(){ return 123; } //await关键字只能在被async修饰的function里面使用 async function play(){ //用await来代替 .then方法,res就是then()里面正确返回的结果 try { var res =await show(); console.log(res); } catch (error) { console.log("万一报错了,执行这里,原因:"+error) } } play();
function ajax(url, method, data) { return new Promise((resolve,reject)=>{ let xhr = new XMLHttpRequest(); xhr.open(method, url); throw "错错错,是我的错" if (method.toUpperCase() == 'POST') { xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); } xhr.send(data); xhr.onreadystatechange = function () { if (this.readyState == 4) { if (this.status == 200) { let res = JSON.parse(this.response) if (res.errcode) { alert(res.errmsg) return; } resolve(res); } else { reject(this.statusText) } } } }) } //使用async+await 让代码看起来像同步代码,代替了过去的回调函数,以及 then async function play(){ try { let url = 'http://yapi.smart-xwork.cn/mock/91220/user/list' let res =await ajax(url,'GET',null) console.log(res); } catch (error) { console.log(error) } } play(); console.log("黑色") console.error("红色") console.info("蓝色") console.warn("黄色")
const path = require('path'); const htmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const Terser =require('terser-webpack-plugin'); const Clean = require('clean-webpack-plugin'); const WebpackBar = require('webpackbar'); module.exports={ //环境:development(开发环境)、production(线上环境) mode:'development', // 入口 entry:{ index:'./src/index.js', print:'./src/print.js', app:'./src/app.js' }, // 出口 output:{ filename:'[name].bundle.js', path:path.resolve(__dirname,'dist') }, //插件配置 plugins:[ new htmlWebpackPlugin({ filename:'index.html', //生成的html的文件名,默认就是index.html title:'Webpack4.x学习', //网页的标题 favicon:'./favicon.ico',//网页小图标 inject:'body',//将生成的js插入在body里面,也可以写head chunks:['index'],//只引入print那个js文件 minify:{ //压缩规则 'removeComments':true, //删除所有注释 'collapseWhitespace':false,//删除所有的空格、换行 } }), new htmlWebpackPlugin({ filename:'login.html', //生成的html的文件名,默认就是index.html title:'登录', //网页的标题 template:'./src/login_template.html', //设置一个模板文件 favicon:'./favicon.ico',//网页小图标 inject:'body',//将生成的js插入在body里面,也可以写head chunks:['app'],//只引入app那个js文件 minify:{ //压缩规则 'removeComments':true, //删除所有注释 'collapseWhitespace':false,//删除所有的空格、换行 } }), new MiniCssExtractPlugin({filename:"[name].css"}),//分离CSS new OptimizeCssAssetsPlugin(),//压缩CSS文件 new Terser(), //在开发环境下压缩JS文件 new Clean.CleanWebpackPlugin(), //清理dist文件夹 new WebpackBar() //打包进度条 ], module:{ rules:[ { test:/\.css$/, // use:['style-loader','css-loader'] use: [{loader:MiniCssExtractPlugin.loader},'css-loader'] }, { test:/\.(jpg|png|gif|webp)$/, use:[{ loader:'url-loader', options:{ limit:8192, outputPath:'images/' } }] }, { test:/\.(ttf|woff)$/, use:['file-loader'] } ] } }
webpack
配置相关使用参考:
安装node.js
安装淘宝镜像npm install -g cnpm -- registry=https://registry.npm.taobao.org
创建“工作区”文件夹
cmd切换到该目录
npm init -y
该文件夹生成package.json
文件
webpack.config.js
手动新建转换配置文件
安装cnpm install --save-dev webpack@4.32.2
和cnpm install --save-dev webpack-cli@3.3.11
(我感觉叫webpack
支持)
这是文件夹大致分布。(dist输出文件夹,src输入文件夹,父盒子 工作配置相关)
index.html
修改(略)
package.json
设置
{ "name": "day09", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack-dev-server --open --config webpack.dev.js", "build": "webpack --config webpack.prod.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "clean-webpack-plugin": "^4.0.0", "css-loader": "^5.0.2", "html-webpack-plugin": "^4.5.2", "mini-css-extract-plugin": "^0.8.2", "optimize-css-assets-webpack-plugin": "^6.0.1", "style-loader": "^2.0.0", "terser-webpack-plugin": "^1.4.5", "url-loader": "^4.1.1", "webpack": "^4.32.2", "webpack-bundle-analyzer": "^4.4.2", "webpack-cli": "^3.3.11", "webpack-dev-server": "^3.11.2", "webpack-merge": "^5.8.0", "webpackbar": "^5.0.0-3" } }
、webpack.config.js
设置
const path = require('path'); // 引入jquery // const $ = require('jquery'); // 新建html const htmlWebpackPlugin = require('html-webpack-plugin'); // 把css抽出为单独的文件 const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 压缩css const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 压缩js const Terser = require('terser-webpack-plugin'); // 每次构建前清理 /dist 文件夹 const Clean = require('clean-webpack-plugin'); // 打包进度条 const WebpackBar = require('webpackbar'); // 分析并可视化构建后的打包文件 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; // 导出webpack配置内容 module.exports = { mode: 'development', // 入口 // entry: './src/index.js', entry: { index: './src/index.js', // print:'./src/print.js', app: './src/app.js' }, // 出口 output: { // filename: 'bundle.js', filename: '[name].bundle.js', // __dirname:代表当前文件的绝对路径 path: path.resolve(__dirname, 'dist') }, plugins: [ new htmlWebpackPlugin({ filename: 'index.html', //生成的html的文件名,默认就是index.html title: '张胖胖', //网页的标题 favicon: './favicon.ico',//网页小图标 inject: 'body',//将生成的js插入在body里面,也可以写head chunks: ['index'],//只引入print那个js文件 minify: { //压缩规则 'removeComments': false, //删除所有注释 'collapseWhitespace': false,//删除所有的空格、换行 } }), new htmlWebpackPlugin({ filename: 'login.html', //生成的html的文件名,默认就是index.html title: '登录', //网页的标题 template: './src/index.html', //设置一个模板文件 favicon: './favicon.ico',//网页小图标 inject: 'body',//将生成的js插入在body里面,也可以写head chunks: ['app', 'index'],//只引入app那个js文件 minify: { //压缩规则 'removeComments': false, //删除所有注释 'collapseWhitespace': false,//删除所有的空格、换行 } }), new MiniCssExtractPlugin({ filename: "[name].css" }), new Clean.CleanWebpackPlugin(), new WebpackBar({ color: 'pink' }), // new OptimizeCssAssetsPlugin(), // new Terser(), // new BundleAnalyzerPlugin, ], module: { rules: [ { test: /\.css$/, // use: ['style-loader', 'css-loader'] use: [{ loader: MiniCssExtractPlugin.loader }, 'css-loader'] }, { test: /\.(jpg|png|gif|webp)$/, use: [{ loader: 'url-loader', options: { limit: 8192, outputPath: 'images/' } }] } ] }, // 以服务器打开实时更新 devServer: { port: 8000, host: '127.0.0.1', contentBase: './dist', overlay: { errors: true }, } }
。(index.js
随便输入个东西,此时基本就可以用npm run build
运行看看了,具体见readme)
安装loader
(插件)--save-dev
忘了怎么说了:
处理css:cnpm install --save-dev style-loader@2.0.0
和cnpm install --save-dev css-loader@5.0.2
规则:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0UnHyoHu-1634128183218)(images/image-20210917200556054.png)]
url:cnpm install --save-dev url-loader
小于8kb的图片用什么64转换显示。
规则:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9DSeeczG-1634128183219)(images/image-20210917200626238.png)]
打包进度条:cnpm install --save-dev webpackbar
new一个!new WebpackBar({ color: 'pink' }),
分析并可视化构建后的打包文件cnpm install --save-dev webpack-bundle-analyzer
new一个!new BundleAnalyzerPlugin,
以服务器打开:cnpm install --save-dev webpack-dev-server@3.11.2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xCqVzLWR-1634128183220)(images/image-20210917200927304.png)]
拆分webpack.config.js插件:cnpm install --save-dev webpack-merge
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PSyctkMS-1634128183220)(images/image-20210917201043750.png)]
时间:cnpm install time-stamp
全部重新安装:cnpm install
安装plugin
(工具):
创建html:cnpm install --save-dev html-webpack-plugin@4.5.2
规则:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MPm3HSEb-1634128183221)(images/image-20210917201335530.png)]
把css抽离成单独的css文件:cnpm install mini-css-extract-plugin@0.8.2 -D
new一个!
CSS代码压缩:cnpm install --save-dev optimize-css-assets-webpack-plugin
new一个!
在开发环境下,压缩JS代码:cnpm install --save-dev terser-webpack-plugin@1.4.5
new一个!
每次构建前清理 /dist 文件夹,是比较推荐的做法:cnpm install --save-dev clean-webpack-plugin
new一个!new 名.CleanWebpackPlugin(),
cmd
相关cmd
常用命令
node xx.js
运行JS文件cls
清屏dir
列出当前目录下的所有文件cd 目录名
进入指定的文件夹md 目录名
创建一个文件夹rd 目录名
删除该文件夹(只能删空文件夹)盘符号:
切换到指定盘符版本库是集中存放在中央服务器的,而干活的时候,用的是自己的电脑,所以要先从中央服务器取得最新的版本,
然后开始干活,干完活了,再把自己的活推送给中央服务器。
中央服务器就好比是一个图书馆.你要改一本书.必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,
可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟
分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,
就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?
比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,
你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,
某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。
而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
由于CVS自身设计的问题,会造成提交文件不完整,版本库莫名其妙损坏的情况。
同样是开源而且免费的SVN修正了CVS的一些稳定性问题,是目前用得最多的集中式版本库控制系统。
Git的优势不单是不必联网这么简单,后面我们还会看到Git极其强大的分支管理,把SVN等远远抛在了后面。
Linux:
终端中直接输入 sudo apt-get install git
Mac:
运行Xcode,菜单“Xcode”->“Preferences”,
在弹出窗口中找到“Downloads”,选择“Command Line Tools”,点“Install”就可以完成安装了
Windows:
下载地址:https://git-for-windows.github.io
安装后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
最后:
在命令行输入名字和邮箱进行登记:
$ git config —global user.name “Your Name”
$ git config —global user.email “email@example.com”
git config --global user.name "自己的名字"
git config --global user.email "自己的邮箱"
git config user.name 查看当前用户名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZhyFW7vX-1634128183222)(images/git命令.jpg)]
特点:基于CMD标准-同步的模块化标准
语法:
//文件A:导入
const 模块名 = require('路径');
模块名.成员1;
模块名.成员2();
//文件B:导出
exports.成员1 = 值;
exports.成员2 = function(){};
//导出
module.exports = {
变量名,函数名
}
//文件A:导出 class Animal{ constructor(name){ this.name=name; } } function print(){ console.log("打印。。。。") } function play(){ console.log("播放") } //具名导出 export const show= () =>{ console.log("show...") }; //具名导出 export {print,play}; //默认导出【每个文件只能写一次】 export default Animal;
//文件B:导入
import Animal,* as api from './output.js';
let ani = new Animal('jack')
console.log(ani);
api.print();
api.play();
api.show();
//文件C:导入
import Animal,{print,play,show} from './output.js';
let ani = new Animal('jack')
console.log(ani);
print();
play();
show();
语法:fs.readFile(filename, [options], callback)
filename 是文件名;[options] 是可选的参数 , 为一个对象,用于指定文件编码(encoding)及操作方式(flag);callback 是回调函数,传递异常err 和文件内容 data 的 2 个参数
var fs = require("fs"); // 引入 fs 模块
fs.readFile(".test.txt",”utf-8”,function(err,data){
if(err){
throw err;
}
// 读取文件成功
console.log(data);
});
语法:fs.readFileSync(filename, [options])
filename 是文件名;[options] 是可选的参数 , 为一个对象,用于指定文件编码(encoding)及操作方式(flag);
var fs = require("fs"); // 引入 fs 模块
var result = fs.readFileSync(".test.txt",”utf-8”);
console.log(result);
语法:fs.writeFile(filename,data,[options],callback)
filename是文件名称;data是要写入文件的数据;[options]是一个对象为可选参数,包含编码格式(encoding),模式(mode)以及操作方式(flag);callback 是回调函数
var fs = require("fs");
var data = " 嘿嘿嘿”;
// 写入文件内容,如果文件不存在则创建文件
fs.writeFile("./test/11.txt",data,{"flag":"a"},function(err){
if(err) throw err;
});
语法:fs.writeFileSync(file, data[, options])
filename是文件名称;data是要写入文件的数据;[options]是一个对象为可选参数,包含编码格式(encoding),模式(mode)以及操作方式(flag)
var fs = require("fs");
var data = " 嘿嘿嘿”;
// 返回undefined
fs.writeFileSync("./test/11.txt",data,{"flag":"a"});
var fs = require("fs");
//1.创建一个可写流
var ws = fs.createWriteStream("hello3.txt",{flags:'a'});
//2.绑定打开和关闭的一次性事件ws.once("open",function () {console.log("流打开了");});
ws.once("close",function () {console.log("流关闭了");});
//3.通过ws向文件中输出内容
ws.write("百度");
ws.write("IT培训");
//4.关闭流
ws.end();
var fs = require("fs");
const rs = fs.createReadStream('./我的自白书.txt','utf-8')
//onData事件,代表读取中
rs.on('data',(data)=>{
//读取的过程中,同时写入
ws.write(data)
})
//onClose事件,表示读取结束
rs.on('close',function(){
//读取结束后,关闭ws
ws.end();
})
语法:fs.unlink(path, callback)
path是文件路径;callback 是回调函数(参数只有一个error对象)
var fs = require("fs");
// 假设 'path/file.txt' 是一个普通文件。
fs.unlink('path/file.txt', (err) => {
if (err) throw err;
console.log('文件已删除');
});
语法:fs.unlinkSync(path)
path是文件路径
var fs = require("fs");
// 没有返回值
fs.unlinkSync('path/file.txt');
语法:fs.mkdir(path, [mode], callback)
path 是需要创建的目录;
[mode] 是目录的权限(不支持windows平台);
callback 是回调函数
var fs = require("fs");
fs.mkdir("./wenjianjia",function(err){
if(err){
throw err;
}
console.log(" 创建目录成功 ");
})
语法:fs.readdir(path, callback)
path 是需要读取的目录;callback 是回调函数.
会返回error和一个数组,数组中是当前根目录下的所有文件夹名称和文件名称。
var fs = require("fs");
fs.readdir("./wenjianjia",function(err,files){
if(err){
throw err;
}
console.log(files);
});
语法:fs.rmdir(path, callback)
path 是需要删除的目录;callback 是回调函数.
注意:只能删除空目录
var fs = require("fs");
fs.rmdir("./wenjianjia",function(err){
if(err){
throw err;
}
});
语法:fs.stat(path, callback)
path 要查看目录 / 文件的完整路径及名;[callback(err, stats)] 操作完成回
调函数,err 错误对象,stats fs.stat 一个对象实例,提供如 :isFile, isDirectory 等方法。
var fs = require('fs');
fs.stat('./wenjianjia',function(err,stats){
if(stats.isDirectory()){
console.log('文件夹');
};
})
语法:fs.exists(path, callback)
path要查看目录 /文件的完整路径及名;[callback(exists)]操作完成回调函数,exists true 存在,false 表示不存在。
var fs = require("fs");
fs.exists("./test/",function(exists){
if(exists){
console.log(" 文件夹存在 ");
}else{
console.log(" 文件夹不存在 ");
}
});
语法:fs.rename(oldPath,newPath,callback)
异步地将 oldPath 上的文件重命名为 newPath 提供的路径名. 如果 newPath 已存在,则覆盖它
let fs = require('fs')
fs.rename('./foo.txt','./bar.txt',function (err) {
if(err){
throw err
}
console.log('修改成功')
})
语法:url.parse(urlStr[, parseQueryString])
urlStr 输入一个 url 字符串;parseQueryString(默认为 false),如为true,则 urlObject.query 为解析后的对象
var url = require("url");
var path ="http://user:pass@host.com:8080/p/a/t/h?query=string#hash";
var query= url.parse(path).query; //query=string
var queyr= url.parse(path,true).query; //{query:'string'}
获取路径中的文件名,第一个参数 path 为必须指定的参数,ext 参数为可选参数。path 参数值必须为一个文件的完整路径,可以是相对路径,也可以使绝对路径。ext 参数值用于在方法所返回的文件名中去掉文件的扩展名
var path = require("path");
var fileName = path.basename("./test/aa.txt");
console.log(fileName); // aa.txt
var name = path.basename("./test/aa.txt",".txt");
console.log(name); //aa
提取出一个路径中的祖先路径
var path = require("path");
var dirname = path.dirname("./test/i/aa.txt");
console.log(dirname); //./test/i
var dirname = path.dirname('./test/i');
console.log(dirname); //./test
获取一个路径中的扩展名
var path = require("path");
var extname = path.extname("./test/aa.txt");
console.log(extname);//.txt
var path = require("path");
path.join('/a', '/b') // Outputs '\a\b'
path.resolve('/a', '/b') // Outputs 'H:\b'
于将非标准路径的字符串转化成标准路径字符串
var path = require("path");
var normalize = path.normalize("../a//b//d//..//c//d/")
console.log(normalize);//..\a\b\c\d
querystring.parse(str[, sep[, eq[, options]]])
是将一个字符串反序列化为一个对象
str 指需要反序列化的字符串,sep(可选)指用于分割 str 这个字符串的字符或字符串,默认值为 “&”;eq(可选)指用于划分键和值的字符或字符串,默认值为 “=”;options(可选)该参数是一个对象,里面可设置 maxKeys 属性:传入一个 number 类型,指定解析键值对的最大值,默认值为 1000,如果设置为 0 时,则取消解析的数量限制
var querystring = require("querystring");
var newObj=querystring.parse("site=QQ&url=http://www.qq.com/");
var queryObj=querystring.parse("site=QQ#url=http://www.qq.com/
#age=5","#",null,{maxKeys:2});
querystring.stringify(obj[, sep[, eq[, options]]])
将一个对象序列化成一个字符串
数 obj 指需要序列化的对象;sep(可选)用于连接键值对的字符或字符串,默认值为 “&”;eq(可选)用于连接键和值的字符或字符串,默认值为 “=”;
var querystring = require("querystring");
var str = querystring.stringify({name:"baidu",sex:"man"});
console.log(str); //name=baidu&sex=man
console.log(queryStr); //name*baidu|sex*man
使传入的字符串进行编码
var querystring = require("querystring");
var str = querystring.escape("name= 百度 ");
console.log(str);
将含有 % 的字符串进行解码
var querystring = require("querystring");
var str = querystring.unescape("name%3D%E4%BC%98%E5%B0%B1%E4%B8%9A");
console.log(str);
//创建一个http服务(就可以通过网址+端口号来访问了) //1.引入http模块 const http = require('http') const fs = require('fs') //2.通过http对象创建Server http.createServer(function(req,res){ console.log(req.url); let data=null; if(req.url=='/'){ //设置响应头,类型为text/html,可以解析html标签 res.writeHead(200,"ok",{'Content-Type':'text/html;charset=utf-8'}) //文件读取:网页 data = fs.readFileSync('./index.html','utf-8') //将网页内容输出给浏览器 }else if(req.url.endsWith('.css')){ //设置响应头,类型为text/html,可以解析html标签 res.writeHead(200,"ok",{'Content-Type':'text/css;charset=utf-8'}) data = fs.readFileSync('.'+req.url,'utf-8');// ./public.css }else if(req.url.endsWith('.js')){ res.writeHead(200,"ok",{'Content-Type':'text/javascript;charset=utf-8'}) data = fs.readFileSync('.'+req.url,'utf-8');// ./public.css }else{ res.writeHead(200,"ok",{'Content-Type':'image/x-icon'}) data = fs.readFileSync('.'+req.url);// 图片 } res.write(data); res.end();//关闭[如果不关闭,页面就会一直加载中,一直等待] }).listen(8888) console.log('server startup on 8888') //3.监听端口:8888 //4.访问地址:http://localhost:8888/
学员管理系统,增删改登录
node.js
是一个基于chrome V8
引擎的js
运行时(运行时指的就是“运行环境”)。const querystring = require('querystring')\
// 原因:亚洲文字,特殊符号在网络传输中容易乱码
// 编码
let res = querystring.escape('哈哈=123')
// 解码
let res2 = querystring.unescape('%E5%93%88%E5%93%88=123')
NodeJS最有名的框架
npm install express
//或
yarn add express
//或
cnpm install express
//app.js
var express = require("express");
var app = express();
//任何请求方式,任何地址都会进入,可用作拦截器使用
app.all("*",function(req,res,next){
next();
})
//匹配路由时,可以自动过滤掉query和hash部分
app.get('/', function (req, res) {
//res.sendFile(); 发送页面给浏览器
res.sendFile(__dirname + '/post_client.html');
//res.send(); 发送数据给浏览器
});
app.listen(8000)
安装工具:npm install express-generator -g
生成项目:express —view=ejs myapp
安装依赖:cd myapp && npm install
启动项目:set DEBUG=myapp:* & npm start
打开浏览器:http://localhost:3000/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wpc05ApJ-1634128183223)(images/Express脚手架.png)]
var express = require("express");
var app = express();
app.get("/",function(req,res){
console.log(req.query);
res.send(req.query);
});
app.listen(3000);
var express = require("express");
var bodyParser = require('body-parser')
var app = express();
app.use(bodyParser.urlencoded({ extended: false }))
app.get("/",function(req,res){
res.send(req.body.username);
});
app.listen(3000);
近两年比较流行的框架
// 默认引入
const express = require('express');
const app = express();
const path = require('path');
// 处理静态资源,要指定静态资源在哪里{assets文件夹中}(js,css,font,媒体)
app.use(express.static(path.ressolve(__dirname,'assets')));
安装:
npm install multer
配置:app.js
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
//【要写在业务模块的前面】
app.use(multer({dest: '/tmp/'}).array('myFile', 10));
//业务模块【indexRouter里面的路径可以直接访问,userRouter里的路径需要在前面加/users】
app.use('/', indexRouter);
app.use('/users', usersRouter);
上传后端:/routes/users.js
//页面访问路径:/users/user/add router.post('/user/add',function(req,res){ //1000 - 9999 var max = 9999; var min = 1000; req.files.forEach(f=>{ //1.拼接一个新的文件名:毫秒值+随机数+后缀名组成 var t = Date.now(); var r = parseInt(Math.random()*(max-min))+min; //生成一个四位随机数 var ext = path.extname(f.originalname);//获取源文件的后缀名 .jpg var name = t + "" + r + ext; //2.读取原始文件 var data = fs.readFileSync(f.path); //3.将图片写入到我们指定的文件夹中 //__dirname:桌面\Express-app\routes //拼完的路径:桌面\Express-app\photo\123123213123.jpg fs.writeFile(path.resolve(__dirname,'../public/images',name),data,function(err){ if(err){ console.log("报错了:",err); throw err; } //如果照片上传成功,再将学员姓名添加到数组中,并返回success //POST的参数:req.body.参数名 console.log("学员姓名:",req.body.username); //将学员姓名和学员照片名以对象形式存储在数组里 students.unshift({ username:req.body.username, photo:name }); }) }) res.send("success"); })
上传前端:/views/add.html
html部分
<input type="text" name="username" id="username" placeholder="请填写学员姓名"><br>
<input type="file" name="userphoto" id="userphoto"><br>
<span></span>
<button>提交</button>
js部分
$("button").click(function(){ var username = $("#username").val(); var userphoto = document.getElementById("userphoto"); var formData = new FormData(); formData.append('username',username); formData.append('userphoto',userphoto.files[0]) $.ajax({ url:'/users/user/add', method:'POST', data:formData, processData:false, //不要去处理文件数据内容 contentType:false, //告诉jQuery不要去设置Content-Type请求头 success:function(res){ console.log(res); }, xhr:function(){ let xhr = $.ajaxSettings.xhr(); if(xhr.upload){ //上传进度查看 xhr.upload.addEventListener('progress',function(e){ var percent = parseInt(e.loaded / e.total * 100); $("span").html(percent+"%"); }) } return xhr; } }) })
RESTful架构,是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。每一个URI代表一种资源;
客户端和服务器之间,传递这种资源的某种表现层;
客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”
GET http://www.baidu.com/api/user # 获取列表
POST http://www.baidu.com/api/user # 创建用户
PUT http://www.baidu.com/api/user/{id} # 修改用户信息
DELETE http://www.baidu.com/api/user/{id} # 删除用户信息
在前端传递参数:
工号为12345
$.ajax({
url:'/teacher/12345',
method:'GET',
success:function(res){
console.log(res);
}
})
在Node中获取参数:
app.get("/teacher/:gonghao",function(req,res){
res.send(" 老师工号 " + req.params.gonghao);
});
打开CMD->输入:mongo 回车: show dbs【查看所有数据库名称列表以及所占硬盘空间】 use 数据库名【切换到指定的数据库中,如果不存在则创建并切换】 db【查看当前的数据库名称】 show tables/show collections 【查看当前数据库中所有集合】 db.createCollection(“集合名称”) 【创建一个空集合】 db.集合名称.insert({key1:value1,key2:value2}) 【给这个集合插入一条数据】 db.集合名称.insert([{key1:value1},{key2:value2}])【给这个集合插入多条数据】 db.集合名称.find() 【查看当前集合的全部数据】 db.集合名称.remove({key:value}) 【删除符合指定key-value条件的数据】 db.集合名称.drop() 【删除当前集合】 db.集合名称.update({筛选条件},{更新的内容},{multi:true})【不加第三个参数,只更新一条】 db.集合名称.update({筛选条件},{$set:{更新的内容}},{multi:true})【$set:只更新要修改的内容,其他内容不变,如果要更新的内容之前没有,则添加进去】 db.集合名称.update({筛选条件},{$unset:{更新的内容}}) 【$unset:删除某些属性】 db.student.find({age:{$lt:20}}) 【筛选age小于20的学生】 db.student.find({age:{$lte:20}}) 【筛选age小于等于20的学生】 db.student.find({age:{$gte:20}}) 【筛选age大于等于20的学生】 db.student.find({age:{$gt:20}}) 【筛选age大于20的学生】 db.student.find({age:{$ne:20}}) 【筛选出年龄不是20的学生】 db.student.find({$or:[{sex:’女’},{age:{$lte:20}}]}) 【筛选出性别是女的或者年龄小于等于20的学生】 db.student.findOne({筛选条件}) 【只查找一条数据】 导出 mongoexport -d 数据库名称 -c 集合名称 -o “E:\mongosql.json” 导入 mongoimport -d 数据库名称 -c 集合名称 —file “E:\mongosql.json” —type=json
安装
npm install mongoose@5.0.15
创建DB.js文件【负责连接数据库】
const mongoose = require('mongoose'); /** * 数据库连接 */ mongoose.connect('mongodb://127.0.0.1/student_manage'); mongoose.connection.on('connected',function(){ console.log('mongodb connected') }) mongoose.connection.on('error',function(){ console.log('mongodb error') }) mongoose.connection.on('disconnected',function(){ console.log('mongodb disconnected') }) module.exports = { mongoose }
创建数据库集合模型【Schema、Model】例如:Student.js
const db = require('./DB');
/**
* 创建学生模型【规则】
*/
var StudentSchema = db.mongoose.Schema({
name:{type:String,required:true},
age:{type:Number,min:1,max:200},
sex:{type:String,enum:['男','女']},
tel:{type:Number},
tid:{type:String}
},{versionKey: false})
//这里的student ,对应数据库里面叫做 students的表
var Student = db.mongoose.model('student',StudentSchema)
module.exports = Student;
通过导出的实例完成CRUD【增删改查】
添加:
Student.create({ name:'小刘', age:20, sex:'女', tel:1012031, tid:'12313' },function(err,data) //或 var s = new Student({ name:'陈小姐', age:22, sex:'女', tel:123123, tid:"123123" }) s.save(function(err,res){})
更新:
Student.create({ name:'小刘', age:20, sex:'女', tel:1012031, tid:'12313' },function(err,data) //或 var s = new Student({ name:'陈小姐', age:22, sex:'女', tel:123123, tid:"123123" }) s.save(function(err,res){})
删除:
Student.deleteMany({name:'petper'},function(err,res)
//或
Student.findByIdAndRemove(id,function(err,res)
语法:
模型.find(查询条件,显示字段,回调函数)
例子:
//显示字段:1代表显示该字段,0代表不显示该字段
//res:是一个数组
Student.find({name:'jack'},{name:1,age:1},function(err,res))
//查询年龄在 21 到 65 之间的学员
Student.find({age: {$gte: 21, $lte: 65}}, callback)
//查询年龄不等于50的学员
Student.find({age: {$ne: 50}}, callback)
//查询名字中包含m的学员
Student.find({'name':{$regex:/m/i}}, function(err, res)
模型.count(查询条件,回调函数)
例子:
//res:返回查询结果的个数
Student.count({name:'jack'},function(err,res))
模型.findById(id值,回调函数)
例子:
//根据id查询唯一的记录
Student.findById('wdadw',function(err,res){})
分页查询:
例子:
var pageSize = 5; //一页多少条
var currentPage = 1; //当前第几页
var sort = {'logindate':-1}; //排序(1 升序,-1降序)
var condition = {}; //条件
var skipnum = (currentPage - 1) * pageSize; //跳过数
User.find(condition).skip(skipnum).limit(pageSize).sort(sort).exec(fn)
关联查询:
例子:
//学生表的tid关联了老师表的_id Student.aggregate([ { $lookup:{ from:'teachers', localField:'tid', foreignField:'_id', as:'results' } } ]).exec(function(err,result){ if(err){ console.log(err); } console.log(result) })
HTML页面->Node服务->MongoDB
MVC
M:Model【Student.js、Teacher.js】
V: View 【页面】
C: Controller 【控制器】:业务处理代码
协议名、域名、端口 三者都保持一致
协议名、域名、端口只要有一个不同,就是跨域请求
http://127.0.0.1:3000和http://127.0.0.2:3000
http://127.0.0.1:3000和http://127.0.0.1:3001
http://127.0.0.1:3000和ftp://127.0.0.1:3001
Ajax请求时才会失败
普通的HTML标签不会失败:
<form>、<img src="">、<script src="">、<iframe>
JSONP
CORS【跨域资源共享】
Nginx【应用服务器】
本质不是ajax,它并没有使用XMLHttpRequest对象,用的是动态创建script标签
只支持GET方式、书写比较复杂
兼容性非常好
支持所有请求方式:GET、POST、PUT、DELETE
const crypto = require('crypto')
var md5 = crypto.createHash('md5');
function MD5(content){
var str = md5.update(content).digest('hex')
return str;
}
var pass = MD5("123")
使用流程:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。