0

0

常见模式与原型链的理解

PHP中文网

PHP中文网

发布时间:2017-06-20 09:37:30

|

1985人浏览过

|

来源于php中文网

原创

内容:

  • 创建对象的几种模式以及创建的过程

  • 原型链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 读取nameinstance.name 

// 2 instance.__proto__ === Test.prototypeTest.prototype.name

// 3 Test.prototype.__proto__ === Object.prototypeObject.prototype.name

// 4Object.prototype.__proto__ === null

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

贞龙网店商城电子商务系统java版
贞龙网店商城电子商务系统java版

BIZOSS-B2C是脱胎于贞龙B2B大型平台的网上商城系统、网上商店系统、网上购物系统的企业级B2C电子商务解决方案。系统设置:这里包含了网店的常用功能和全局配置的开关。包括 商店设置 、支付方式和配送方式 、邮件服务器设置、地区列表、友情链接、自定义导航栏、站点地图。商品管理:网店展示商品的核心。其中包括了 商品分类、商品类型、商品品牌、商品回收站、商品上下架等一些设置。促销管理:这个是我们网

下载

由这里我们自然可以想到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.继承

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

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

// 定义父类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 = namethis.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 = namethis.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

相关专题

更多
c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

57

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

57

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

237

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

393

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

17

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

103

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

73

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

81

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

70

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.1万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.4万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号