首页 > 其他分享 >18js面向对象回顾及原型讲解

18js面向对象回顾及原型讲解

时间:2022-08-19 21:22:26浏览次数:62  
标签:__ console log Person proto 面向对象 18js 讲解 prototype

面向对象回顾

核心概念:万物皆对象 (顶层对象Object)抽取名词作为属性 抽取行为作为方法

俩种构建对象的方式

构造函数构建
es6的形式 class
class Person{
    constructor(){ //构造器
        this.name = 'jack'
    }
}

 

es3的形式 function
function Person(){
    this.name = 'jack'
}

 

使用new关键词
var person = new Person()

 

  • 自动构建对象

  • 手动设置属性

  • 自动返回对象

工厂构建
function factory(){
    var obj = new Object()
    obj.name = 'jack'
    return obj
}

 

调用方法
var person = factory()

 

  • 手动构建对象

  • 手动设置属性

  • 手动返回对象

prototype

概述:所有的函数都拥有一个属性 这个属性称为prototype 他是一个对象空间(里面就可以存放对应的数据)他被称为显式原型

示例
function fn(){
    
}
//打印这个属性对应的空间
console.log(fn.prototype)

 

 

  • constructor 构造器他指向对应的构建的函数(指向他自己)

  • 根据上面的我们可以看到每个函数都有这样的一个属性,那么作为构造函数也有对应prototype属性

function Person(){
    
}
console.log(Person.prototype) //作为一个属性存在 属性是唯一 也就是当前他只有一个prototype 属性的声明只会声明一次

 

  • 作为一个属性存在 属性是唯一 也就是当前他只有一个prototype 属性的声明只会声明一次

  • 因为当前这个属性 他对应的是一个对象空间,所以他里面的内容可以被更改和设置的

  • 那么我们就可以在这个里面存放一些内容

function Person(){
​
}
Person.prototype.username = 'jack' //往这个对象空间存放一个属性 叫username
Person.prototype.age = 18 //往这个对象空间存放一个属性 叫age
Person.prototype.sayHello = ()=>{}
console.log(Person.prototype)
通过实例对象 来访问对应的prototype里面的属性

//取出里面数据 因为构造函数是用于构建对象的 所以我们这个prototype的里面数据 是应该给实例对象去获取
var person = new Person()
//访问原型中数据(构造函数的prototype里面的属性)实例对象.属性名
console.log(person.username);

 

  • 因为上面讲过 对应的prototype是作为构造函数的属性 而构造函数的他只声明一次 那么对应的prototype也只声明一次

  • 也就意味者 你每次拿到的prototype是一个 也就是说他里面存放的数据也只声明一次

var person1 = new Person()
console.log(person1.sayHello == person.sayHello);//true

 

  • 由此可见 如果想对应的数据只声明一次的情况 我们可以放在原型里面

总结

  • 一般把方法放在原型里面

  • 把属性放在构造函数里面

function Son(){
    this.name = 'jack'
    this.age = 18
}
Son.prototype.print = function(){
    console.log(this); //指向当前的实例对象
    console.log(this.name); //指向当前的实例对象
}
new Son().print()

 

__proto__

概述:每个对象都有一个属性 叫做__proto__,他也是一个内存空间,他指向对应的构造函数的prototype。称为隐式原型。

示例
var obj = {}
console.log(obj.__proto__) 

这个对象空间里面也可以存储对应的数据 这个__proto__ ,他是每个对象都有的,那么实例对象也是个对象他同样也有。

function Person(){

}
let person = new Person()
person.__proto__.username = 'jack'
console.log(person.__proto__)
//通过打印的结果 我们可以看到对应的里面的结果类似于我们的构造的prototype
console.log(Person.prototype == person.__proto__) //ture

 

从上述代码 大家可以看到对应的构造函数的prototype和对应的实例对象的__proto__ 是相等,那么也就证明了对应俩个内容其实是一个对象。那么我们就要明白 谁指向谁,从对应的先后顺序来看,我们知道先有的构造函数再有的实例对象,所以对应的实例对象的__proto__ 是指向对应的构造函数的prototype。那么这个内容是不是就是对象访问原型的属性(所以他又被称为隐式原型),所以我们在实际使用中并不会用到__proto__ ,而是通过这个属性来访问对应的显式原型

