JS对象继承与原型链
1.以复制方式实现的继承
1.1浅拷贝
基本类型的复制
var parent = {
lanage: "chinese"
}
var child = {
name: "xxx",
age: 12
}
function extend(parent, child) {
var child = child || {};
for (const propertype in parent) {
child[propertype] = parent[propertype];
}
}
extend(parent, child);
console.log(child);//{ name: 'xxx', age: 12, lanage: 'chinese' }
以上代码中,通过一个extend()函数,将父对象parent的属性遍历赋给子对象child,从而实现继承。
但是这种字面量复制的方式存在巨大的缺陷,当父对象有引用类型的属性时,通过这么复制的方式,就像上一节中的var b = a一样,只会将a对象的引用赋给b对象,结果两者是指向同一个对象内存的,继承出来的子对象的属性是同一个,显然是不能满足需求的,(基本类型之间画等号是值的复制,引用类型之间画等号是引用的复制)所以就需要另谋出路。
1.2.深拷贝
利用递归加类型判断复制引用类型
var parent = {
lanage: "chinese",
address: {
home: "gansu",
office: "xian"
},
schools: ["xiaoxue", "zhongxue", "daxue"]
}
var child = {
name: "xxx",
age: 12
}
function extendDeeply(parent, child) {
var child = child || {};
for (const propertype in parent) {
//首先判断父对象的当前属性是不是引用类型
if (typeof parent[propertype] === "object") {
//再判断该引用类型是不是数组,是则给子对象初始化为空数组,否则初始化为空对象
child[propertype] = Array.isArray(parent[propertype]) ? [] : {};
//递归调用自己,将父对象的属性复制到子对象
extendDeeply(parent[propertype], child[propertype]);
} else {
//基本类型直接复制
child[propertype] = parent[propertype];
}
}
}
extendDeeply(parent, child);
console.log(child);
child.schools[0] = "qinghua"; //改变子对象的属性值
child.address.home = "tianjin";
console.log(child.schools[0]); //qinghua
console.log(parent.schools[0]); //xiaoxue
console.log(child.address.home); //tianjin
console.log(parent.address.home); //gansu
可见此时子对象的改变并不会影响到父对象,父子彻底决裂。这便是深拷贝实现的继承。
注意:for in 是可以遍历数组的,结果为数组元素下标。
2.以构造函数实现继承
function Parent() {
this.name = "name";
this.age = 12;
}
function Child() {
Parent.call(this);
this.language = "chinese";
}
var child = new Child();
console.log(child);//{ name: 'name', age: 12, language: 'chinese' }
child.name = "swk";
console.log(new Parent().name);//name
如上所示,通过在子类构造函数中调用父类构造函数,将父类属性继承到子类对象上,new出来的每一个子类对象都是独立的实例,这种方式更符合面向对象的思想。
3.以原型方式实现继承
var person = {name: "pname"};
function myCreate(person) {
var ins;
function F() { };
F.prototype = person;
ins = new F();
return ins;
}
var c = new myCreate(person);
console.log(c.name); //pname
console.log(c); //{}
如上所示,将一个构造函数的原型替换为父对象,然后返回该构造函数的实例,如此一来创建的子对象就是F的实例,并且其原型为父对象,所以c.name可以被查找到,但子对象c本身是没有属性的。这种直接重写prototype原型对象的弊端在于会断掉原本的原型链,即没有了继承自Object的方法,和给原型对象prototype上添加属性是不同的。
4.JS原型链
盗一波大神的经典图

