一文读懂JS中的原型和原型链(图解)
讲原型的时候,我们应该先要记住以下几个要点,这几个要点是理解原型的关键:
1、所有的引用类型(数组、函数、对象)可以自由扩展属性(除null以外)。
2、所有的引用类型都有一个’_ _ proto_ _'属性(也叫隐式原型,它是一个普通的对象)。
3、所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象)。
4、所有引用类型,它的’_ _ proto_ _'属性指向它的构造函数的’prototype’属性。
5、当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。
那么要点说完了,我们就根据这些要点来理解原型和原型链。
原型
我们先来看一个原型的例子。
//这是一个构造函数
function Foo(name,age){
this.name=name;
this.age=age;
}
/*根据要点3,所有的函数都有一个prototype属性,这个属性是一个对象
再根据要点1,所有的对象可以自由扩展属性
于是就有了以下写法*/
Foo.prototype={
// prototype对象里面又有其他的属性
showName:function(){
console.log("I'm "+this.name);//this是什么要看执行的时候谁调用了这个函数
},
showAge:function(){
console.log("And I'm "+this.age);//this是什么要看执行的时候谁调用了这个函数
}
}
var fn=new Foo('小明',19)
/*当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它
构造函数的'prototype'属性中去找*/
fn.showName(); //I'm 小明
fn.showAge(); //And I'm 19
这就是原型,很好理解。那为什么要使用原型呢?
试想如果我们要通过Foo()来创建很多很多个对象,如果我们是这样子写的话:
function Foo(name,age){
this.name=name;
this.age=age;
this.showName=function(){
console.log("I'm "+this.name);
}
this.showAge=function(){
console.log("And I'm "+this.age);
}
}
那么我们创建出来的每一个对象,里面都有showName和showAge方法,这样就会占用很多的资源。
而通过原型来实现的话,只需要在构造函数里面给属性赋值,而把方法写在Foo.prototype属性(这个属性是唯一的)里面。这样每个对象都可以使用prototype属性里面的showName、showAge方法,并且节省了不少的资源。
原型链
理解了原型,那么原型链就更好理解了。
#####下面这段话可以帮助理解原型链
根据要点5,当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的’prototype’属性中去寻找。那又因为’prototype’属性是一个对象,所以它也有一个’_ _ proto_ _'属性。
那么我们来看一个例子:
// 构造函数
function Foo(name,age){
this.name=name;
this.age=age;
}
Object.prototype.toString=function(){
//this是什么要看执行的时候谁调用了这个函数。
console.log("I'm "+this.name+" And I'm "+this.age);
}
var fn=new Foo('小明',19);
fn.toString(); //I'm 小明 And I'm 19
console.log(fn.toString===Foo.prototype.__proto__.toString); //true
console.log(fn.__proto__ ===Foo.prototype)//true
console.log(Foo.prototype.__proto__===Object.prototype)//true
console.log(Object.prototype.__proto__===null)//true
是不是觉得有点奇怪?我们来分析一下。
首先,fn的构造函数是Foo()。所以:
fn._ _ proto _ _=== Foo.prototype
又因为Foo.prototype是一个普通的对象,它的构造函数是Object,所以:
Foo.prototype._ _ proto _ _=== Object.prototype
通过上面的代码,我们知道这个toString()方法是在Object.prototype里面的,当调用这个对象的本身并不存在的方法时,它会一层一层地往上去找,一直到null为止。
所以当fn调用toString()时,JS发现fn中没有这个方法,于是它就去Foo.prototype中去找,发现还是没有这个方法,然后就去Object.prototype中去找,找到了,就调用Object.prototype中的toString()方法。
这就是原型链,fn能够调用Object.prototype中的方法正是因为存在原型链的机制。
另外,在使用原型的时候,一般推荐将需要扩展的方法写在构造函数的prototype属性中,避免写在_ _ proto _ _属性里面。
---------------------
一文读懂JS中的原型和原型链(图解)的更多相关文章
- 一文搞懂 js 中的各种 for 循环的不同之处
一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...
- 一文读懂Java中的动态代理
从代理模式说起 回顾前文: 设计模式系列之代理模式(Proxy Pattern) 要读懂动态代理,应从代理模式说起.而实现代理模式,常见有下面两种实现: (1) 代理类关联目标对象,实现目标对象实现的 ...
- 一文看懂js中元素的滚动大小(scrollWidth,scrollHeight,scrollTop,scrollLeft)
滚动大小(scroll dimension) 滚动大小指的是包含滚动内容元素的大小. 以下是与元素滚动内容大小相关的属性: 1. scrollWidth:在没有滚动条的情况下,元素内容的总宽度. 2. ...
- 一文看懂js中元素的客户区大小(clientWidth,clientHeight)
元素的客户区 元素的客户区大小,指的是元素内容及其内边距所占据的空间大小. 相关属性如下: 1. clientWidth:元素内容区宽度+元素左右内边距 2. clientHeight:元素内容区高度 ...
- 一文搞懂js中的typeof用法
基础 typeof 运算符是 javascript 的基础知识点,尽管它存在一定的局限性(见下文),但在前端js的实际编码过程中,仍然是使用比较多的类型判断方式. 因此,掌握该运算符的特点,对于写出好 ...
- 一文读懂BERT中的WordPiece
1. 前言 2018年最火的论文要属google的BERT,不过今天我们不介绍BERT的模型,而是要介绍BERT中的一个小模块WordPiece. 2. WordPiece原理 现在基本性能好一些的N ...
- 一文看懂js中的clientX,clientY,pageX,pageY,screenX,screenY
一. 客户区坐标位置(clientX,clientY) 鼠标事件都是在浏览器视口中的特定位置发生的.这个位置信息保存在事件对象的clientX和clientY属性中,所有浏览器都支持这两个属性. 我们 ...
- 一文看懂js中元素偏移量(offsetLeft,offsetTop,offsetWidth,offsetHeight)
偏移量(offset dimension) 偏移量:包括元素在屏幕上占用的所有可见空间,元素的可见大小有其高度,宽度决定,包括所有内边距,滚动条和边框大小(注意,不包括外边距). 以下4个属性可以获取 ...
- 一文读懂 .NET 中的高性能队列 Channel
介绍 System.Threading.Channels 是.NET Core 3.0 后推出的新的集合类型, 具有异步API,高性能,线程安全等特点,它可以用来做消息队列,进行数据的生产和消费, 公 ...
随机推荐
- JS高级程序设计第2章--精简版
前言:这次是二刷了,想暑假做一次完整的笔记,但用本子来写笔记的话太贵了,可能哪天还丢了..所以还是博客好== 第二章:在HTML中使用JavaScript 2.1 <script>元素: ...
- 爬取链家网租房图 使用ImagesPipeline保存图片
# 爬虫文件 # -*- coding: utf-8 -*- import scrapy import os from urllib import request from lianjia.items ...
- Spring 核心技术(2)
接上篇:Spring 核心技术(1) version 5.1.8.RELEASE 1.3 Bean概述 Spring IoC 容器管理一个或多个bean,他们都是根据提供的配置元数据(例如 XML 中 ...
- 基于SpringBoot从零构建博客网站 - 设计可扩展上传模块和开发修改头像密码功能
上传模块在web开发中是很常见的功能也是很重要的功能,在web应用中需要上传的可以是图片.pdf.压缩包等其它类型的文件,同时对于图片可能需要回显,对于其它文件要能够支持下载等.在守望博客系统中对于上 ...
- Go语言解密上篇中用java aes实现的加密
上一篇java aes文件加解密中加密的梅须逊雪三分白,雪却输梅一段香.使用go语言解密. 解密代码如下: AESUtil.go package util import ( "crypto/ ...
- 开源框架Autofac使用入门
目录导航 1.Autofac是什么 1.1什么是DI和IOC 1.2DI和IOC在项目中起到什么作用 2.Autofac如何使用 2.1下载 2.2代码Demo 2.3Demo分析 3总结 1.Aut ...
- 【HDU - 1560】DNA sequence (dfs+回溯)
DNA sequence 直接中文了 题目描述 21世纪是生物科技飞速发展的时代.我们都知道基因是由DNA组成的,而DNA的基本组成单位是A,C,G,T.在现代生物分子计算中,如何找到DNA之间的最长 ...
- 五分钟部署一套完整的Zabbix
Zabbix-安装与使用 安装NTP yum install -y ntp 配置ntp.conf cd /etc/ vim ntp.conf # 打开之后讲一下内容添加 server cn.ntp.o ...
- ForkJoinPool分支/合并框架工程使用的工作窃取
ForkJoinPool分支/合并框架 在必要的情况下,讲一个大任务,进行拆分(fork)成若干个小任务(拆到不可拆为止),再将一个个小的任务运算的结果进行join汇总. 工作窃取的背景 分支/合并框 ...
- Java 虚拟机部分面试题
Java虚拟机部分的面试内容包括三部分:GC.类加载机制以及内存 Java内存区域 JVM内存分为哪几部分,这些部分分别都存储哪些数据? 线程隔离的数据区:程序计数器.Java虚拟机栈.本地方法栈. ...