- Object
- 原型链
- Prototype
- ObjectFunction方法
- 封装函数自执行
- 继承
- es6 继承
- 组件封装
- jQuery的Extend:关于对象的扩充
- this 指向谁
- 闭包
jsoo称为js面向对象
,面向对象的
特征:封装
(把抽取出来的特征放到一起去组装),
继承
,
多态
,
抽象
(抽取特征)。
实体是类的具体体现,类是实体的抽象
Object
javascript">class Point{constructor(x,y) {this.x=x;this.y=y;};getStu(){return this.x+"+"+this.y;}
}let myPoint=new Point(9,9)
console.log(myPoint.getStu())
//Point(); 错误的,类只能用关键字newfunction Plane() {this.x=x;this.y=y;
}
Plane(); //构造函数也可以用普通函数的调用方式(只不过不是对象)
原型链
javascript">//创建对象的方法:
//1.通过new关键词
let obj1=new Object();
console.log(obj1) //能够得到一个实例化的对象,说明Object()是一个构造函数//2.通过字面量方式创建对象
let obj2={}
console.log(obj2)//__proto__:指向当前对象的构造函数的原型
//constructor:当前对象的构造者
//3.通过Object.create()创建对象
console.dir(Object) //底层Object的creat()方法
let obj3=Object.create({x:1}); //照着什么样子(简单模板{x:1})去创建对象;相当于字面量创建对象
console.log(obj3)obj3.y=2; //依照着谁(obj3)创建的内容,就在谁那层上面
console.log(obj3)//对象原型
let obj4=Object.create(obj3) //obj3并不是构造函数是对象,只是以obj3为模板来创建
console.log(obj4)console.log(obj4.__proto__); //obj4的原型指向obj3
console.log(obj4.__proto__.__proto__); //obj4 => obj3 => {x=1}
console.log(obj4.__proto__.__proto__.__proto__); //obj3 => {x=1} => Object原型
console.log(obj4.__proto__.__proto__.__proto__.__proto__); //obj3 => {x=1} => Object原型 => null
//对象存在堆中(引用类型存放在堆中)
/*let a=1;let b=a;b=2;console.log(a,b) //1 2let arr1=[1,2];let arr2=arr1; //正确赋值:arr2=[...arr1]arr2[0]=3;console.log(arr1,arr2) //[3,2] [3,2] 指向堆中的同一个地址
*///Object也有原型
Object.prototype.age=15;
console.log(obj4.age)function Plane() {this.name="飞机"
}
let plane=new Plane();
console.log(plane)
console.log(plane.age)Plane.prototype.x=150;
Object.prototype.x=200;
console.log(plane.x); //150 使用在原型链上离它最近的那个Plane.prototype.move=function () {console.log("MOVE")
}//NAME => MOVE => AGE
console.log("age" in plane) //true in表示对象是否能够访问某属性
console.log(plane.hasOwnProperty("age")) //false 对象自身是否有该属性
console.log(plane.constructor) //找出对象的构造者console.log(obj4.constructor)
Prototype
__proto__ 和 prototype 和 constructor 的区别
:
(1)__proto__和constructor是对象独有
的
(2)prototype是函数独有
的( 函数也是对象,所以函数也有__proto__和constructor )
(3)__proto__属性的作用:
当访问一个对象的属性时,如果该对象内部不存在这个属性,那么它就会去它的__proto__所指向的那个对象(父对象)里去找 (顺着原型链去找),一直找到__proto__属性的终点null,然后返回undefined,通过__proto__属性将对象链接起来的这条链路就是原型链
(4)prototype属性的作用:
让该函数所有实例化的对象都可以找到公用的属性和方法
(5)constructor属性的含义:指向该对象的构造函数
javascript">function Person() {this.sex="男";this.name="月月";
}//实例化
let p1=new Person();
// console.log(p1)
// console.log(p1.age) //undefined
// arr=[];
// console.log(arr[0]) //undefined
// let a;
// console.log(a) //undefined 对象属性、变量、数组是存在的,但是没有给它赋值
// p1.age=15;
let p2=new Person();
console.log(p1==p2) //false 只是内容一样,但指向不一样
console.log(p1.__proto__===p2.__proto__) //true 它们的原型是一样的
// console.log(p1)
// console.log(p2)Person.prototype.address="成都"; //原型上有的,实例化出来的对象上都有
console.log(p1.address,p2.address)function Dog() {this.sound="汪汪"
}
let d1=new Dog();
console.log(d1.address) //undefinedObject.prototype.color="white";
Person.prototype.color="yellow"
console.log(d1.color)
console.log(p1.color)Person.iq=false; //加指定对象的属性
console.log(p1.iq) //undefinedfunction myTest() {this.name="二狗子"
}
let b=new myTest();
console.log(b)
console.log(b.age) //undefined
b.age=18;
myTest.prototype.age=30;
Object.prototype.age=40;
console.log(b.age) //18 原型链就近原则
ObjectFunction方法
in \ 对象.hasOwnProperty("属性") \ instanceof \ delete \ prototype
javascript">//in(属性 in 对象:是否能够访问到某属性)
//对象.hasOwnProperty("属性"):属性是否是自身的//instanceof:判断对象是否是某个构造函数的实例对象,返回true或false
console.log(Function instanceof Object) //函数是否是Object的实例let obj=new Object();
// obj=null; //null是基本数据类型存在栈中,原本堆中的对象未被指向了,它会自动销毁
obj.name="张三";
console.log(obj.name) //报错:它不是对象,没法设置它的属性obj.name=null; //属性重新赋值
obj.sex="男";
delete obj.name; //属性清空(删某个属性)
console.log(obj)/*扩展:(练习如何使用prototype)*/
let d=new Date();
// console.log(d.formDate());
//希望new Date()出来的对象上都有formDate方法;如果用户传递了参数,输出结果xxxx-xx-xx,如果没有传参,输出当前时间2024-04-10Date.prototype.formDate=function () {console.log(arguments)if(arguments.length){return arguments[0]+"-"+arguments[1]+"-"+arguments[2]}else{return this.getFullYear()+"-"+(this.getMonth()+1)+"-"+this.getDate()}}
let d2=new Date();
console.log(d2.formDate(2000,10,10))
封装函数自执行
变量和函数都是暴露在外面的,谁都可以去修改
javascript">let a=10;
function getStudent(){console.log("getStudent")
}
a=20;
getStudent.prototype.hello=function () {}
自执行函数
<script src="3.js"></script>
<script>javascript">(function () {console.log("自执行函数")})(); //():自己调用自己//等同于:+function () { //+ - ~ !等其它一元操作符console.log("自执行函数")}()(function () {let b=10; //局部变量,作用域在自执行函数function内,超出就无法获取和使用function getStudent() {c=20; //c是全局变量,但如果getStudent函数不执行,就不会识别到c变量console.log("自执行函数内部的方法")}getStudent() //调用函数,识别到全局变量cconsole.log(c) //可以获取c})()console.log(c) //可以获取cgetStudent() //报错,调不到getStu();window.a="测试window对象的属性a";let x="测试全局变量x";console.log(a)console.log(x)
</script>
3.js文件
javascript">(function () {let a=10;function setStudent() {console.log("setStudent")}function getStudent() {console.log("自执行函数内部的方法")}//对外提供一个接口通道(外部不知道真正的名字,数据更安全)window.getStu=getStudent; //window.xxx表示去定义一个全局变量,效果和在外部定义let xxx全局变量一样的
})()
ajax.js的封装
javascript">/*ajax执行步骤:1.创建xhr对象2.打开ajax连接服务器:xhr.open(设置参数)3.发送请求到服务器:xhr.send()4.设置回调函数:xhr.onreadystatechange=function(){}readystate: 0 - 45.服务器接收请求,处理请求,响应resp.send()6.调用回调函数 =>4
*//*(function () {//创建xhr对象function createXHR() {let xhr=new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP");return xhr;}//执行ajax请求function ourAjax(obj) {let xhr=createXHR();//回调xhr.onreadystatechange=obj.success();//同步异步if(obj.sync==undefined){obj.sync=true;}//get或postif(obj.method=="get"){obj.url=obj.url+"?"+obj.data;xhr.open(obj.method,obj.url,obj.sync)xhr.send(null)}else if(obj.method=="post"){xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")xhr.open(obj.method,obj.url,obj.sync)xhr.send(obj.data)}}//提供给外部使用的接口window.myAjax=ourAjax();window.myCreateXHR=createXHR();
})()myAjax({url:"",method:"",data:,sync:true,success:function (){}
})*/let myFx=(function () {//创建xhr对象function createXHR() {let xhr=new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP");return xhr;}//执行ajax请求function ourAjax(obj) {let xhr=createXHR();//回调xhr.onreadystatechange=obj.success();//同步异步if(obj.sync==undefined){obj.sync=true;}//get或postif(obj.method=="get"){obj.url=obj.url+"?"+obj.data;xhr.open(obj.method,obj.url,obj.sync)xhr.send(null)}else if(obj.method=="post"){xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")xhr.open(obj.method,obj.url,obj.sync)xhr.send(obj.data)}}//返回给外部使用return {runAjax:ourAjax,creat:createXHR,}
})()myFx.runAjax({})/*封装的方法不一样,调用的方法也不一样*/
继承
继承:子模板和父模板的关系;作用:代码重用;语法:call 或 apply 或 原型继承
javascript">//飞机公用模板
function plane(x,y) {this.x=x;this.y=y;this.imgNode=document.createElement("img");this.speed=10;this.blood=5;this.move=function () {this.y+=10;console.log("飞机移动公用方式")}this.init=function () {}this.init();
}//玩家飞机
function planePlane(x,y) {// plane.call(this); //call继承,注意:继承放在子模板首行plane.call(this,x,y)//玩家飞机自己的属性和方法this.move=function () {console.log("玩家飞机的移动方式")}this.shoot=function () {console.log("玩家飞机攻击方式")}
}
let planer=new planePlane(100,100);
console.log(planer)
planer.move()//Boss飞机
function bossPlane(x,y) {plane.apply(this,[x,y]); //apply继承,传参时有所不同this.move=function () {console.log("Boss飞机的移动方式")}this.shoot=function () {console.log("Boss飞机攻击方式")}
}
let boss=new bossPlane(200,200)
console.log(boss)
boss.move()/*原型继承*/
function phone(name, price) {this.phoneName=name;this.phonePrice=price;this.callPhone=function () {}
}function iphone() {this.music=function () {}this.news=function () {}
}
let ip=new iphone();
console.log(ip)iphone.prototype=new phone("苹果15",600) //继承原型
let ip2=new iphone();
console.log(ip2.phoneName)
对象属性(合并)
javascript">// let o=new Object()
// o.name="月月";
// let s="sex";
// o[s]="男"; //区别在于:方括号中可以写变量
// console.log(o.sex , o["sex"] , o[s])function person() {this.name="月月";this.age=24;
}
let p=new person();
console.log(p)function student() {this.move=function () {};this.sex="女";
}
let s=new student();
console.log(s)//两个对象属性的合并(可以循环对象中的属性)
for(let i in p){console.log(i) //键名 name ageconsole.log(p[i]) //值 月月 24if(s[i]==undefined){s[i]=p[i]}
}
console.log(s)let s2=new student();
console.log(s2) //对原型构造函数本身没有影响,还是原本的样子
es6 继承
extends 、super
javascript">class test{constructor(x,y) {this.x=x;this.y=y;}gogo(){let a="gogogo";return a;}
}class myTest extends test{constructor(x,y,color) {super(x,y); //必须有,调用父类的constructor(x,y),如果不调用super方法,子类的继承就得不到this对象this.color=color;}toto(){return this.color+" "+super.gogo()}
}
let myT=new myTest(10,10,"red")
console.log(myT)
console.log(myT.toto())
组件封装
javascript">// $.ajax({}) == jquery.ajax({})
/*let myAjax=(function () {return {}
})()*/function util() {function person() {this.move=function () {console.log("gogogogo")}}person.prototype=util.prototype; //写在前,写在后;会有影响let p=new person()// person.prototype.name="月月"return p;
}util.prototype.name="月亮"
util.prototype.sing=function () {console.log("做饭特好吃~")
}
let myPerson=util();
console.log(myPerson)
myPerson.sing();
/*
将person.prototype=util.prototype写在后面会报错的原因:1.函数外部改变util的原型2.调用util()3.实例化对象4.设置person的原型就是util的原型对象都实例化了,后设置也用不上了
*///对外提供一个叫fn的方法来修改util.prototype(藏的更深一点,隐藏真正的属性和方法的目的)
(function () {function util() {function person() {this.move=function () {console.log("gogogogo")}}person.prototype=util.prototype;let p=new person()return p;}util.fn=util.prototype;window.jquery=util;window.$=util;
})()// util.prototype.name="秀芹"; //自执行函数内部的外部拿不到
$.fn.name="秀琴";
$.fn.sing=function () {console.log("唱歌~")
}
$.fn.css=function () {console.log("css方法")
}let p=$();
console.log(p)
p.css()
jQuery的Extend:关于对象的扩充
扩展jQuery对象的两种方法:全局,jQuery.ajax() ;局部,只针对的是某一个实例化的对象 jQuery().css()
javascript">全局:$.extend()作用:在jQuery对象上扩充对象 (内写属性、方法)语法:(1)$.extend(需要扩充的对象,作为扩充用的对象......)(2)$.extend(只有一个对象参数时就是扩展jQuery自己)局部:$.fn.extend()作用:在jQuery实例化的对象上扩充对象(内写属性、方法)
<script src="2.jquery.3.6.js"></script>
<script>javascript">$(function () {let obj1={name:"沈璃",sex:"女",tel:"电话号码"}let obj2={name:"行止",sex: "男",title:"cp滴滴"}console.log(obj1.title); // undefined$.extend(obj1,obj2); //扩展对象;并不会改变作为扩充用的对象console.log(obj1,obj2); //合并后,相同的属性,值会被覆盖console.log("title" in obj1) //trueconsole.log(obj1.hasOwnProperty("title")) //true//$.extend扩充jQuery对象(当只有一个对象参数的时候就是扩展jQuery它自己)console.log("扩充前myname:"+$.myname)$.extend({ //写属性myname: "小仙女"})console.log("扩充前myname:"+$.myname)let obj={ //写方法mySum:function (a,b) {return a+b;}}$.extend(obj)console.log($.mySum(2,2)) //--------------全局扩展//--------------局部扩展//$().html() 得到jQuery实例化的对象后再去使用属性和方法(jQuery本身是一个构造函数)$.fn.extend({"mystudent":"阳光明媚"});$.fn.extend({ganfan:function () {console.log("一顿干两碗")}})console.log($("#box").mystudent) //这样jQuery实例化的每个对象上都有了扩展的属性、方法可以使用$("#box").ganfan()})
</script>
原理(理解后可封装自定义内容,或再进行扩充)
<div id="box"></div>
<script>javascript">// $("#div") 1.封装对象// $(".div")// $("div").html("123") 2.扩展对象//封装(把写好逻辑的函数放入自执行函数中)(function () {function jQuery(selector) {return new Init(selector) //返回一个对象}function Init(selector) {this.node="";if(/^#/.test(selector)){ //使用正则表达式this.node=document.getElementById(selector.substring(1))}else if(/^\./.test(selector)){this.node=document.getElementsByClassName(selector.substring(1))}else if(/\D*/.test(selector)){this.node=document.getElementsByTagName(selector)}}Init.prototype.html=function (content) {console.log("html方法");this.node.innerHTML=content;}jQuery.fn=jQuery.prototype=Init.prototype; //如果想要扩展方法就可以这样,既不那么直接且保证了安全(a=b=c a=c b=c)window.$=window.jQuery=jQuery;})()console.log($("#box"),jQuery("#box"));$("#box").html("哈哈哈")//局部扩展:$.fn.css=function () {console.log("css方法")}$("#box").css();//全局扩展:jQuery.extend=function (obj) {for(let key in obj){jQuery[key]=obj[key] //扩到全局对象上}jQuery.fn.obj=obj; //扩到实例对象上;因为是把obj(对象)直接给了它,所以调用时写法不同(实例对象.obj.方法名)}jQuery.extend({each:function () {console.log("全局扩展的each方法")},newFn:function () {console.log("全局扩展的newFn方法")}})jQuery.each();jQuery.newFn();console.log(jQuery.fn)$("#box").obj.each();$("#box").obj.newFn();
</script>
this 指向谁
<button id="btn1" onclick="window.btn1()">按钮1</button>
<button id="btn2" onclick="window.btn2(this)">按钮2</button>
<button id="btn3">按钮3</button><script>javascript">function btn1() {console.log(this); //指向window,平时写的时候都是省略的写window.person()}function btn2(obj) {console.log(obj); //obj指向节点console.log(this); //指向window}function btn3() {console.log(this); //指向节点}document.getElementById("btn3").onclick=btn3;/*function person() {console.log(this); //指向对象pthis.move=function () {console.log(this); //指向对象p}}let p=new person();p.move();*//*function person() {this.name="月月";this.move=function () {console.log(this); //指向对象p// window.setTimeout(function () {//指向windowwindow.setTimeout(()=>{console.log(this); //指向对象p(箭头函数)},0)}}let p=new person();p.move();*//*function person() {this.name="月月";this.move=function () {console.log(this.name); //月月let that=this;setTimeout(function () {console.log(that.name); //指向对象pconsole.log(this.name); //"",这里的this指向window,window下有属性name:""})}}let p=new person();p.move();*//*function myTest() {function test() {// console.log(this); //指向windowconsole.log(this); //指向对象a}// return test;return {test:test};}// let a=myTest(); //a=testlet a=myTest(); //a={test}// a()a.test()*/function test() {function test1() {console.log(this); //指向对象cfunction test2() {console.log(this); //指向window}return test2;}return {test1:test1};}let c=test(); // c={test1}let b=c.test1(); //b=test2b()
</script>
闭包
闭包:解决私有化(封装私有变量,以防止其被外部访问和修改);解决外部调用函数内部变量(在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量);
需要手动释放闭包资源占用的内存
javascript">/*let a=10;
function test() {let b=10;c=20; //没有写关键词let var它就是个全局变量,但是该全局变量需要函数被调用才能识别到console.log(c) //20console.log(a) //10
}test();
console.log(c) //20
console.log(b) //局部变量:b is not defined*///简单闭包的写法:
/*function closure() {let a=10;function add() {a++;console.log(a)}return add;
}let addFun=closure(); //add
addFun(); //11
addFun(); //12*/function plane() { //飞机模板}
function creatPlane() { //创建飞机let list=new Array();function addPlane() {let p=new plane();list.push(p);console.log(list)}function getList() {console.log(list)let returnList=[...list]; //是一个新数组后,从而别人就修改不到原数组return returnList; //return出去别人才能拿到使用(不要return原数组以防数据被修改)}return {addPlane,getList};
}function movePlane() { //飞机移动let planeList=create.getList();planeList.push("哈哈哈") //修改不到原数组上console.log(planeList)
}let create=creatPlane(); //{}
create.addPlane(); //list.push(飞机)
create.addPlane();
create.addPlane();
movePlane()//释放内存;闭包资源一直会在内存中不会释放,需要手动设置释放(原理:它会认为你后续还会用到creatPlane()中的变量等等,就不会自动销毁)
create=null;