关于JS对象原型prototype与继承,ES6的class和extends · kesheng's personal blog
传统方式:通过function关键字来定义一个对象类型
1 |
function People(name) {
|
上面的代码里,我们定义People这种类型,它的属性特征有name、toSay、toEat 。然后我们以People为模板new出来一个p的实例对象。刚接触js时,可能会疑惑,function声明的不是函数么,怎么又变成定义对象类型?prototype是什么?
其实在js中,函数本身也是一个对象。这种对象有点特殊,它的作用是定义了对象类型,可以说是数据结构模板。 而prototype是它的一个属性,称为对象原型,其本质也是一个对象,包含constructor和其他属性成员。constructor默认指向自身构造函数。
所以声明People的时候,程序自动People对象添加了prototype属性,并且让prototype.constructor指向了People,即函数本身。所以上面的例子等同于下面的写法:
1 |
function People(name) {
|
prototype的作用:当我们new一个实例对象p时,程序根据对象类型People的原型prototype,将原型所定义的属性(constructor除外)复制给新的实例对象p,并执行了一次prototype.constructor 所指向的构造函数,对实例对象p进行初始化。
实例对象p有两种属性:实例属性、原型属性
实例属性: 构造方法里定义的
原型属性: 在原型prototype里定义
hasOwnProperty方法可以帮我们区分
p.hasOwnProperty(“name”); // true
p.hasOwnProperty(“toSay”); // false,因为这个属性是原型上定义的
问题1:为什么我们不直接都在构造函数里面定义呢?
1 |
function People(name) {
|
答: 这个主要考虑内存管理,因为函数是内存中的一个对象,也就是说,toSay或toEat都是对象占有一定内存。写在构造函数里面,每new一个实例对象,都会执行一次构造函数,都会重新创建一个函数对象,赋给新的实例对象的属性上。结果就是每一个实例对象的toSay或toEat属性都对应各自的函数对象,而这些函数功能都是一样的,我们创建了一大堆重复的函数对象。使用prototype不会,因为大家共享一个prototype对象。
问题2: 为什么name不是直接定义在原型prototype上呢?
答:每个人名字不同,如果定义在prototype上,大家名字就一样了,其中一个改变了name值,都会影响到其他实例对象。
注意:实例对象是没有prototype属性,所以你不可以用实例对象为模板new一个新的实例对象来,只能用函数对象为模板来创建。
var p1 = new People(‘’小明”); // 正确,函数对象的prototype的constructor指定构造方法
var p2 = new p1(“小王”) ; // error ,实例对象没有prototype,找不到构造方法
各大浏览器厂商给实例对象实现了一个 proto 属性,指向对象原型,我们称为实例对象的隐式原型,即:
var p1 = new People(“小明”)
p1.proto === People.prototype // true
但我们要避免使用这个属性, 这个属性作用我猜测是浏览器提供给我们方便调试的时候用的。
问题1:People.prototype是一个对象,这个对象是什么?
答:Object, js所有对象默认继承js内置对象Object。
问题2: js中,怎么实现对象的继承?
答:js的继承是通过对象原型prototype来实现的。
1 |
// 父类型 |
上面的代码,我们就实现了Cat的对象类型是继承了Animal对象类型,所以我们可以看到:
1 |
var cat1 = new Cat() |
hasFoot、与footNum都是从父类型annimal继承过来的,而toString为什么有呢,其实是这样,Cat继承了Animal,而Animal默认继承了Object,所以当我们找cat1的toString属性是,发现自身实例属性没有,发现原型上也没有定义,那程序就会寻所继承的父对象的实例属性,父对象的原型属性,这样一步步找下去,这就是JS的原型链。所以就是:
1 |
cat1.__proto__ === Cat.prototype // true |
上 大专栏 关于JS对象原型prototype与继承,ES6的class和extends · kesheng's personal blog面的程序设计存在一个问题,有的猫只有一种颜色,有猫身上的颜色有三种,橘、白、黑。显然从Animal继承过来的颜色只有不能满足这种情况
1 |
var cat2 =new Cat() |
面对这种情况,我们的Cat对象类型应该这么写:
1 |
function Cat() {
|
虽然的方式解决了问题,但是还是有个缺点,调用了两次Animal构造函数。第一次是指定Cat.prototype,第二次是Cat自身构造函数中主动调用。我们更想要的是,指定了prototype,new实例时,构造函数就不要再调用Animal()了。此时我们需要一个工具来完成
1 |
// 工具extend |
上面的这种方式,将指定Cat.prototype从通过new Animal()换成直接Object.creat(Animal.prototype),这样就避免了Animal() 构造函数的执行。
实际上,这方式是最高效的方式。
对比其他面向对象开发语言(如: java),js通过function定义对象类型,容易让人不理解。ES6新规范推出class和extends关键字来实现面向对象编程。
ES6方式:用class关键字定义对象类型,用extends关键字实现继承
1 |
const private2 = Symbol('I am symbol value')
|
class关键字会让我们更清晰设计一个对象类型,实际上,这只是语法糖:
A 的实质还是一个function
对属性的定义是实例属性,而对方法的定义是定义在原型上
// 通过extends继承
1 |
class B extends A{
|
我们可以知道,实际上A、B都是两个对象类型,B继承A。ES6的class作为语法糖也提供了prototype和proto两个属性;
1 |
let instanceA = new A() |
对于class本来就是让我们能够避开传统function的不容易理解的语义,我们实际中尽量不要去使用proto,很多时候把自己给绕晕了。另外,这里补充一句:
class内部定义的变量是不能存在变量提升的,也就是说你用了var也是不存在变量提升。因为他是一个语法糖,我们new一个实例时才会走进构造函数栈,执行完后,当前栈被销毁,而里面返回的值赋给了实例的属性,而里面的变量标记会被清除掉,因此不存在变量提升。
关于JS对象原型prototype与继承,ES6的class和extends · kesheng's personal blog的更多相关文章
- js对象原型prototype
javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用. 每一个构造函数都有一个属性叫做原型 1.1. 原型法设 ...
- JS基础-原型链和继承
创建对象的方法 字面量创建 构造函数创建 Object.create() var o1 = {name: 'value'}; var o2 = new Object({name: 'value'}); ...
- js的原型prototype究竟是什么?
Javascript也是面向对象的语言,但它是一种基于原型Prototype的语言,而不是基于类的语言.在Javascript中,类和对象看起来没有太多的区别. 1.什么是prototype: fun ...
- JS对象原型的理解
基于原型的语言 JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板.从原型继承方法和属性.原型对象 ...
- js对象原型链
JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象.这个对象的所有属性和方法,都会被构造函数的所拥有. 这也就意味着,我们可以把所有对象实例需要共享的属性和方 ...
- js对象冒充实现的继承
//人类 function Person(name) { this.name = name; this.showName = function () { console.log("my na ...
- javascript 对象 原型 prototype
- 怎么理解js的原型链继承?
前言 了解java等面向对象语言的童鞋应该知道.面向对象的三大特性就是:封装,继承,多态. 今天,我们就来聊一聊继承.但是,注意,我们现在说的是js的继承. 在js的es6语法出来之前,我们想实现js ...
- 攻略前端面试官(三):JS的原型和原型链
本文在个人主页同步更新~ 背就完事了 介绍:一些知识点相关的面试题和答案 使用姿势:看答案前先尝试回答,看完后把答案收起来检验成果~ 面试官:什么是构造函数 答:构造函数的本质是一个普通函数,他的特点 ...
随机推荐
- html title属性内容换行方法(静态页面)
鼠标经过悬停于对象时提示内容(title属性内容)换行排版方法,html title 换行方法总结. html的title属性默认是显示一行的,这里介绍两种换行方法为大家分享使用. 一.直接title ...
- Huffman编码实验
一. 实验目的 熟练掌握哈夫曼树的建立和哈夫曼编码的算法实现. 二. 实验内容 根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求赫夫曼编码,并能把给定的编码进行译码. 三. 实验要求 ...
- LeetCode——1305. 两棵二叉搜索树中的所有元素
给你 root1 和 root2 这两棵二叉搜索树. 请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序.. 示例 1: 输入:root1 = [2,1,4], root2 = [1,0 ...
- 14 微服务电商【黑马乐优商城】:day06-了解vue-router和webpack的使用
本项目的笔记和资料的Download,请点击这一句话自行获取. day01-springboot(理论篇) :day01-springboot(实践篇) day02-springcloud(理论篇一) ...
- 小程序中map的取值和赋值
1.初始化 resultMap: { "near": [], "join": [], "publish": [] } 2.js中直接取 co ...
- \b 是单词边界锚点 word-boundary anchor,一个“\b”匹配一个单词的一端,两个“\b”匹配一个单词的头尾两端
123 $_ = "beforematcha? fter"; 124 if(/\b\w+a\b/){ 125 print "matched: < ...
- CentOS本地挂载镜像
title date tags layout CentOS6.5 ISO镜像挂载,创建本地yum源 2018-08-23 Linux post 1.虚拟机挂载光盘选择相应的镜像 2.@#¥%--&am ...
- LeetCode No.97,98,99
No.97 IsInterleave 交错字符串 题目 给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的. 示例 输入: s1 = "aabcc&qu ...
- 算法笔记 4.4 贪心 问题 A: 看电视
问题 A: 看电视 题目描述 暑假到了,小明终于可以开心的看电视了.但是小明喜欢的节目太多了,他希望尽量多的看到完整的节目. 现在他把他喜欢的电视节目的转播时间表给你,你能帮他合理安排吗? 输入 输入 ...
- qsub|pasta|
cd /xxx/genome_stat/Annotation ln -s /xxx/02.annotation/gff_v2/*.homolog.v2.gff /xxx/genome_stat/Ann ...