深刻浅出面向对象和原型【概念篇2】

墙裂建议您在看这篇文章以前阅读一遍我以前写的文章 深刻浅出面向对象和原型【概念篇1】,由于此篇文章涉及到很多相关概念都在上篇文章里啦

1.1 简单复习对象

对象是老生常谈的概念了,在这里咱们来简单复习一下segmentfault

var obj = {
        a: 1, 
        b: "hello",
        c: true,
        d: function () {
            console.log("hello")
        },
        e: {
            e_1: "对象内储存一个对象"
        }
    }

对象是一个储存一系列无序 key: value【键值对】 的集合的容器函数

注意:核心是要将对象做为一个容器看待

使用对象做为容器的这个特性咱们能够进行封装,这会产生两个好处this

  1. 让咱们的代码变得优雅、易读
  2. 规避全局变量

1.2 经过构造函数建立对象

1.2.1 关于function的额外知识

  1. function做为构造函数(经过new操做符调用)的时候会 返回 一个类型为function的对象
  2. function能够接受参数,能够根据参数来建立 相同类型不一样值 的对象
  3. function实例做用域内有一个constructor属性,这个属性就能够指示其构造器

1.2.2 学会使用 new Function

new 运算符接受一个函数 F 及其参数:new F(arguments...)spa

  1. 建立类的实例——这步是把一个空的对象的__proto__属性设置为 F.prototype
  2. 初始化实例——函数 F 被传入参数并调用,关键字 this 被设定为该实例
  3. 返回实例
function People(name) {
        this.name = name
        this.sayName = function () {
            console.log(name)
        }
        // 通常在这个函数里不要 return
        // 若是return引用类型的话,等于把return的值赋值给p1
    }

    People() // this指向全局变量,name和sayName成为了全局变量的属性

    var p1 = new People('sad')
    // 第一步:instance = {} 建立了一个类的实例 —— 空对象,而且将空的对象的__proto__属性设置为 F.prototype,也就是说
    // 第二步:执行函数People(),并传入参数"sad",并将this指向p1
    // 第三步:return instance【实例】 , 即把instance赋值给p1

    // 请注意 People()是一个函数,new People()是构造函数

    var p2 = new People('angry')

1.2.3 instanceof

instance 的中文意思为 实例
那么 instanceof 天然就是用来判断对象是否为某个类型的实例prototype

console.log(p1 instanceof People) // true
    // 意思是判断 对象(p1)是否为某个类型(People)的实例
    // p1 是由 People 构建出来的,天然是People的实例,返回为true

但须要注意的是,instanceof 运算符的工做原理是检测 类的prototype 是否存在实例的原型链上3d

console.log(p1 instanceof Object) // true
    // 由于Object.prototype能够被实例p1以原型链的方式访问到

1.2.4 构造函数存在的问题

构造函数在解决了上面全部问题,同时为实例带来了类型
但能够注意到在上例中,每一个的实例的方法做用是同样的
可是每一个实例被建立的时候都要从新声明一遍,浪费了内存code

// 咱们再来看一下这个函数
    function People(name) {
        this.name = name
        this.sayName = function () {
            console.log(name)
        } // 每一个实例的sayName方法倒是相同的,并且每出现一个新实例,都是新声明一个函数,大大地浪费了内存
    }

能不能给People的实例都使用同一个sayName方法呢对象

1.3 构造函数&原型&原型链

1.3.1 构造函数

任何函数使用new表达式就是构造函数,也就是说这个函数成为了一个类blog

1.3.2 用原型链解决重复建立的问题

  1. 每一个对象都会自带一个名称为prototype的属性
  2. prototype属性是一个对象
// 仍是这个例子
    function People(name) {
        this.name = name
        this.sayName = function () {
            console.log(name)
        } 
    }
    var p1 = new People('sad')
    var p2 = new People('angry')
    
    // People自己就有prototype属性
    console.log(People.prototype) // {constructor: ƒ} 

    // 而每一个对象也都会带有一个__proto__属性,指向这个构造函数【实例】的类
    // 全部的实例都共用一个prototype
    console.log(p1.__proto__ === People.prototype) // true
    console.log(p2.__proto__ === People.prototype) // true
// 实例能够经过__prop__访问到其 类 的prototype属性,这就意味着类的prototype对象能够做为一个公共容器,供全部实例访问。
    People.prototype.test = "abc"
    console.log(p1.test) // abc

    // p1这个对象没有test属性,可是能够经过它的__proto__属性访问到People的prototype属性
上述关系咱们用一张图来帮助你们更好地理解

clipboard.png

1.3.3 解决内存浪费问题

由上咱们能够知道ip

  1. 全部实例都会经过原型链引用到其类的prototype
  2. prototype至关于全部实例均可以访问到的一个公共容器,这个公共容器也是这些实例的类的属性

    那么如何解决内存浪费问题呢?

    Answer:重复的东西移动到公共容器里就能够了

function People(name) {
        this.name = name // 每一个对象的name属性时不一样的,这点无可厚非
    }

    People.prototype.sayName = function () {
        console.log(this.name)
    } // 将sayName方法放入People的原型中

    var p1 = new People('sad')
    var p2 = new People('angry')
    console.log(p1.sayName())
    console.log(p2.sayName())
相关文章
相关标签/搜索