面向对象
Created: July 8, 2021 11:35 AM Tags: JavaScript
必看预习
对象创建
字面量方式
javascriptlet obj = { name:"张三", age:20, hobby:function(){} }
构造函数:Object( )
javascriptlet obj = new Object(); obj.name = "张三" obj.age = 20 obj.hobby = function(){}
Object.create ( )
javascriptlet obj = Object.create({ name:"张三", age:20, hobby:function(){} })
对象调用
- obj.name
- obj['name']
- str = "name" obj[str]
工厂模式(类似类):提高代码复用性,减少冗余
javascriptfunction Person(name,age,hobby){ let obj = {} obj.name = name obj.age = age obj.hobby = function(){console.log(hobby)} return obj; } let zhangsan = Person("张三",20,"喜欢篮球")
new运算符
- 执行函数
- 创建空对象
- 把空对象和this绑定
- 如果没有返还,隐式返还this
javascriptfunction Person(name,age,hobby){ this.name = name this.age = age this.hobby = function(){console.log(hobby)} } let zhangsan = new Person("张三",20,"喜欢篮球")
构造函数
是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
- 首字母大写
- this指向实例化对象
静态属性和方法(属于类本身的)
javascriptPerson.num++ Person.fn = function(){}
静态成员
原型对象:公共空间
javascript**Person.prototype.**hobby = function(){} console.log(zhangsan.hobby === lisi.hobby) //true zhangsan.__proto__ === Person.prototype //true Person.prototype.constructor === Person //true zhangsan.prototype.constructor === Person //true
- 用法:判断类型
原型和构造函数this都指向实例化对象
构造函数中不要使用return
- 如果return一个基本数据类型,会被实例化对象覆盖
- 如果return一个对象,会覆盖实例化对象
原型链(就近原则)
javascriptfunction Person(name){ this.name = name this.test = "你好111" //结果:你好 } Person.prototype.test = "hello" //结果:hello Object.prototype.test = "你好222" //结果:你好 let zhangsan = Person("张三") console.log(zhangsan.test)
- call apply bind(函数)
javascriptfunction foo (name,age){ console.log(this) } foo(); //返回windows let obj = { name:"张三" } **foo.call**(obj,**"张三",20**) //改变this指向 **foo.apply**(obj,**["张三",20]**)//改变this指向,区别:参数 **foo.bind**(obj)**("张三",20)**//多执行一次函数
- 继承(ES5)
javascriptfunction Dad(name,age){ this.name = name this.age = age this.money = 10000 } Dad.prototype.fn = function(){} function Son(anme,age){ **Dad.call(this,name,age)** //ES5语法 this.sex = '男' } Son.prototype = new Dad(name,age) //构造函数的原型是一个对象,这里我们把Dad实例放在这里,通过Person 的实例对象就可以拿到Person的prototype的所有方法 let zhangsan = new Son("张三",20) console.log(zhangsan.money) console.log(zahngsan.sex) zhangsan.fn() //默认不能继承 Son.prototype = Dad.prototype //传址,改变子类的prototype也会改变父类的prototype Son = Dad //传址,改变子类也会改变父类
复杂数据类型传址,简单数据类型传值
深拷贝
- JSON法
javascript//使用这个方法会丢失方法和undefined的字段 let Son = JSON.parse(JSON.srtingify(Dad))
- 定义深拷贝函数
javascriptfunction deepCopy(obj){ let newObj = Array.isArray(obj)?[]:{} for(let key in obj){ if(obj.hasOwnProerty(key)){ if(typeof obj[key] === "object"){ newObj[key] = deepCopy(obj[key]) }else{ newObj[key] = obj[key] } } } return newObj }
- 组合继承
javascriptfunction Dad(name,age){ this.name = name this.age = age this.money = 10000 } Dad.prototype.fn = function(){} **let Link = function(){} Link.prototype = Dad.prototype Son.prototype = new Link() Son.prototype.constructor = Son**
正式课程
- console.dir( ):将对象的数据属性和方法都展开
- Class语法:语法糖,还是会转化为function
javascript
class Person(){
consrtuctor(name,age){
this.name = name
this.age = age
this.sayName = function(){
console.log(this.name)
}
}
}
let p = new Person("kkb",8)
- 大多数情况下,__proto__可以理解为“构造器的原型”,即:
javascript
__ptoto__ === constructor(构造函数).prototype
- 自定义属性
javascript
<div id="box" data-kkb="8">box</div>
let box = document.querySelector("#box")
box.dataset.kkb = 20;
box.onclick = function(e){
let {target} = e
console.log(target)
}
- 原型与原型链
- 原型:函数中的属性
- 原型链:对象中的属性,对象的原型链链接其构造函数的原型
- 当我们调用对象的某个属性(方法),如果对象自身没有,就会通过他的原型链属性,去找其构造函数的原型中是否有这个方法
- this的指向
- function:function的this,谁调用的this指向谁
- 全局调用:windows
- 作为对象的属性调用,this 指向该对象
- 箭头函数:本身没有this,其this继承声明时所在作用域的this
- function:function的this,谁调用的this指向谁
javascript
let f1 = function(){
console.log(this)
}
let f2 = ()=>{
console.log(this)
}
document.onclick = f1
document.body.onclick = f2
class Drag{
constructor(f){
this.f = f
}
}
f1(); //windows
f2(); //windows
document.onclick(); //document
document.body.onclick(); //windows
new Drag(f1).f(); //drag{}
new Drag(f2).f(); //windows
- 作用域
- 全局作用域
- 函数作用域
- 块作用域
- 公有字段:在实例化对象中也能正常使用,作为对象的一个普通属性存在
- 私有字段:只能在类中使用,不能在实例对象中使用,加#
- 继承extends
javascript
class Person{
constructor(name,age){
this.name = name
this.age = age
}
}
class Teacher extends Person{
constructor(name,age){
//如果在子类中定义constructor,一定在这里调用super
super(name,age)
this.speciality = "讲课"
}
}
- 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
- 类中实现多态
面试题, 实现一个Event类_JoshFenge的博客-CSDN博客
- 实现一个基本拖拽类
javascript
class baseDrag{
//元素起始的位置
startEl= {}
//鼠标起始的位置
startMouse = {}
//将该元素设置为私有属性,可实现不同元素多次复用
#el = null
//构造函数
constructor(el) {
this.#el = el //将传进来的元素进行赋值
this.start()
}
//摁下时要做的事
start(){
let move = (e)=>{
// console.log(e)
this.move(e)
}
//监听鼠标按住的事件
this.#el.addEventListener("mousedown",(e)=>{
//记录鼠标开始位置
this.startMouse={
x:e.clientX,
y:e.clientY
}
//自定义内容
this.onDragStart&&this.onDragStart()
//监听鼠标移动事件,调用move事件
document.addEventListener("mousemove",move)
document.addEventListener("mouseup",()=>{
document.removeEventListener("mousemove",move)
this.end()
},{once:true})
})
}
//移动时要做的事,对元素位置进行改变
move(e){
//记录鼠标当前位置
let nowMouse = {
x:e.clientX,
y:e.clientY
}
//计算出当前移动的距离
let disMouse = {
x: nowMouse.x - this.startMouse.x,
y: nowMouse.y - this.startMouse.y
}
//自定义内容
this.ondragmove&&this.ondragmove()
}
end(){
//自定义内容
this.ondragend&&this.ondragend()
}
}
- Event类
javascript
class Event {
events = {} //事件池
on(eventName, Fn) { //添加一个事件处理
if (!this.events[eventName]) {
this.events[eventName] = []
}
if (!this.events[eventName].includes(Fn)) {
this.events[eventName].push(Fn)
}
}
off(eventName, Fn) { //删除一个事件处理
if (!this.events[eventName]) {
return
}
this.events[eventName] = this.events[eventName].filter(item => item != Fn)
}
dispatch(eventName, ...arg) { //触发事件
if (!this.events[eventName]) {
return
}
this.events[eventName].forEach(item => {
item.call(this, ...arg) //重新指向
})
}
}
- 静态属性&静态方法:给类用的,不能给实例化对象使用,在属性和方法前面加上static,this指向这个类
- 类命名:首字母大写
- 严格模式:
- 不允许使用未声明变量
- 不允许变量重名
- 不允许使用八进制
- 不允许对只读属性赋值
- 不允许使用转义字符
- 变量名不能使用“eval”字符串
- 变量名不能使用“arguments”字符串
- 禁止this关键字指向全局对象
- ...
- JQuery原理解析
javascript
class JQuery {
constructor(arg, root) {
root = root || $(document, {}) //把上次的操作对象存入this的prevObject
this["prevObject"] = root
if (typeof arg === "string") {
//如果是一个字符串类型,就先获取元素然后通过setElement把元素绑定在this上
let ele = document.querySelectorAll(arg)
this.setElement(ele)
} else if (typeof arg === "object") {
//如果是一个对象类型,就通过setElement把元素都绑定在this上
this.setElement(arg)
} else if (typeof arg === "function") {
//如果传入是一个函数,在文档读完之后执行这个函数
//DOMContentLoaded 文档读完
//onload 资源也加载完
window.addEventListener("DOMContentLoaded", arg)
}
this.cssHooks = {} //设置css代理
}
eq(index) {
//当用户调用eq方法后,这会使操作对象进行改变,返回把上一次的this传入
return $(this[index], this) //加上$()实现链式操作,返回一个JQuery对象
}
//调用end方法,返回我们上一次的操作对象
end() {
return this["prevObject"]
}
setElement(eles) {
if (eles.length === undefined) {
//如果传进去的是一个元素,则把length设为1,方便后续进行循环操作
this[0] = eles
this.length = 1
} else {
for (let i = 0; i < eles.length; i++) {
this[i] = eles[i]
}
this.length = eles.length
}
}
click(fn) {
//依次添加事件
for (let i = 0; i < this.length; i++) {
this[i].addEventListener("click", fn)
}
return this //将这个实例化对象接着返回
}
//添加事件
on(eventNames, fn) {
//eventNames eventNames可以存放多个事件名称,每个事件名称用空格隔开
eventNames = eventNames.trim().split(" ");
eventNames = eventNames.filter(item => item)
for (let i = 0; i < this.length; i++) {
for (let j = 0; j < eventNames.length; j++) {
this[i].addEventListener(eventNames[j], fn)
}
}
}
//添加样式
css(...arg) {
if (typeof arg[0] === "string") { //string不是String
if (arg.length > 1) {
//两个参数设置样式
for(let i = 0;i < this.length;i++){
JQuery.setStyle(this[i],arg[0],arg[1])
}
} else {
//一个参数获取样式
return JQuery.getStyle(this[0],arg[0]) //默认获取第一个元素
}
} else if (typeof arg[0] === "object") { //object不是Object
//批量设置样式
for(let i = 0;i<this.length;i++){
for(let s in arg[0]){
//s:key值 arg[0][s]:value值
JQuery.setStyle(this[i],s,arg[0][s])
}
}
}
return this //链式操作
}
setStyle(el,attr,val){
if(attr in this.cssHooks){
//如果attr这条是一个样式,用户设置hooks,直接调用hooks把设置权交还给用户
$.cssHooks[attr].set(el,val)
}else {
el.style[attr] = val
}
}
getStyle(el,attr){
if(attr in this.cssHooks){
return $.cssHooks[attr].get(el)
}
return getComputedStyle(el)[attr]
}
}
function $(...arg) {
return new JQuery(...arg)
}