js的第19天(原型和继承))

day19 原型和继承


面向对象回顾

通过new构造函数的方式

class的constructor (es6)

class Person{

    constructor(name){ //构造器

        this.name = name

    }

}

var person = new Person('tom')

function的方式 (es3)

function Person(name){

this.name = name

}

var person = new Person('jack')

步骤

自动构建对象

手动设置属性

自动返回对象

通过工厂模式

function factory(name){

var obj = new Object()

obj.name = name

return obj

}

步骤

手动构建对象

手动设置属性

手动返回对象

构造函数的缺陷

function Person(name){

this.name = name

this.age = 18

this.sayHello = ()=>{

console.log('hello');

}

}

var person = new Person('jack')

var person1 = new Person('tom')

console.log(person == person1);//false 对应的存储地址不一样

console.log(person.age == person1.age);//true

console.log(person.sayHello == person1.sayHello);//false 函数也是引用数据比较的是地

址、

因为上面的俩个sayHello方法不是一个方法 证明每次去new一个对象的时候对应的sayHello就会

重新在对应的堆上开辟一个内存

如果对应的new的操作很多那么对应的sayHello占用的内存就很大 (效率就低了)

按照我们的思考 sayHello方法做的事情是一样 那么我们其实只需要一个sayHello就满足了

构造函数的缺陷 就是里面声明的函数 会在每次new的时候重新开辟内存

解决方式 找一个共享的空间(对象)(只声明一次) 将这个函数放进去)

那么现在这个共享空间应该属于谁 构造函数

这个属于构造函数的空间就被称为原型

原型


prototype

概述:prototype是属于函数的一个空间,它是一个对象。因为构造函数也是函数所以它也具备。而这

个prototype属性我们称为显式原型。

函数的prototype

function fn(){

}

console.log(fn.prototype);

对应的这个prototype显示是一个对象,里面具备对应的属性及方法。主要为方法,那么也就是说这个prototype属性上一般存放对应的方法。

构造函数的prototype

function Person(){

}

console.log(Person.prototype);

//获取当前的构造函数

console.log(Person.prototype.constructor);

//将函数存储在原型上

Person.prototype.sayHello = ()=>{

console.log(this);

}

//新建对象

var person = new Person()

var person1 = new Person()

console.log(person == person1);//false

//person.sayHello ===> Person.prototype.sayHello

//对于prototype上存储的内容 通过实例对象.属性名访问

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

///对于prototype上存储的内容 通过实例对象.属性名访问

console.log(person.constructor);

从上可得构造函数的prototype是一个对象,第二个里面有个属性 constructor指向当前的构造函

数。

实例对象访问对于的prototype上的内容可以通过实例对象.属性名访问

一般将对应的函数存储在对应prototype上(这个函数只会声明一次)。将函数存储在原型,将属

性放在构造函数里面。

在prototype里面声明的函数的this指向当前的调用的实例对象

__proto__

概述:

__proto__ 称为隐式原型,它是属于对象的一个空间,每个对象都存在这个空间,那么对应的实例对

象也是一个对象,所以它也有这个空间。这个空间指向对应的构造函数的prototype。

var obj = new Object()

//每个对象都存在的一个空间 它指向对应的构造函数的prototype

console.log(obj.__proto__);

//对象的__proto__指向对应的构造函数的prototype

console.log(obj.__proto__ == Object.prototype);

function Person(){

}

var person = new Person()

console.log(person.__proto__ == Person.prototype);

// Person.prototype.sayHello = ()=>{

// }

person.__proto__.sayHello = ()=>{

console.log('hello');

}

person.sayHello()

__proto__ 的指向问题

__proto__ 指向对应的构造函数的prototype

构造函数也是一个对象 那么它的 __proto__ 指向谁 指向对应的父类的构造函数的prototype

Object的 __proto__ 指向null

//指向Person.prototype

console.log(person.__proto__);

//指向构造函数的原型的原型 构造函数的原型是啥 是一个对象 Object.prototype

console.log(person.__proto__.__proto__);

//指向构造函数的原型的原型 构造函数的原型是啥 是一个对象 Object.prototype 的__proto__是

null

console.log(person.__proto__.__proto__.__proto__);

原型链

概述:

对象在 __proto__ 上找属性的链式结构被称为原型链。

从上面的指向问题来看 对象在原型上找属性的过程为

先找自己的 __proto__ (对应的构造函数的prototype),

再找对应的自身构造函数的原型的 __proto__ 找到父类构造函数的原型

,再找对应的父类的原

型的 __proto__ ,直到找到object为止

Object的原型的 __proto__ (null)上还找不到返回undefined

Object.prototype.hello = '你好'

class Person{

constructor(){

this.name = '张三'

}

}

Person.prototype.sex = '女'

Person.prototype.username = 'rose'

//对象赋值 有就重新赋值 没有就添加属性赋值

Person.hi = '你好吗'

var person = new Person()

person.age =