从该图可以看出两点
4.1从原型prototype层面:
- 不论是 new Foo()自定义构造函数,new Object()系统构造函数,还是对象字面量创建出来的对象,只要是对象,其原型最终都指向Object.prototype对象,自定义的多绕了一步,就像Java里说的,Object.prototype是一切JS对象的根对象。
- 函数的原型都指向Function.prototype,而在JS中,函数也是对象的一种,所以符合第一条。
4.2从构造器constructor层面
- 首先对象的构造器肯定是指向他的构造函数,f1, f2指向Foo(), o1, o2指向Object()。
- 而构造函数Foo()和Object()的constructor属性最终指向函数构造器Function()。
JS对象继承与原型链的更多相关文章
- 一步步学习javascript基础篇(5):面向对象设计之对象继承(原型链继承)
上一篇介绍了对象创建的几种基本方式,今天我们看分析下对象的继承. 一.原型链继承 1.通过设置prototype指向“父类”的实例来实现继承. function Obj1() { this.name1 ...
- JS面向对象(2) -- this的使用,对象之间的赋值,for...in语句,delete使用,成员方法,json对象的使用,prototype的使用,原型继承与原型链
相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...
- JS function 是函数也是对象, 浅谈原型链
JS function 是函数也是对象, 浅谈原型链 JS 唯一支持的继承方式是通过原型链继承, 理解好原型链非常重要, 我记录下我的理解 1. 前言 new 出来的实例有 _proto_ 属性, 并 ...
- js继承之原型链方式实现
温故而知新: 在之前的文章已经重点了解了原型对象,今天就理一理这个原型对象在原型链式的继承中的使用 function a(x,y){this.x=x;this.y=y;} //定义一个函数,当构造函数 ...
- JS对象继承篇
JS对象继承篇 ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的 原型链 其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法 function Person() ...
- (翻译) Inheritance and the prototype chain 继承和原型链
JavaScript is a bit confusing for developers experienced in class-based languages (like Java or C++) ...
- JavaScript之继承(原型链)
JavaScript之继承(原型链) 我们知道继承是oo语言中不可缺少的一部分,对于JavaScript也是如此.一般的继承有两种方式:其一,接口继承,只继承方法的签名:其二,实现继承,继承实际的方法 ...
- 一篇JavaScript技术栈带你了解继承和原型链
作者 | Jeskson 来源 | 达达前端小酒馆 1 在学习JavaScript中,我们知道它是一种灵活的语言,具有面向对象,函数式风格的编程模式,面向对象具有两点要记住,三大特性,六大原则. 那么 ...
- 关于JavaScript的原型继承与原型链
在讨论原型继承之前,先回顾一下关于创建自定义类型的方式,这里推荐将构造函数和原型模式组合使用,通过构造函数来定义实例自己的属性,再通过原型来定义公共的方法和属性. 这样一来,每个实例都有自己的实例属性 ...
随机推荐
- Docker和虚拟机的区别
这是docker官网的图,可以看到虚拟化技术通过Hypervisor(虚拟机管理系统)为每个app启动一个Guest OS(客户机操作系统),也就是为每个app启动一个虚拟机.比较直观地说,vm通过H ...
- [javase学习笔记]-7.6 thiskeyword的原理
这一节我们来讲一个keyword.就是thiskeyword. 我们还是通过样例来看吧: class Person { private String name; private int age; Pe ...
- 怎样选择正确的HTTP状态码
本文来源于我在InfoQ中文站翻译的文章.原文地址是:http://www.infoq.com/cn/news/2015/12/how-to-choose-http-status-code 众所周知. ...
- 用DOM动态控制表格
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- Kali linux 2016.2(Rolling)中metasploit的搜集特定地址的邮件地址
不多说,直接上干货! 使用search_email_collector搜集特定地址的邮件地址 search_email_collector 要求提供一个邮箱后缀,通过多个搜索引擎的查询结果分析使用此后 ...
- ReactiveCocoa结合了几种编程风格
函数式编程(Functional Programming):使用高阶函数,例如函数用其他函数作为参数.响应式编程(Reactive Programming):关注于数据流和变化传播.所以,你可能听说过 ...
- Python3基础笔记--装饰器
装饰器是十二分重要的高级函数. 参考博客:装饰器 所需前提知识: 1.作用域: LEGB 2.高阶函数 高阶函数是至少满足下列一个条件的函数: 1)接受一个或多个函数作为输入 2)输出一个函数 注意理 ...
- git rebase 的使用 (用于撤销某次commit)
Q: I wrote the wrong thing in a commit message. Alternatively, I've forgotten to include some files. ...
- Linux学习-Ubuntu 18.04-安装图文教程
Ubuntu(友帮拓.优般图.乌班图)是一个以桌面应用为主的开源GNU/Linux操作系统,Ubuntu 是基于Debian GNU/Linux,支持x86.amd64(即x64)和ppc架构,由全球 ...
- CodeForces 400A Inna and Choose Options
Inna and Choose Options Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on Cod ...