JS-理解原型与原型链

构造函数

构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。另外就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用

    function Person(name, age, gender) {
        this.name = name
        this.age = age
        this.gender = gender
        this.sayName = function () {
            alert(this.name);
        }
    }
    var per = new Person("孙悟空", 18, "男");
    function Dog(name, age, gender) {
        this.name = name
        this.age = age
        this.gender = gender
    }
    var dog = new Dog("旺财", 4, "雄")
    console.log(per);//当我们直接在页面中打印一个对象时,事件上是输出的对象的toString()方法的返回值
    console.log(dog);

每创建一个Person构造函数,在Person构造函数中,为每一个对象都添加了一个sayName方法,也就是说构造函数每执行一次就会创建一个新的sayName方法。这样就导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个新的方法,而10000个方法都是一摸一样的,为什么不把这个方法单独放到一个地方,并让所有的实例都可以访问到呢?这就需要原型(prototype)


原型

在JavaScript中,每当定义一个函数数据类型 (普通函数、类)时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。
image.png

原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。

 function Person(name,age){
            this.name=name
            this.age=age
            this.sayName = function () {
                alert(this.name);
            }
        }

改造下

 function Person(name,age){
            this.name=name
            this.age=age
        }
 
        Person.prototype.year=2021   // 往原型上添加一点东西
        Person.prototype.sayName =function(){
            alert(this.name);
        }
        const personA=new Person()
        const personB=new Person()
        console.log('personA',personA , personB)
        console.log(personA.hasOwnProperty('year'), 'year' in personA ) // false true
        console.log(personB.hasOwnProperty('year'), 'year' in personB) // false true
        // hasOwnProperty只会从实例本身上找属性, in会从实例所属类的原型身上找
        console.log('personA.year',personA.year , personB.year )  // 2021 2021

原型的作用:
1:实现对象之间的数据共享。
2.在es6之前,没有class的情况下,模拟面向对象,构造函数中放私有属性,原型上放公有属性,一般放方法。

通过原型添加的方法,可以完美的解决属性与方法共享问题,从而节省了内存空间..


原型链

每一个对象数据类型(普通的对象、实例、prototype......)也天生自带一个属性__proto__,这个属性的值是当前实例所属类的原型对象(prototype)。
原型对象中有一个属性constructor, 它指向构造函数。

image.png
    function Person() {}   // 构造函数
    var person = new Person()  // 实例person
    console.log(person.__proto__ === Person.prototype)  // true
    console.log(Person.prototype.constructor===Person)  // true

    //顺便学习一个ES5的方法,可以获得对象的原型
    console.log(Object.getPrototypeOf(person) === Person.prototype)   // true

js实例对象的原型属性__proto__的属性值,指向这个实例对象所属类的原型

例如 new Array 出来的数组,属于Array这个类

const xArray=new Array()

那么

xArray.__proto__ === Array.prototype  // true

Array.prototype拥有的方法,array的每一个实例都会有,直接通过xArray.push()这样调用,而不需要xArray._ proto _.push,不需要这样去调用。

 Array.prototype.__proto__ === Object.prototype  // true
Object.prototype._proto_  // null

所谓原型链,指的就是这一条指针链!

原型链的顶层就是Object.prototype,而Object的原型对象的是没有原型属性的。 Object.prototype._proto_ ===null


何为原型链

在JavaScript中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。

举例说明:person → Person → Object ,普通人继承人类,人类继承对象类

当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。如果没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined。

我们可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性;使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true

function Person() {}
    Person.prototype.a = 123;
    Person.prototype.sayHello = function () {
      alert("hello");
 };
    var person = new Person()
    console.log(person.a)//123
    console.log(person.hasOwnProperty('a'));//false
    console.log('a'in person)//true

person实例中没有a这个属性,从 person 对象中找不到 a 属性就会从 person 的原型也就是 person.__proto__,也就是 Person.prototype中查找,很幸运地得到a的值为123。那假如 person.__proto__中也没有该属性,又该如何查找?

当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层Object为止。Object是JS中所有对象数据类型的基类(最顶层的类),在Object.prototype上没有__proto__这个属性。

console.log(Object.prototype.__proto__ === null) // true
image.png

所谓原型链,指的就是图中的proto这一条指针链!

原型链的顶层就是Object.prototype,而Object的原型对象的是没有原型属性的。

先找自身,找不到就沿着__proto__一直往上找原型,直到找到最顶层的类Object,Object类没有原型了,如果还找不到就返回undefined



实战:用ES6的class定义一套对象/函数

ES6提供了class,但是这个并不是类,而是 Function 的语法糖。
目的是简化ES5里面,为了实现继承而采用的各种“神操作”。

用class来定义,结构和关系会非常清晰,再也不会看着头疼了,建议新手可以跳过ES5的实现方式,直接用ES6的方式。

我们先定义一个Base,然后定义一个Person继承Base,再定义一个Man继承Person。
也就是说,可以深层继承。

class Base {
  constructor (title) {
    this.title = '测试一下基类:' + title
  }

  baseFun1(info) {
    console.log('\n这是base的函数一,参数:', info, '\nthis:', this)
  }
}

class Person extends Base{
  constructor (title, age) {
    super(title)
    this.title = '人类:' + title
    this.age = age
  }

  personFun1(info) {
    console.log('\n这是base的函数一,参数:', info, '\nthis:', this)
  }
}


class Man extends Person {
  constructor (title, age, date) {
    super(title, age)
    this.title = '男人:' + title
    this.birthday = date
  }

  manFun3 (msg) {
    console.log('jim 的 this ===', this, msg)
  }
}

  • 构造函数 constructor
    打印结果很清晰的表达了,构造函数就是我们定义的class。

  • 属性
    属性比较简单,统统都挂在 this 上面,而且是同一个级别。

  • 函数
    函数就有点复杂了,首先函数是分级别的,挂在每一级的原型上面

  • 原型链
    Man的实例 > Man的原型 > Person的原型 > Base 的原型 > Object 的原型。
    通过 __proto__ 连接了起来。

    image.png

Man的实例 man1,可以通过这个“链条”,找到 baseFun1,
直接用 man1.baseFun1() 即可(✔),
而不需要使用__proto__
man1.__ proto__.__ proto__.__ proto__.baseFun1() (✘)

man1.__ proto__ === Man.prototype
Man.prototype .__proto__ === Person.prototype
Person.prototype .__proto__ === Base.prototype
Base.prototype .__proto__ === Object.prototype
Object.prototype .__proto__ === null

image.png

Object是js顶层类,原型链的顶端也就是Object.prototype ,Object.prototype没有__proto__属性




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

推荐阅读更多精彩内容