'

109'

class Son extends Person{

constructor(){

super()

this.age = '李四'

}

}

Son.prototype.sex = '男'

//实例化对象

var son = new Son()

console.log(son.age);//李四

console.log(son.name);//张三

console.log(son.username);//rose

console.log(son.sex);//男

console.log(son.hello);//你好

console.log(son.hi);//undefined

注意事项

原型链不包含对象赋值

对象赋值的操作是找到这个属性了重新设置值

没有找到这个属性进行 添加这个属性进行赋值操作

总结

构造函数的原型prototype

实例对象的原型 __proto__

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

原型链通过对应的对象的 __proto__ 去找对应的属性 直到找到Object为止

原型一般上面写函数,可以保证函数只声明一次。对应的属性写在构造函数内。

原型上的方法/属性。通过实例对象.属性名直接访问(平常通过对象去点的方法都称为原型方法)

在对应的原型上的函数里面的this指向当前调用的实例对象

通过原型来实现数组的高阶函数

forEach实现 map实现

//数组的原型

//在数组的原型上添加一个myForEach的方法

//在对应的原型上的函数里面的this指向当前调用的实例对象

Array.prototype.myForEach = function(fn){

//遍历

for(let i=0;i<this.length;i++){

fn(this[i],i,this)

}

}

Array.prototype.myMap = function(fn){

let returnArr = []

//遍历

for(let i=0;i<this.length;i++){

returnArr.push(fn(this[i],i,this))

}

return returnArr

}

reduce实现

//回调函数 defaultValue初始值

Array.prototype.myReduce = function(fn,defaultValue){

//默认请求 前面的值为第一个开始下标为第二个

let previousValue = this[0]

let index = 1

//如果传了初始值 那么对应的初始值为传入的值 开始的下标从0开始

if(typeof defaultValue != 'undefined'){

previousValue = defaultValue

index = 0

}

//遍历

for(let i=index;i<this.length;i++){

previousValue = fn(previousValue,this[i],i,this)

}

return previousValue

}

面向对象的三大特性

封装 (函数的抽取 属性的抽取)

继承 (子类继承父类)

多态 (重写 子类重写父类方法)

继承

概述:

子类继承父类的属性和方法(非私有的属性和方法 非静态的方法)

继承的实现

使用extends关键词实现继承(es6新增 类的继承)

// es6新增类的继承 extends关键词实现

class Person{

constructor(){

this.name = 'jack'

}

}

class Son extends Person{

constructor(age){

super()

this.age = age

}

}

var son = new Son(18)

console.log(`son`, son);

原型链继承 (覆盖之前原型上的所有方法 显示的时候不会显示继承来的属性 (在原型上重复出现一样

的属性))

核心 在子类的原型上创建父类的对象

function Person(){

this.name = 'jack'

}

function Son(age){

this.age = age

}

Son.prototype.say = ()=>{

console.log(`你好`);

}

//原型继承

// 将要继承的类放在继承的子类的原型上

//原型链会覆盖原本原型上的私有的方法及属性

Son.prototype = new Person()

var son = new Son(18)

console.log(`son`, son);

console.log(son.name);

// son.say()

对象冒充 (会显示继承的属性 不能继承原型上的方法)

核心 在子类中调用父类的构造函数 更改this指向

function Person(){

this.name = 'jack'

}

function Son(age){

//改this指向 执行父类的构造函数

Person.call(this)

this.age = age

}

var son = new Son(18)

console.log(`son`, son);

组合继承 (使用原型链继承和对象冒充结合)

// 组合继承 原型链继承加对象冒充

function Person(){

this.name = 'jack'

}

Person.prototype.say = ()=>{

console.log(`hello`);

}

function Son(age){

//改this指向 执行父类的构造函数

Person.call(this)

this.age = age

}

//原型链继承

Son.prototype = new Person()

var son = new Son(18)

console.log(`son`, son);

son.say()

组合寄生继承 (对象冒充 + 原型链继承(创建一个原型对象放在原型链上))

对象冒充

在子类的原型上创建父类的原型对象

//组合寄生继承

function Person(){

this.name = 'jack'

}

Person.prototype.say = ()=>{

console.log(`hello`);

}

function Son(age){

//改this指向 执行父类的构造函数

Person.call(this)

this.age = age

}

//寄生

Son.prototype = Object.create(Person.prototype)

var son = new Son(18)

console.log(`son`, son);

轮播图面向对象

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<meta name=

"

viewport" content="width=device-width, initial-scale=1.0">

<title>Document</title>

<style>

*

{

margin: 0;

padding: 0;

}

.

showBox,

li {

width: 400px;

height: 250px;

}

li>img {

width: 100%;

}

.

showBox {

position: relative;

margin: 200px auto;

/* 溢出隐藏 */

overflow: hidden;

}

ul {

width: 800%;

position: relative;

}

ul>li {

list-style: none;

float: left;

}

.