总结

  • 实例对象__proto__ 是指向对应构造函数的prototype

  • 在实际使用中一般不会用__proto__ ,是通过他来访问对应的prototype

从上可得对应的实例对象的__proto__ 是指向构造函数的prototype,那么请问对应的函数是不是也是一个对象,他同样具备__proto__ ,那么他的__proto__ 指向谁,最终又指向谁?

原型链

概述: 原型链其实就对应的寻找原型(__proto__)的过程组成的一个链式结构,称为原型链。

示例
Object.prototype.hello = 'hello'
class Person{
    constructor(){
        this.username = 'jack'
    }
}
Person.prototype.age = 18
class Son extends Person{
    constructor(){
        super()
    }
}
Son.prototype.say = ()=>{}
let son = new Son()
//son的__proto__指向构造函数的原型 对应的Son这个构造函数的__proto__又指向了对应的父类的原型
//对应的父类的构造的函数原型的__proto__指向了对应的Object的构造函数的原型 
//那么对应的Object的构造函原型的__proto__ 指向null 这个寻找的过程就称为原型链
console.log(son.__proto__.__proto__.__proto__.__proto__);
//那么接下来 我们又知道了对应的对象去访问原型的中属性 直接通过点的形式
//又明白了作用域链 是一层一层向上找变量作用域
//所以我们又可以通过原型链来找对应的属性 原型中的属性
console.log(son.age); //18
console.log(son.hello); //hello
console.log(son.abc); //undefined 

这个寻找的过程就称为原型链

那么我想问请问对应的对象的属性赋值算不算原型链

不是 不是 不是!!!!

那么对象的属性赋值的操作有就覆盖 没有就添加

1.找的到就覆盖这个值

2.找不到就添加这个属性

利用原型来实现对应的底层源码

实现对应的数组的高阶函数
//find findIndex
Array.prototype.myFind = function(fn){
    //先遍历数组
    for(var i=0;i<this.length;i++){
        if(fn(this[i],i,this)){
            return this[i]
        }
    }
}
Array.prototype.myFindIndex = function(fn){
    var index = -1
    //先遍历数组
    for(var i=0;i<this.length;i++){
        if(fn(this[i],i,this)){
            index = i
            break
        }
    }
    return index
}
//map forEach
Array.prototype.myMap = function(fn){
    var result = []
    //先遍历数组
    for(var i=0;i<this.length;i++){
        result.push(fn(this[i],i,this))
    }
    return result
}
Array.prototype.myForEach= function(fn){
    //先遍历数组
    for(var i=0;i<this.length;i++){
        fn(this[i],i,this)
    }
}

 

继承

概述:

继承属于面向对象的三大特性之一,面向对象的三大特性。封装 (抽取内容封装) 继承(子类继承父类) 多态(重写 重载)

继承为子类继承父类的内容,子类可以拥有父类所有的非私有的属性及方法。

继承的实现

extends 关键词(class的继承)*(es6的)
class Person{
    constructor(){
        this.username = 'jack'
    }
}
class Son extends Person{
    constructor(){
         super()
    }
}
console.log(new Son().username) //jack

 

原型继承(prototype赋值给需要继承的对象)
function Person(){
    this.password = '123'
}
function Son(){

}
Son.prototype = new Person()
console.log(new Son().password )//123

 

组合继承 (原型+call改this指向)
//组合继承
function Person() {
    this.password = '123'
}
function Son() {
    Person.call(this) //将person里面的this改成Son里面的this
}
Son.prototype = new Person()
console.log(new Son().password) //123

 

对象冒充(改this指向 找不到原型上的内容(无法继承原型))
//对象冒充
function Person() {
    this.password = '123'
}

function Son() {
    Person.call(this) //将person里面的this改成Son里面的this
}
let son = new Son()
console.log(son.password);

 

多态

概述:一个东西多种形态体现,(水 冰 水汽)。子类是父类多态的体现(基于继承的)。

