【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使用原型链这种机制来实现动态代理. ...
随机推荐
- navicat premium 15 下载和激活
Navicat Premium 15 下载地址 链接:https://pan.baidu.com/s/1bL-M3-hkEa4M-547giVjYQ?pwd=1107 推荐安装参考地址:https:/ ...
- Linux之SELinux
1.什么是SELinux? 安全增强型 Linux(Security-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统. SELi ...
- golang errgroup 的超时检测
errgroup 的超时检测通常是一种事后得到结果的方式. errgroup本身并不直接支持超时控制,而是依赖于与之关联的context.Context来实现超时和取消功能. 当context超时时, ...
- 基于React的SSG静态站点渲染方案
基于React的SSG静态站点渲染方案 静态站点生成SSG - Static Site Generation是一种在构建时生成静态HTML等文件资源的方法,其可以完全不需要服务端的运行,通过预先生成静 ...
- k8s——deployment
创建deployment [root@master deploy]# kubectl create deploy nginx-deploy --image=nginx:1.7.9 deployment ...
- 震惊!docker镜像还有这些知识,你都知道吗?----镜像(二)
镜像查看 查看镜像 [root@hmm-docker ~]# docker images REPOSITORY#镜像仓库 TAG #标签 IMAGE ID#镜像id CREATED #创建时间 SIZ ...
- redhat8连接xshell命令卡顿
取消下方 转发x11连接到(X) 再重新连接一遍 就好了
- nodejs加jq来实现下载word文档
先看效果 浏览器上: 下载的效果: 第一步是自己先搭建前端页面把自己写的结构数据全部传到后端 下面就是整个的结构 结构分析后端拿到数据后端解析: 第一层菜单层: { role: '分析报告', //顶 ...
- JS获取表单所有内容
var formData = {}; var t = $('#Form').serializeArray(); $.each(t, function() { formData[this.name] = ...
- Scrapy爬取知名技术文章网站
scrapy安装以及目录结构介绍 创建有python3的虚拟环境 mkvirtualenv mkvirtualenv py3env 安装scrapy 进入虚拟环境py3env,把pip的源设置为豆瓣源 ...