javascript 面向对象学习(二)——原型与继承
什么是原型?
首先我们创建一个简单的空对象,再把它打印出来
var example = {}
console.log(example)
结果如下:
{
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}
我们创建的example是个空对象,按理说应该什么属性都没有,却出现了一个__proto__属性,这个属性是从哪里来的呢?实际上,当我们调用 var example = {} 时,相当于调用 var example = new Object(),隐式地继承了 Object.prototype 的属性和方法。Object.prototype 对象是 javascript 的根对象,javascript 的每个对象都是从这个对象来的,下面我们通过构造函数的例子看一下prototype、__proto__到底是什么。
我们来定义一个构造函数
function Person() {}
console.log(Person.prototype)
打印出 Person 的 prototype 属性,结果如下:
{
    constructor: ƒ Person(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}
可以看到,这个属性包含了consturcor属性(指向自己)和__proto__属性(指向Object.prototype,即根对象。因为在js里,函数也是对象,继承自根对象)。所有的函数都有这样一个叫做prototype的属性,即原型对象,我们可以在原型对象上定义属性和方法:
Person.prototype.name = 'Jack'
Person.prototype.jump = function() {
console.log(this.name + '-jump')
}
console.log(Person.prototype)
这时打印出的原型对象为
{
    name: "Jack",
    jump: ƒ (),
    constructor: ƒ doSomething(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}
name 属性和 jump 方法被加到了这个对象上面。那么,这个原型对象有什么用呢?
我们再用这个构造函数创建一个实例:
function Person() {}
Person.prototype.name = 'Jack'var jack = new Person()
jack.sex = 'male'
console.log(jack)
我们在构造函数原型和实例对象上都加了属性,现在把 jack 打印出来如下:
{
    sex: "male",
    __proto__: {
        name: "Jack",
        constructor: ƒ doSomething(),
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }
可以看到,jack 有个 __proto__ 属性,这个属性跟它的构造函数 Person 的 prototype 属性内容是一样的,我们打印如下内容:
console.log(jack.name) // Jack
得到的结果是 “Jack”,在jack的属性里并没有name这一项,name 是定义在Person 的 prototype 属性上的,然而我们却能从jack中访问到,这就是原型的继承作用。我们访问jack.name时,浏览器首先查找jack有没有name属性,有的话直接获取,没有的话会去jack.__proto__属性里查询,再查不到继续在jack.__proto__.proto__里找……由此形成一条链,即原型链。在这里jack.__proto__.__proto__就是Object.prototype。需要注意的是,原型继承的核心是prototype,而不是__proto__,__proto__是浏览器内部属性,只是用来访问原型对象prototype属性的。下面我们来看一下怎么让两个不相关的对象通过原型链实现继承。
// 定义父对象
var father = {
name: 'Jack'
}
// 定义子对象的构造函数
function Son() {}
// 令子对象的构造函数的原型指向父对象
Son.prototype = father
// 创建子对象实例
var son = new Son() console.log(son.name) // Jack
核心代码就是标红的那句:令子对象的构造函数的原型对象指向父对象。
总结:在javascript里,每个函数都有叫做原型对象的prototype属性,js的根对象是Object.prototype。通过构造函数创建出的实例能继承构造函数原型对象的属性和方法。
javascript 面向对象学习(二)——原型与继承的更多相关文章
- JavaScript之面向对象学习二(原型属性对象与in操作符)获取对象中所有属性的方法
		
1.原型属性对象于in操作符之in单独使用 有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用中,代码如下: function Person(){ } Person.protot ...
 - (二)Javascript面向对象编程:构造函数的继承
		
Javascript面向对象编程:构造函数的继承 这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承 ...
 - JavaScript 面向对象程序设计(下)——继承与多态 【转】
		
JavaScript 面向对象程序设计(下)--继承与多态 前面我们讨论了如何在 JavaScript 语言中实现对私有实例成员.公有实例成员.私有静态成员.公有静态成员和静态类的封装.这次我们来讨论 ...
 - Lua面向对象之二:类继承
		
1.类继承 ①代码 Sharp = { } --① 父类 function Sharp:new() local new_sharp = { } self.__index = self --②,self ...
 - Javascript面向对象特性实现封装、继承、接口详细案例——进级高手篇
		
Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...
 - Javascript面向对象特性实现封装、继承、接口详细案例
		
Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...
 - JavaScript面向对象学习笔记
		
JavaScript 常被描述为一种基于原型的语言 (prototype-based language)--每个对象拥有一个原型对象,对象以其原型为模板.从原型继承方法和属性.原型对象也可能拥有原型, ...
 - javascript 面向对象 new 关键字 原型链 构造函数
		
JavaScript面向对象JavaScript 语言使用构造函数(constructor)作为对象的模板.所谓"构造函数",就是专门用来生成实例对象的函数.它就是对象的模板,描述 ...
 - JavaScript面向对象 实例与原型
		
JavaScript 面向对象 和 C# 不太一样,js 的对象是继承自原型的如下: 首先创建一个 js 实例 new function function f () {} 这个函数 会继承 Func ...
 
随机推荐
- 【Linux】Xshell 配置密钥登陆
			
设置不需要密码登陆 vim /etc/ssh/sshd_config 在配置文件中参数的意义 PubkeyAuthentication yes #启用公告密钥配对认证方式 AuthorizedKeys ...
 - XXX_ProductCRUD的项目结构与配置文件
			
MVC_ProductCRUD Hibernate_ProductCRUD 项目结构 ...
 - Python小技巧:如何批量更新已安装的库?
			
众所周知,升级某个库(假设为 xxx),可以用pip install --upgrade xxx 命令,或者简写成pip install -U xxx . 如果有多个库,可以依次写在 xxx 后面,以 ...
 - Springboot 关于日期时间格式化处理方式总结
			
项目中使用LocalDateTime系列作为DTO中时间的数据类型,但是SpringMVC收到参数后总报错,为了配置全局时间类型转换,尝试了如下处理方式. 注:本文基于Springboot2.x测试, ...
 - LinkedList为什么增删快、查询慢
			
List家族中共两个常用的对象ArrayList和LinkedList,具有以下基本特征. ArrayList:长于随机访问元素,中间插入和移除元素比较慢,在插入时,必须创建空间并将它的所有引用向前移 ...
 - 关于 conda中的 lxml 无法导入 etree 问题
			
找到你conda的安装目录下\Lib\site-packages下的两个文件夹lxml和lxml-4.3.4.dist-info,将这两个文件夹删除. 执行命令pip install lxml 重新安 ...
 - [Unity2d系列教程] 006.Unity如何根据图片自动生成Animator
			
Unity制作2D产品的时候,我们在制作动画的时候,要不断的生成Animation,Animator等等资源,如果动画一多的话,就变得麻烦.由于Unity是支持插件开发的,我们可以添加一个Editor ...
 - Java中的集合(十一) 实现Map接口的TreeMap
			
Java中的集合(十一) 实现Map接口的TreeMap 一.TreeMap简介(基于JDK1.8) TreeMap是基于红黑树数据结构,是一个key-value的有序集合,该映射根据其键的自然顺序进 ...
 - Chisel3 - model - IO ports
			
https://mp.weixin.qq.com/s/fgCvIFt0RdEajhJVSy125w 介绍模块的输入输出端口的定义与管理. 1. _ports 1) 模块的输入输出端口, ...
 - Java实现 LeetCode 543 二叉树的直径
			
543. 二叉树的直径 给定一棵二叉树,你需要计算它的直径长度.一棵二叉树的直径长度是任意两个结点路径长度中的最大值.这条路径可能穿过根结点. 示例 : 给定二叉树 1 / \ 2 3 / \ 4 5 ...