内容:

  • 创建对象的几种模式以及创建的过程
  • 原型链prototype的理解,以及prototype与 __proto__[[Prototype]])的关系
  • 继承的几种实现

1.常见模式与原型链的理解

a.构造函数创建

function Test() {
//
}

流程

  • 创建函数的时候会默认为Test创建一个prototype属性,Test.prototype包含一个指针指向的是Object.prototype
  • prototype默认会有一个constructor,且Test.prototype.constructor = Test
  • prototype里的其它方法都是从Object继承而来

示例
// 调用构造函数创建实例
var instance = new Test()

此处的instance包含了一个指针指向构造函数的原型,(此处的指针在chrome里叫__proto__,也等于[[Prototype]]

示例

b.原型模式
由上我们可以知道,默认创建的prototype属性只拥有constructor和继承至Object的属性,原型模式就是为prototype添加属性和方法

Test.prototype.getName = ()=> {
alert('name')
}

此时的instance实例就拥有了getName方法,因为实例的指针是指向Test.prototype的

instance.__proto__ === Test.prototype

如下图所示

897RVF]E5@IX$)`IVJ3BOSY.png

这里我们可得知:实例instance与构造函数之间是通过原型prototype来相关联的。

c.组合模式
这种模式我们用的最多,其实也是原型模式的另一种写法,只不过有一点小区别而已

function Test() {}

Test.prototype = {
getName() {
alert('name')
}
}

我们经常会这么直接重写prototype方法,由上我们可知,prototype会默认自带constructor属性指向构造函数本身,那么重写以后呢?

Test.prototype.constructor === Object
// 而并不等于Test了
// 因为重写以后相当于利用字面量方式创建一个实例对象,这个实例的构造函数是指向Object本身的

当然我们也可以手动赋值constructor

Test.prototype = {
constructor: Test,
getName() {
alert('name')
}
}

那么又会有疑问了constructor要不要有何意义?我觉得constructor意义仅仅是为了来鉴别原型所属的构造函数吧。

当需要获取某个属性的时候,会先从实例中查找,没有就根据指针所指向的原型去查找,依次向上,直到实例的指针__proto__指向为null时停止查找,例如:

// 1 读取name
instance.name // 2 instance.__proto__ === Test.prototype
Test.prototype.name // 3 Test.prototype.__proto__ === Object.prototype
Object.prototype.name // 4
Object.prototype.__proto__ === null

当找到了这个属性就会直接返回,而不会继续查找,即使这个属性值为null,想要继续查找,我们可以通过delete操作符来实现。

由这里我们自然可以想到Array, Date, Function, String,都是一个构造函数,他们的原型的指针都是指向Object.prototype,它们就像我这里定义的Test一样,只不过是原生自带而已

d.几个有用的方法

  • Object.getPrototypeOf() 获取某个实例的指针所指向的原型

    Object.getPrototypeOf(instance) === Test.prototype
  • hasOwnProperty 判断一个属性是存在于实例中还是存在于原型中,如图所示:

    NY~N}CNR`}8W%4QA$M8LFE4.png
  • in操作符,无论该属性是否可枚举
    'name' in instance  // true
    'getName' in instance // true

    无论属性是在实例中,还是在原型中都返回true,所以当我们需要判断一个属性存在与实例中,还是原型中有2种办法

    // 一种就是使用hasOwnProperty判断在实例中
    // 另一种判断在原型中
    instance.hasOwnProperty('getName') === false && 'getName' in instance === true
  • for ... in操作符也是一样的,但只会列出可枚举的属性,ie8版本的bug是无论该属性是否可枚举,都会列出

    D(%S__GN8404{H9X6PW$DVK.png

    name是在实例中定义的,getName是在原型中定义的

  • Object.keys()则不一样,它返回一个对象上所有可枚举的属性,仅仅是该实例中的

    Object.keys(instance)
    // ["name"]

e.总结
以上讨论了构造函数,原型和实例的关系:

  • 每个构造函数都有原型对象
  • 每个原型对象都有一个constructor指针指向构造函数
  • 每个实例都有一个__proto__指针指向原型

2.继承

继承的实质是利用构造函数的原型 = 某个构造函数的实例,以此来形成原型链。例如

// 定义父类
function Parent() {}
Parent.prototype.getName = ()=> {
console.log('parent')
}
// 实例化父类
let parent = new Parent() // 定义子类
function Child() {}
Child.prototype = parent
// 实例化子类
let child = new Child() child.getName() // parent
// 此时
child.constructor === parent.constructor === Parent

a.最经典的继承模式

function Parent(name) {
this.name = name
this.colors = ['red']
}
Parent.prototype.getName = function() {
console.log(this.name)
}
// 实例化父类
let parent = new Parent() function Child(age, name) {
Parent.call(this, name)
this.age = age
}
Child.prototype = parent
// 实例化子类
let child = new Child(1, 'aaa')
child.getName() // parent

这里会让我想到ES6中的class继承

class Parent {
constructor(name) {
this.name = name
this.colors = ['red']
}
getName() {
console.log(this.name)
}
} class Child extends Parent {
constructor(age, name) {
super(name)
}
} let child = new Child(1, 'aaa')
child.getName() // parent

其实是一个道理,这里我们不难想到,将Child.prototype指向parent实例,就是利用原型实现的继承,而为了每个实例都拥有各自的colors和name,也就是基础属性,在Child的构造函数中call调用了Parent的构造函数,相当于每次实例化的时候都初始化一遍colors和name,而不是所有实例共享原型链中的colors和name

学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入学习交流群
343599877,我们一起学前端!

JavaScript原型与继承(1)的更多相关文章

  1. 深入理解:JavaScript原型与继承

    深入理解:JavaScript原型与继承 看过不少书籍,不少文章,对于原型与继承的说明基本上让人不明觉厉,特别是对于习惯了面向对象编程的人来说更难理解,这里我就给大家说说我的理解. 首先JavaScr ...

  2. JavaScript原型与继承

    JavaScript原型与继承 原型 在JavaScript中,每个函数都有一个prototype属性,这个属性是一个指针,指向该函数的原型对象.这个原型对象为所有该实例所共享.在默认情况下,原型对象 ...

  3. JavaScript原型与继承的秘密

    在GitHub上看到的关于JavaScript原型与继承的讲解,感觉很有用,为方便以后阅读,copy到自己的随笔中. 原文地址:https://github.com/dreamapplehappy/b ...

  4. JavaScript 原型与继承

    JavaScript 原型与继承 JavaScript 中函数原型是实现继承的基础.prototype.construct.原型链以及基于原型链的继承是面向对象的重要内容 prototype 原型即 ...

  5. javascript原型链继承

    一.关于javascript原型的基本概念: prototype属性:每个函数都一个prototype属性,这个属性指向函数的原型对象.原型对象主要用于共享实例中所包含的的属性和方法. constru ...

  6. JavaScript 原型与继承机制详解

    引言 初识 JavaScript 对象的时候,我以为 JS 是没有继承这种说法的,虽说 JS 是一门面向对象语言,可是面向对象的一些特性在 JS 中并不存在(比如多态,不过严格来说也没有继承).这就困 ...

  7. 8条规则图解JavaScript原型链继承原理

    原形链是JS难点之一,而且很多书都喜欢用一大堆的文字解释给你听什么什么是原型链,就算有图配上讲解,有的图也是点到为止,很难让人不产生疑惑. 我们先来看一段程序,友情提示sublimeText看更爽: ...

  8. 【Javascript】Javascript原型与继承

    一切都是对象! 以下的四种(undefined, number, string, boolean)属于简单的值类型,不是对象.剩下的几种情况——函数.数组.对象.null.new Number(10) ...

  9. 【前端知识体系-JS相关】深入理解JavaScript原型(继承)和原型链

    1. Javascript继承 1.1 原型链继承 function Parent() { this.name = 'zhangsan'; this.children = ['A', 'B', 'C' ...

  10. JavaScript原型及继承

    一.浅谈原型 首先我们要知道创建对象的方法有两种: 1.通过字面量的方式直接创建 var obj = { name:'baimao', age:21 } 2.通过构造函数创建对象 function P ...

随机推荐

  1. Go语言【第四篇】:Go运算符

    Go语言运算符 运算符用于在程序运行时执行数据或逻辑运算,Go语言内置的运算符有: 算数运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 算数运算符 下表列出了所有Go语言的算数运算符 ...

  2. 【刷题】洛谷 P3804 【模板】后缀自动机

    题目描述 给定一个只包含小写字母的字符串 \(S\) , 请你求出 \(S\) 的所有出现次数不为 \(1\) 的子串的出现次数乘上该子串长度的最大值. 输入输出格式 输入格式: 一行一个仅包含小写字 ...

  3. POJ2352:Stars——题解

    http://poj.org/problem?id=2352 Astronomers晚上仰望星空,看到了很多星星.回到办公桌,Astronomers将这些星星画到二维坐标系,每个星星的坐标都是整数.例 ...

  4. ZOJ3229:Shoot the Bullet——题解

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3229 题目大意:射命丸文要给幻想乡的居民照相,共照n天m个人,每天射命丸文 ...

  5. [bzoj] 1040 骑士 || 基环外向树dp

    原题 给出n个点n条边和每个点的点权,一条边的两个断点不能同时选择,问最大可以选多少. //图是一张基环外向树森林 是不是很像舞会啊- 就是多了一条边. 所以我们考虑一下对于一棵基环外向树,拆掉一条在 ...

  6. ZOJ3874 Permutation Graph 【分治NTT】

    题目链接 ZOJ3874 题意简述: 在一个序列中,两点间如果有边,当且仅当两点为逆序对 给定一个序列的联通情况,求方案数对\(786433\)取模 题解 自己弄了一个晚上终于弄出来了 首先\(yy\ ...

  7. UVA.10066 The Twin Towers (DP LCS)

    UVA.10066 The Twin Towers (DP LCS) 题意分析 有2座塔,分别由不同长度的石块组成.现在要求移走一些石块,使得这2座塔的高度相同,求高度最大是多少. 问题的实质可以转化 ...

  8. IDEA_MyBatis_SQLException:Parameter index out of range坑

    报错信息:超出数据库数据表设定的规定长度了 nested exception is org.apache.ibatis.type.TypeException: Could not set parame ...

  9. mysql语句进阶

    1.null mysql> create table worker(id int not null,name varchar(8) not null,pass varchar(20) not n ...

  10. SCU 4527 NightMare2 最短路+二分 好题

    可怜的又做噩梦了..但是这次跟上次不大一样,虽然他又被困在迷宫里,又被装上了一个定时炸弹,但是值得高兴的是,他发现他身边有数不清的财宝,所以他如果能带着这些财宝并活着逃出去的话,他就发财啦.不过,这次 ...