【JavaScript高级02】JavaScript第一大神兽:原型和原型链
1,函数中的prototype属性
每个函数都会有一个属性prototy,该属性默认指向一个空Object对象,而这个空的Object对象被称之为原型对象。
<script >
console.log(typeof Date.prototype);
</script>
打印结果:
会发现,Date的prototype中定义了很多的空方法,用于表示Date的结构,该Object并不是一个空的,使用es定义的,这也说明了,在默认情况指向一个空的原型对象。该情况如下所示:
<script >
function fun(){}
console.log(fun.prototype,typeof fun.prototype);
</script>
打印结果为:
会发现,在这个fun函数中的Object原型对象中,只有两个属性,该两个属性为系统定义的,之后并无其他属性。可以看做是一个空的Object对象。该原型对象有一个属性constructor,指向它的函数对象。还有一个属性叫做__proto__,这个属性后面细说。向看看原型对象的的constructor属性是否指向函数对象。
<script >
function fun(){}
console.log(fun.prototype.constructor===fun,Date.prototype.constructor===Date);
</script>
打印结果为:
结果都为true,表示是对的。
综合上述可以得出:一个函数都会有一个prototype对象,该对象默认指向一个空Object对象,称其为原型对象。在系统(js)定义的函数中,指向的原型对象不是空的,而是定义了很多的空方法,表示该函数的结构。在原型对象中有个属性为constructor,该属性指向其函数,示例图如下所示。
我们可以在原型对象中添加属性,一般情况我们只添加方法(变量也可以添加)。
<script >
function Fun(){}
fun.prototype.text=function(){
console.log("ha")
}
var f=new Fun()
f.text()
</script>
2,显示原型属性和隐示原型属性
先给出定义:
每个函数function都有一个prototype,即显式原型属性。
每个实例对象都有一个__proto__,可称为隐式原型属性。
显式原型属性和隐式原型属性的关系为:对象的隐式原型的值为其对应构造函数的显式原型的值。
显式原型属性就不说了,上面讲的和详细了,那就讲讲隐式原型属性吧。
__proto__隐式原型属性实在对象被创建时才被添加,其值为其对应构造函数的显式原型的值。其指向和显式原型属性一样。默认指向一个空Object对象。
<script >
function Fun(){}
var f=new Fun();//隐含了this.__proto__=Fun.prototype
console.log(f.__proto__===Fun.prototype)
</script>
打印结果为true。在来一段代码,以此代码来画出内存示意图:
<script >
function Fun(){}
Fun.prototype.text=function(){
}//隐含this.prototype={}
console.log(Fun.prototype)
var f=new Fun();//隐含this.__proto__=Fun.prototype
console.log(f.__proto__===Fun.prototype)
console.log(f.__proto__)
f.text()
</script>
内存示意图:
3,原型链
先来一段代码:
function Fn() {
this.test1 = function () {
console.log('test1()')
}
}
console.log(Fn.prototype)
Fn.prototype.test2 = function () {
console.log('test2()')
}
var fn = new Fn()
fn.test1()
fn.test2()
console.log(fn.toString())
console.log(fn.test3)
运行结果为:
前面的输出结果在意料之中,我们在函数和原型中添加了方法,在调用之后,输出了test1()和test2()。当时函数中没有toString和test3,但是调用的时候,确输出了不同的结果,一个是输出[object Object],另一个输出undefined,是什么导致这个结果?这个就得引出一个知识点:原型链。
代码的内存示例图:
第一步:首先,Fn保存了Fn函数对象的地址值,Fn函数对象在堆内存中有块内存空间,Fn指向该内存空间。Fn函数对象有个属性prototype(显示原型),该属性指向一个原型对象(空Object对象)。
第二步:有个全局作用域对象Object在页面加载的时候也会被创建,指向Object的函数对象,Object的显式原型属性会指向其原型对象。
第三步:由于Object的原型对象的存在,空Object对象的隐式原型属性会指向Object的原型对象(对象的隐式原型的值为其对应构造函数的显式原型的值)。Object的原型对象会有个隐式原型属性,其值为null,表示原型链的尽头。
第四步:创建fn实例 对象,会在内存中开辟一个内存空间用来存放Fn的实例对象,函数的实例对象会有个隐式原型属性指向其构造函数的原型对象(对象的隐式原型的值为其对应构造函数的显式原型的值)。
第五步:添加函数,Fn添加函数是在其原型中添加,fn则是在实例函数中添加,查找是,查找test1会沿着内存为0x567这条查找,在其函数实例总找到并打印。查找test2时,会沿着内存为0x123这条找,最终在其原型对象中找到。查找toString时,在原型对象找不到,回到Object的原型对象查找,找到后打印。查找test3时,在原型链的尽头都没有,会放反回一个undefined。
总结为:
访问一个对象的属性时,先在自身属性中查找,找到返回,如果没有, 再沿着__proto__这条链向上查找, 找到返回,如果最终没找到, 返回undefined。可以看出,整条链是沿着隐式原型属性查找,所以也被称之为 隐式原型链。
注意:
a,函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true
b, 所有函数都是Function的实例(包含Function)
console.log(Function.__proto__===Function.prototype)
c, Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) // null
4,原型链的属性问题
读取对象的属性值时: 会自动到原型链中查找。
设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值。
方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上。
无论对象创建多少次,其实例对象的隐式原型属性都不变。
function Fn() {}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a, fn1)
var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a, fn2.a, fn2)
Person.prototype.setName = function (name) {
this.name = name
}
var p1 = new Person('Tom', 12)
p1.setName('Bob')
console.log(p1)
var p2 = new Person('Jack', 12)
p2.setName('Cat')
console.log(p2)
console.log(p1.__proto__===p2.__proto__) // true
5,instanceof的实现原理:利用原型链
表达式: A instanceof B
如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false。其中A是一个实例对象,B是一个构造函数对象。
/*
案例1
*/
function Foo() { }
var f1 = new Foo()
console.log(f1 instanceof Foo) // true
console.log(f1 instanceof Object) // true
/*
案例2
*/
console.log(Object instanceof Function) // true
console.log(Object instanceof Object) // true
console.log(Function instanceof Function) // true
console.log(Function instanceof Object) // true
function Foo() {}
console.log(Object instanceof Foo) // false
【JavaScript高级02】JavaScript第一大神兽:原型和原型链的更多相关文章
- JavaScript高级程序设计:第一章
JavaScript简介: 1.JavaScript实现应该由以下三部分组成: (1)核心:ECMAScript (2)文档对象模型:DOM (3)浏览器对象模型:BOM 2.什么是ECMAScrip ...
- Javascript高级编程学习笔记(21)—— 对象原型
JS中对象相关的最重要的恐怕就是原型链了 原型链也是JS中对象继承的实现的基础 接昨天的文章,我们使用构造函数创建对象的时候仍然存在一些问题 那就是所有的实例没法共用一个函数 这样无疑会造成极大的内存 ...
- javaScript系列 [02]-javaScript对象探析
[02]-javaScript对象探析 题记:多年前,以非常偶然的方式关注了微信公众号“面向对象”,本以为这个公众号主要以分享面向对象编程的干货为主,不料其乃实实在在的猿圈相亲平台.通过查看公开资料, ...
- 《JAVASCRIPT高级程序设计》第一章
在使用调制解调器的时代,频繁的表单验证对客户端来说是一个很大的负担,javascript,作为一种专门进行表单验证的客户端脚本语言诞生了.到今天,javascript早已超越了当初设定的角色.Java ...
- 《JavaScript 高级程序设计》第一章:简介
JavaScript 历史 JavaScript的诞生的主要是当时的 netspace 公司谋求为自己的浏览器 Navigator 添加一种脚本语言,以便在本地客户端进行一些行为操作,而这一功能的需求 ...
- 《JavaScript高级程序设计》——第一章JavaScript简介
第一章主要讲了JavaScript的诞生和发展.刚刚接触JavaScript的我,似乎对这些内容并不感兴趣,快速看了一遍就开始去看第二章了. 看完第一章,收获也就是了解到JavaScript由ECMA ...
- Javascript高级程序设计——javascript简介
1.Javascript简史 javascript诞生于1995年,是由网景公司的Brendan Eich开发的,最初的目的是在客户端处理一些输入验证操作,自此后成为常见浏览器的特色功能,如今用途已经 ...
- Javascript高级程序设计——Javascript简史+使用Javascript
一.Javascipt简史 1.了解Javascript历史 Netscape(Javascript1.0).Microsoft(JScript)到JS1.1,再到ECMA-262标准 2.知道ECM ...
- javaScript基础-02 javascript表达式和运算符
一.原始表达式 原始表达式是表达式的最小单位,不再包含其他表达式,包含常量,直接量,关键字和变量. 二.对象和数组的初始化表达式 对象和数组初始化表达式实际上是一个新创建的对象和数组. 三.函数表达式 ...
- javaScript系列 [03]-javaScript原型对象
[03]-javaScript原型对象 引用: javaScript是一门基于原型的语言,它允许对象通过原型链引用另一个对象来构建对象中的复杂性,JavaScript使用原型链这种机制来实现动态代理. ...
随机推荐
- vue我自己的动态菜单思路
1.在router里把所有的路由都加上. 2.后端存储路由path和其他设计需要的信息. 3.登录后,后端返回菜单树,根据权限不同,返回的菜单不同,并且还要返回每个path代表的页面具有的权限数组.可 ...
- 【C#】 封装的异步HttpRequest
private async void btn_userLogin_Click(object sender, EventArgs e) { UInfo = new ...
- win11如何调解屏幕亮度【win10刚刚升级win11】?
打开电脑后鼠标右键,点击个性化 点击系统 点击屏幕亮度 滑动按钮,调解屏幕亮度即可
- RocketMQ主从同步原理
一. 主从同步概述 主从同步这个概念相信大家在平时的工作中,多少都会听到.其目的主要是用于做一备份类操作,以及一些读写分离场景.比如我们常用的关系型数据库mysql,就有主从同步功能在. 主从同步,就 ...
- 部署Zabbix
https://blog.csdn.net/qq_57414752/article/details/125819822
- CSS——样式继承
CSS的样式表继承指的是,特定的CSS属性向下传递到子孙元素.总的来说,一个HTML文档就是一个家族,然后html元素有两个子元素,相当于它的儿子,分别是head和body,然后body和head各自 ...
- WPF 实现触摸滑动功能
自定义ScrollViewer的Touch事件--触摸上下移动ScrollViewer滚动到指定位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...
- 关于ThreadLocal最直白的解释
ThreadLocal 底层原理如下: 实线是强引用,虚线是弱引用 Thread 持有 ThreadLocal 对象的引用,ThreadLocalMap 是 Thread 的成员变量,它是一个 Map ...
- mysql通过binlog来恢复被删除的数据库
binlog日志 查询: MariaDB [(none)]> show variables like 'log_bin'; +---------------+-------+ | Variabl ...
- ros2 foxy订阅话题问题
代码片段 这部分代码在galactic版本编译是OK的,可在foxy下编译就出了问题 TeleopPanel::TeleopPanel(QWidget* parent) : rviz_common:: ...