cirList {

position: absolute;

right: 20px;

bottom: 10px;

width: 150px;

}

.

cirList>li {

width: 10px;

height: 10px;

background-color: #fff;

border-radius: 50%;

margin: 0 5px;

}

.

cirList .selected {

background-color: red;

}

.

arrow {

display: none;

}

.

arrow>a {

display: block;

width: 50px;

height: 50px;

position: absolute;

top: 50%;

margin-top: -25px;

}

.

arrow>.prev {

background: url(./images/prev.png) no-repeat center;

background-size: contain;

left: 0;

}

.

arrow>.next {

background: url(./images/next.png) no-repeat center;

background-size: contain;

right: 0;

}

</style>

</head>

<body>

<div class="showBox">

<ul class="nav">

<li><img src="./images/slidepic1.jpg" alt=""></li>

<li><img src="./images/slidepic2.jpg" alt=""></li>

<li><img src="./images/slidepic3.jpg" alt=""></li>

<li><img src="./images/slidepic4.jpg" alt=""></li>

<li><img src="./images/slidepic5.jpg" alt=""></li>

<li><img src="./images/slidepic6.jpg" alt=""></li>

<li><img src="./images/slidepic7.jpg" alt=""></li>

</ul>

<!-- 焦点 -->

<ul class="cirList">

</ul>

<div class="arrow">

<a href="" class="prev"></a>

<a href="" class="next"></a>

</div>

</div>

</body>

</html>

<script src='https://cdn.bootcdn.net/ajax/libs/move.js/0.5.0/move.js'></script>

<script>

//需要存储所有的图片的盒子 nav

// 焦点 左右切换的盒子

class Carousel {

constructor(box) {

this.box = box

//根据大盒子获取存储图片的盒子

this.nav = box.querySelector('.nav')

//根据大盒子获取存储焦点的盒子

this.cirList = box.querySelector('.cirList')

//控制的下标

this.index = 0

this.init()

this.handlerClick()

}

init() {

//根据对应的原本的图片个数

//将this.nav.children 当作数组调用forEach方法

Array.prototype.forEach.call(this.nav.children, (v, i) => {

let htmlCode = '<li></li>'

if(i == 0){

htmlCode = "<li class='selected'></li>"

}

//给对应的焦点进行添加

this.cirList.innerHTML += htmlCode

})

//生成焦点和在对应的nav后添加第一张图

var cloneNode = this.nav.children[0].cloneNode(true)

//加给最后

this.nav.appendChild(cloneNode)

}

move(direction = true) {

//区间判断

if (this.index < 1 && !direction) {

this.index = this.nav.children.length - 1

//切换位置

this.nav.style.transform = `translate3d(${this.index *

this.box.offsetWidth * -1}px, 0px, 0px)`

}

if (this.index > this.nav.children.length - 2 && direction) {

this.index = 0

this.nav.style.transform = 'translate3d(-0px, 0px, 0px)'

}

//反方向为false

if (direction) {

this.index++

} else {

this.index--

}

//移动

var x = this.index * this.box.offsetWidth * -1

this.focusElement(this.index)

move('.nav').to(x, 0).duration('1s').end()

}

autoMove() {

let

_

self = this

this.timer = setInterval(() => {

_

self.move(true)

}, 2000)

}

focusElement(index){

//取值为0-6

if(index==7){

index = 0

}

//排他思想

Array.prototype.forEach.call(this.cirList.children,(v,i)=>{

v.className = (i == index ? 'selected' : '')

})

}

handlerClick(){

var

_

self = this

Array.prototype.forEach.call(this.cirList.children,(v,i)=>{

let index = i

v.onclick = function(){

_

self.index = index-1

_

self.move()

}

})

}

}

var box = document.querySelector('.showBox')

var carousel = new Carousel(box)

carousel.autoMove()

</script>

ES6的模块化

模块的思想,将对应的功能代码封装为一个模块(js代码 css代码 html代码)。

想要使用别人就导入,想要给别人用就导出。复用。

模块化的常用的模式

amd (在对应的加载之前导入)

cmd (在用的时候导入)

comment.js (基于amd和cmd之上)

es6的模块化的关键词(要想导入想要导出)

import 导入

export 导出

export的使用

第一种 export default (只能声明一次)

// //默认导出只有一个 如果使用export default 导出的可以使用对应的一个名字来接

export default {

obj,

str,

say

}

接收

import obj from './test.js'

console.log(obj) //{obj,str,say}

第二种导出

//如果直接使用的对应的export 导出那么必须通过{键}来接

export const obj = {

name:

'

jack',

age:18

}

//如果导出的是值类型 一定要写变量名

export const str =

"

你好世界"

export const say = ()=>{

console.log('hello world');

}

接收

import {obj,str,say} from './test.js'

第三种导出

const name = 'tom'

//第三种导出

export {

//只能写变量

name

}

接收

import {name} from './test.js'

import使用

import 名字 from '地址'

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容