Skip to content
On this page

面向对象

Created: July 8, 2021 11:35 AM Tags: JavaScript

必看预习

  • 对象创建

    • 字面量方式

      javascript
      let obj = {
      	name:"张三"
      	age:20,
      	hobby:function(){}
      }
      
    • 构造函数:Object( )

      javascript
      let obj = new Object();
      obj.name = "张三"
      obj.age = 20
      obj.hobby = function(){}
      
    • Object.create ( )

      javascript
      let obj = Object.create({
      	name:"张三"
      	age:20,
      	hobby:function(){}
      })
      
  • 对象调用

    • obj.name
    • obj['name']
    • str = "name" obj[str]
  • 工厂模式(类似类):提高代码复用性,减少冗余

    javascript
    function 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运算符

    1. 执行函数
    2. 创建空对象
    3. 把空对象和this绑定
    4. 如果没有返还,隐式返还this
    javascript
    function Person(name,age,hobby){
    	this.name = name
    	this.age = age
    	this.hobby = function(){console.log(hobby)}
    }
    
    let zhangsan = new Person("张三",20,"喜欢篮球")
    
  • 构造函数

    是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

    1. 首字母大写
    2. this指向实例化对象
    • 静态属性和方法(属于类本身的)

      javascript
      Person.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一个对象,会覆盖实例化对象
    • 原型链(就近原则)

    javascript
    function 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(函数)
    javascript
    function 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)
    javascript
    function 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)) 
      
      • 定义深拷贝函数
      javascript
      function 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
      }
      
      • 组合继承
      javascript
      function 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
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博客

motao314/js-

  • 实现一个基本拖拽类
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)
    }

MIT Licensed | Copyright © 2021 - 2022