js原型和构造函数
前言
从应用层面深入理解原型模式和js中的构造函数。
构造函数(constructor)
js中的任何对象都有自己的构造函数。js中使用字面量声明的普通对象({})或数组([])等子对象本质上都是使用相关的函数做构造调用声明的。
// 等同于 var obj = {}; var obj = new Object(); // 等同于 arr = []; var arr = new Array();
获取对象的构造函数:constructor是可读的,在对象上进行普通的属性访问(. / [])即可。
// 这里我们可以看到字面量语法声明的对象本质还是使用Object()构造的。var obj = {}; console.log(obj.constructor); // ƒ Object() { [native code] }
原型
显式原型prototype属性
prototype是函数的属性。每个函数被创建之后,都会拥有一个prototype属性,这个属性指向函数的原型对象。
function fn (){} console.log(fn.prototype);
fn.prototype的原型在chrome下的输出。是一个对象,这个对象有一个显式的属性constructor(构造函数),它指向的是构造这个对象的函数。 还有一个隐式的属性,__proto__。
隐式原型__proto__属性
__proto__是对象的属性。每个对象被创建的时候都会拥有这个属性,这个属性指向的是,构造这个对象的函数的原型对象。
访问对象的__proto__属性:IE10以前无法识别__proto__属性,其他浏览器大部分都可以识别,可以输出但无法访问内部信心。ES5提供的Object.getPtotypeOf(obj) 可以获取指定对象的__proto__属性。
function fn (){} var obj = new fn(); console.log(fn.prototype === Object.getPrototypeOf(obj)); // true
搞清楚prototype/__proto__/constructor之间的区别和联系
1,所有对象都有自己的构造函数(constructor),和一个隐式的原型属性(__proto__),__proto__指向的是这个对象的构造函数的原型。
2,所有的函数都有一个prototype属性这个熟悉指向的是构造函数的原型对象。
var obj = {}; // 这里的true不理解的话回头再看一遍之前的小例子,敲一下。理解这个true的话 原型这个部分的应用就没问题了。 console.log(obj.constructor.prototype === Object.getPrototypeOf(obj)); // true
原型链
原型链就是一个对象作为另一个对象的原型而存,而这个作为别人原型的对象还有自己的原型。
根对象
js中的所有对象都拓展于Object.prototype。 它是js中的顶层对象。在它之上没有其他的原型了。
var obj= {}; var objConstructor = obj.constructor; // Object() 是使用js字面量创建的对象的构造函数。 console.log(objConstructor); // ƒ Object() { [native code] } // Object.prototype是js中的根对象,在它之上没有其他原型了。 console.log(Object.getPrototypeOf(objConstructor.prototype)); // null
原型链的形成
关键就在于让一个对象成为另一个对象的原型。
Object.create(obj):返回一个把指定参数作为原型的新对象。
var obj= {name:"obj"}; var newObj = Object.create(obj); console.log(newObj);
从chrome下的输出我们可以看到 形成了一个三层的原型链 newObject 中的隐式原型属性__proto__指向了obj,obj是使用字面量创建的普通对象,它本质上是使用Object()创建的。所以它指向的是根对象Object.prototype。
原型模式的执行流程
在对象本身查找要访问的属性和方法,如果没有,就到最近的原型上找,直接原型上没有,就到原型的原型上找,找到就直接返回,结束查找。一直找到Object.prototype上都没有,就返回undefined。
原型模式的应用
主要有两种,面向对象写法和任务委托写法。面向对象就是使用原型继承,多态都用的很少,使用起来也比较难理解。任务委托是在《你不知道的js》一书中看到的写法,设计上来看比强行面向对象要直观。但现在时代变了,ES6提供了Class语法糖,让面向对象的js程序可读性较好,便于理解。所以只了解一下任务委托写法。
面向对象
三大特征:封装,继承,多态。
好处:结构清晰,易维护,易拓展。
基于原型继承的面向对象
js中是没有传统面向类语言中的类和构造函数的,它使用new关键字配合普通函数模拟了构造函数,使用原型模拟类,让js拥有了继承和多态的能力。
面向对象写法:定义普通函数做构造调用,在函数的原型上提供实例共享的属性和方法。
任务委托:将数据和工具对象分开定义,让工具对象作为数据对象的原型。达到数据和逻辑分离,将任务处理委托给其他对象的目的。
var util = { say:function(){ console.log(this.name); } } var data = Object.create(util); data.name = "键盘"; data.say(); // 键盘
小结:
1,每个对象都有自己的构造函数,可以通过constructor属性访问到。
2,每个对象都有一个隐式原型属性__proto__,可以使用Object.getPrototypeOf(obj)访问。
3,每个函数都有自己的原型对象,可以通过prototype属性访问。
4,对象的隐式原型属性(__proto__)指向的就是它的构造函数的原型(prototype)。
5,所有使用字面量创建的对象,本质上都是使用相关构造器函数构造出来的,函数是(Function()),数组是(Array())等等。
6,js中的Object是顶层函数它的prototype之上没有其他的原型了。js中所有对象的原型链的顶层几乎都是Object.prototype。
7,原型链就是对象做为其他对象的原型,的同时还有自己的原型。
8,原型模式的执行顺序就是首先在对象自有属性中查找,找不到就问原型有没有,原型没有就问原型的原型有没有,直到找到返回或找到顶层原型后返回undefined。
9,js中的面向对象就是基于原型模式在普通函数的原型上定义共享的属性和方法,达到继承的目的。
js原型和构造函数的更多相关文章
- 对js原型及构造函数的相关理解
一.js中的原型创建(声明)一个函数,浏览器在内存中会创建一个对象.每个函数都默认会有一个属性prototype指向了这个对象,就是说prototype的属性的值就是这个对象.此对象就是该函数的原型对 ...
- js原型和构造函数混合模式
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- JS原型、原型链、构造函数、实例与继承
https://cloud.tencent.com/developer/article/1408283 https://cloud.tencent.com/developer/article/1195 ...
- 一篇文章理解JS继承——原型链/构造函数/组合/原型式/寄生式/寄生组合/Class extends
说实在话,以前我只需要知道"寄生组合继承"是最好的,有个祖传代码模版用就行.最近因为一些事情,几个星期以来一直心心念念想整理出来.本文以<JavaScript高级程序设计&g ...
- JS中关于构造函数、原型链、prototype、constructor、instanceof、__proto__属性
在Javascript不存在类(Class)的概念,javascript中不是基于类的,而是通过构造函数(constructor)和原型链(prototype chains)实现的.但是在ES6中引入 ...
- Js中关于构造函数,原型,原型链深入理解
在 ES6之前,在Javascript不存在类(Class)的概念,javascript中不是基于类的,而是通过构造函数(constructor)和原型链(prototype chains)实现的.但 ...
- 简单粗暴地理解js原型链--js面向对象编程
原型链理解起来有点绕了,网上资料也是很多,每次晚上睡不着的时候总喜欢在网上找点原型链和闭包的文章看,效果极好. 不要纠结于那一堆术语了,那除了让你脑筋拧成麻花,真的不能帮你什么.简单粗暴点看原型链吧, ...
- JS原型链
JS作为发展了多年了对象语言,支持继承,和完全面向对象语言不同的是,JS依赖原型链来实现对象的继承. 首先JS的对象分两大类,函数对象和普通对象,每个对象均内置__proto__属性,在不人为赋值__ ...
- 【09-23】js原型继承学习笔记
js原型继承学习笔记 function funcA(){ this.a="prototype a"; } var b=new funcA(); b.a="object a ...
随机推荐
- Java多线程系列 基础篇10 wait/notify/sleep/yield/join
1.Object类中的wait()/notify()/notifyAll() wait(): 让当前线程处于Waiting状态并释放掉持有的对象锁,直到其他线程调用此对象的线程notify()/not ...
- Spring Boot2.0之统一处理web请求日志
试问,你的项目中,如果有几万个方法,你还这么写log.info("name"+name+",age"+age )日志么?low~ 所以用AOP呀 1.首先创建个 ...
- 使用C++模拟C#的委托机制
1. [代码][C/C++]代码 //Event.h #ifndef _EVENT_H_#define _EVENT_H_class EmptyObject {};template<typen ...
- linux启动全过程
参考: http://www.staroceans.org/e-book/linux-bootstrap-1.html 1. MBR里的内容属于grub grub-2.02\grub-core\boo ...
- linux 下errno各个值的意义(转) errno.h
strerror(errno):获取errno对应的错误 查看错误代码errno是调试程序的一个重要方法.当linux C api函数发生异常时,一般会将errno变量(需include errno. ...
- k8s-flannel容器集群网络部署
[root@k8s-master src]# wget https://github.com/coreos/flannel/releases/download/v0.9.1/flannel-v0.9. ...
- BZOJ1453:[WC]Dface双面棋盘
浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://lydsy.com/JudgeOnline/problem. ...
- SQL SERVER 判断是否存在数据库、表、列、视图
SQL SERVER 判断是否存在数据库.表.列.视图 --1. 判断数据库是否存在 IF EXISTS (SELECT * FROM SYS.DATABASES WHERE NAME = '数据库名 ...
- TCP点对点穿透探索--失败
TCP点对点穿透探索 点对点穿透是穿透什么 点对点穿透,需要实现的是对NAT的穿透.想实现NAT的穿透,当然要先了解NAT到底是什么,以及NAT是用来干什么的.NAT全称Network Address ...
- python3中,pycharm中怎么连接数据库
因为python3现在还不能直接连接数据库,所有如果想连接,就只能通过以下方法: 在APP中的,__init__.py中,添加以下代码就可以: import pymysql pymysql.insta ...