重写 子类重写父类的方法
function Person(){
    this.sayHello = ()=>{
        console.log('你好')
    }
}
function Son(){
    this.sayHello = ()=>{
        console.log('hello') //子类重写父类方法
    }
}
Son.prototype = new Person()
let son = new Son()
son.sayHello() //hello

 

重载 同一个类里面有多个同名的方法(覆盖 js没有重载)

重写应用

基础拖拽类
class Touch {
    constructor(ele) {
        this.ele = ele
        this.handlerDown()
    }
    handlerDown() {
        this.ele.onmousedown = (e) => {
            e = e || event
            //记录的是鼠标在div里面的位置
            //在mousedown里面记录按下的位置
            this.x = e.offsetX
            this.y = e.offsetY
            this.handlerMove()
            this.handlerUp()
        }
    }
    handlerMove() {
        document.onmousemove = (e) => {
            e = e || event
            //记录每次的位置  在document里面的位置
            var currentX = e.pageX
            var currentY = e.pageY
            //并且设置div的位置
            this.ele.style.left = currentX - this.x + "px"
            this.ele.style.top = currentY - this.y + "px"
        }
    }
    handlerUp() {
        //给document添加mouseup事件
        document.onmouseup = function () {
            //清除对应的mousemove事件
            document.onmousemove = null
        }
    }
}
var box = document.getElementById('box')
new Touch(box)

 

固定拖拽
class FixedTouch extends Touch {
    constructor(box, ele) {
        super(ele)
        this.box = box
    }
    handlerMove() {
        document.onmousemove = (e) => {
            e = e || event
            //记录每次的位置  在document里面的位置
            var currentX = e.pageX - getOffset(this.box).left
            var currentY = e.pageY - getOffset(this.box).top
            //范围判断
            this.target = {
                x: currentX - this.x,
                y: currentY - this.y
            }
            if (this.target.x < 0) {
                this.target.x = 0
            }
            if (this.target.y < 0) {
                this.target.y = 0
            }
            if (this.target.x > this.box.clientWidth - this.ele.offsetWidth) {
                this.target.x = this.box.clientWidth - this.ele.offsetWidth
            }
            if (this.target.y > this.box.clientHeight - this.ele.offsetHeight) {
                this.target.y = this.box.clientHeight - this.ele.offsetHeight
            }
            //并且设置div的位置
            this.ele.style.left = this.target.x + "px"
            this.ele.style.top = this.target.y + "px"
        }
    }
}

 

基于固定拖拽的放大镜
class Magnifier extends FixedTouch {
    constructor(smallBox, bigBox) {
        //调用父类构造
        super(smallBox, smallBox.querySelector('.move'))
        this.smallBox = smallBox
        this.bigBox = bigBox
        this.move = smallBox.querySelector('.move')
        this.bigImg = bigBox.children[0]
        this.init()
        this.handlerHover()
        //取消按下的事件
        this.handlerDown = () => {}
        //调用move 
        this.handlerMove()
    }
    init() {
        //计算对应的move这个盒子的宽高
        // 大的比大的等于小的比小的 bigImg/bigBox = box/move ==>  bigImg/box == bigBox/move
        this.move.style.width = this.smallBox.clientWidth / (this.bigImg.clientWidth / this.bigBox
            .clientWidth) + 'px'
        this.move.style.height = this.smallBox.clientHeight / (this.bigImg.clientHeight / this.bigBox
            .clientHeight) + 'px'
        //先需要隐藏
        this.move.style.display = 'none'
        this.bigBox.style.display = 'none'
    }
    handlerHover() {
        //移入移出
        this.smallBox.onmouseenter = () => {
            this.move.style.display = 'block'
            this.bigBox.style.display = 'block'
            //x y的属性值
            this.x = this.move.clientWidth / 2,
                this.y = this.move.clientHeight / 2
        }
        this.smallBox.onmouseleave = () => {
            this.move.style.display = 'none'
            this.bigBox.style.display = 'none'
        }
        //添加一个移动的事件
        this.smallBox.onmousemove = () => {
            //改变大盒子里面图片的位置
            this.bigImg.style.left = -this.target.x * this.bigImg.clientWidth / this.smallBox.clientWidth + 'px'
            this.bigImg.style.top = -this.target.y * this.bigImg.clientHeight / this.smallBox.clientHeight + 'px'
        }
    }
}

 

es6的模块化

import 导入

export 导出

es6的写法
<script type='module'></script>

 

一个内容如果需要导入 必须先从其他地方导出

第一种写法

export导出
//对象
const obj = {
    username:"jack",
    password:'123'
}
//函数
const sayHello = ()=>{
    console.log('hello');
}
//值
const message = '这个是一个信息'
//数组
const arr = [1,2,3,4]

//变量的接的数据 需要导出必须用{}
export {
    obj,
    sayHello,
    message,
    arr
}

 

import导入
import {
    obj,
    sayHello,
    message,
    arr
} from './a.js'  //解构
sayHello()

console.log(`obj`, obj);
console.log(`message`, message);
console.log(`arr`, arr);

 

第二种写法

export 导出
export const obj = {
        username:"jack",
        password:'123'
    }
export const sayHello = ()=>{
    console.log('hello');
}
export const arr = [1,2,3,4]
export const message = '这个是一个信息'

 

import 导入
//* 表示所有的 as取别名(随便取)
import * as hello from './a.js' 
hello.sayHello()

console.log(`obj`, hello.obj);
console.log(`message`, hello.message);
console.log(`arr`, hello.arr);

 

第三种写法

export 导出
export default {
    obj,
    sayHello,
    message,
    arr
}

 

import 导入
import a from './a.js' 
a.sayHello()

console.log(`obj`, a.obj);
console.log(`message`, a.message);
console.log(`arr`, a.arr);

 

总结

export 导出内容
  • export const 对应的变量

  • export default 对应的变量

  • export {}

import 导入内容
  • import 变量名 from 文件地址 (所有的话 * 必须取别名 as)

标签:__,console,log,Person,proto,面向对象,18js,讲解,prototype
From: https://www.cnblogs.com/sshong/p/16603353.html

相关文章

  • 面向对象——多态
    多态即同一方法可以根据发送对象的不同而采用不同的行为方式多态是指不同的子类在继承父类后分别都重写覆盖了父类的方法,即父类同一个方法,在继承的子类中表现出不同的形......
  • 第7章 面向对象编程(基础部分)
    ​7.1 类与对象oop     问题:编写一个程序,输入猫名字,显示该猫的名字,年龄,颜色     现有技术:单独定义变量、数组;缺点:不利于数据管理,效率低   ......
  • Python-面向对象
    面向对象面向对象是一种编程思想,即按照真实世界的思维方式构建软件系统.定义类class类名[(父类)]:类体创建对象用类创建对象的过程称为实例化,是将类这个抽......
  • JavaSE:第四章:面向对象上
    史上最全的知识体系脑图,覆盖所有知识点,所有细节,注意事项。面向对象上:包含面向对象与面向过程,类和对象,属性,方法,封装和隐藏,构造器(构造方法),this的使用,值传递,package、impor......
  • 23、面向对象编程
    23、面向对象编程 目录:对象的概念类与对象面向对象编程类的定义与实例化属性访问类属性与对象属性属性查找顺序与绑定方法小结视频链接 ......
  • 面向对象思想的概述和面向对象思想的举例
    面向对象思想的概述 面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节面向对象:当需要实现一个功能的时候,不关心具体的步骤,而是找一个......
  • 面向对象——封装
    封装该露的露,该藏的藏我们程序设计要追求”高内聚,低耦合“。高内聚就是类的内部数据细节由自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。封装(数据的隐......
  • 面向对象回顾及原型讲解
    面向对象回顾      核心概念:万物皆对象(顶层对象Object)抽取行为作为方法抽取名词作为属性    俩种构建对象的方式      构造函数构建......
  • 面向对象——类与对象的关系
    类和对象的关系类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物对象是抽象概念的具体实例创建和初始化对象使用new关键字创建......
  • 面向对象——初识面向对象、回顾方法定义调用
    初识面向对象属性+方法=类对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象来分析整个系统。但是,具体到微观操作,让然需要面向过程的思路去处......