封装 ,继承 
 
封装 ?
面向对象有三大特性,封装、继承和多态。对于ES5来说,没有class(类)的概念,并且由于JS的函数级作用域(函数内部的变量在函数外访问不到),所以我们就可以模拟 class (类)的概念,在ES5中,类其实就是保存了一个函数的变量,这个函数有自己的属性和方法;将属性和方法组成一个类的过程就是封装。
那么,如果我们要把"属性"(property)和"方法"(method),封装成一个对象,甚至要从原型对象生成一个实例对象,我们应该怎么做呢?
 
原始模式
function Cat (name, color) {
return {
name: name,
color: color
}
}
var cat1 = Cat("大毛", "黄色");//{name: "大毛", color: "黄色"}
var cat2 = Cat("二毛", "黑色");//{name: "二毛", color: "黑色"}

这种模式并不能看出来 cat1 和 cat2 是同一个原型对象的实例

构造函数模式

为了解决从原型对象生成实例的问题,Js提供了一个构造函数(Constructor)模式。
所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量,对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上
 function Cat (name, color) {
  this.name = name;
  this.color = color;
   this.age = "5";
 }
 var cat1 = new Cat("大毛", "黄色");
 var cat2 = new Cat("二毛", "黑色");
cat1.constructor == Cat;//true
cat2.constructor == Cat; //true
cat1.constructor == cat2.constructor//true
JS 还提供了 instanceof 运算符,用来校验原型对象与实例对象的关系 
cat1 instanceof Cat ;// true
表面上好像没什么问题,但是实际上这样做,有一个小小的不优雅,那就是对于每一个实例对象,age属性都会生成一遍,每生成一个实例,都必须为重复的内容,多占用一些内存,这样既不环保,也缺乏效率。那么有办法解决吗 ? 答案当然是有的:
 
Prototype模式
Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上;
 function Cat (name, color) {
  this.name = name;
  this.color = color;
 }
Cat.prototype.age = "10";
 var cat1 = new Cat("大毛", "黄色");
 var cat2 = new Cat("二毛", "黑色");
cat1.age; // 10;
cat2.age; // 10;
这时所有实例的age属性,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率;
 
继承 ?
 
Prototype 原型继承

// 创建父构造函数
function SuperClass(name){
this.name = name;
this.showName = function(){
alert(this.name);
}
}
// 设置父构造器的原型对象
SuperClass.prototype.Age = '123';
// 创建子构造函数
function SubClass(){}
// 设置子构造函数的原型对象实现继承
SubClass.prototype = SuperClass.prototype;
//生成实例
var child = new SubClass() child.name // undefined
child.Age //
 
上述的Prototype模式已经实现了继承,但仅仅继承了父构造函数的prototype 原型上的成员,并不能继承父构造函数的其它成员,那么还有别的方法来实现继承嘛 ? 答案当然是有的;
 
原型链继承
 
//即 子构造函数.prototype = new 父构造函数()
// 创建父构造函数
function SuperClass(){
this.name = 'HiSen';
this.age = 25;
this.showName = function(){
console.log(this.name);
}
}
// 设置父构造函数的原型
SuperClass.prototype.friends = ['js', 'css'];
SuperClass.prototype.showAge = function(){
console.log(this.age);
}
// 创建子构造函数
function SubClass(){}
// 实现继承
SubClass.prototype = new SuperClass();
// 修改子构造函数的原型的构造器属性,因为此时继承了父构造函数指向 //SuperClass; 所以要修改一下。
SubClass.prototype.constructor = SubClass; //生成实例
var child = new SubClass();
console.log(child.name); // HiSen
console.log(child.age);//
child.showName();// HiSen
child.showAge();//
console.log(child.friends); // ['js','css'] // 当我们改变friends的时候, 父构造函数的原型对象的也会变化
child.friends.push('html');
console.log(child.friends);// ["js", "css", "html"] var father = new SuperClass();
console.log(father.friends);// ["js", "css", "html"]

此时再看:发现子构造函数 不仅继承了父构造函数原型 prototype 上的成员,也继承了其它成员。可是修改子构造函数的属性时,我们发现父构造函数的原型对象也对应修改,那有没有办法屏蔽这一种情况呢 ? 接着往下看:

拷贝实现继承

说到拷贝,可能会分深拷贝和浅拷贝,其实:

浅拷贝是对象的属性的引用,而不是对象本身; (浅拷贝只拷贝一层,如果存在多层还是会影响原对象)

深拷贝是创建一个新的内存地址保存值 ; (与原对象互不影响)

下边我列举两个拷贝的方法来实践一下:

浅拷贝

例举一个简单的浅拷贝: 对象形式

function clone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}

深拷贝

对象形式的深拷贝

function clone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
if (typeof source[i] === 'object') {
target[i] = clone(source[i]); // 注意这里
} else {
target[i] = source[i];
}
}
} return target;
}

数组形式的深拷贝

function clone(source) {
var out = [],i = 0,len = source.length;
for (; i < len; i++) {
if (source[i] instanceof Array){
out[i] = clone(arr[i]);
}
else out[i] = source[i];
}
return out;
}

 

当然出了以上这些实现继承的方法以外还有更多的方式同样可以实现继承,例如:

Object.create();继承

ECMAScript 5 中引入了一个新方法:Object.create()。可以调用这个方法来创建一个新对象。新对象的原型就是调用 create 方法时传入的第一个参数:
 
Object.create()方法接受两个参数:Object.create(obj,propertiesObject) ;
obj:一个对象,应该是新创建的对象的原型。
propertiesObject:可选。该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,值是属性描述符(这些属性描述符的结构与Object.defineProperties()的第二个参数一样)。注意:该参数对象不能是 undefined,另外只有该对象中自身拥有的可枚举的属性才有效,也就是说该对象的原型链上属性是无效的。

var obj = {
"a":'123',
fun :function () {
alert(1)
}
}

var jc = Object.create(obj); jc.a; //123
jc.fun();//1

我们可以看到,jc 继承了 obj 的属性;同时也继承了 obj 对象的方法;

ES6钟提供了一个方法 Object.assign();

Object.assign是ES6的新函数。Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。

Object.assign(target, ...sources)

target:目标对象。
sources:任意多个源对象。

var obj = { a: {a: "hello", b: 21} };
var initalObj = Object.assign({}, obj); initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"

最后再说一种最简单的方式,转成字符串 - 再转回来;

var obj1 = { o: { a: 1 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
 
ECMAScript6 引入了一套新的关键字用来实现 class。使用基于类语言的开发人员会对这些结构感到熟悉,但它们是不同的。JavaScript 仍然基于原型。这些新的关键字包括 class, constructor,static,extends 和 super。敬请期待...

 
 

Js 面向对象之封装,继承,原型,原型链的更多相关文章

  1. 原生JS面向对象思想封装轮播图组件

    原生JS面向对象思想封装轮播图组件 在前端页面开发过程中,页面中的轮播图特效很常见,因此我就想封装一个自己的原生JS的轮播图组件.有了这个需求就开始着手准备了,代码当然是以简洁为目标,轮播图的各个功能 ...

  2. JS面向对象(封装,继承)

    在六月份找工作中,被问的最多的问题就是: js面向对象,继承,封装,原型链这些,你了解多少? 额,,,我怎么回答呢, 只能说,了解一些,不多不少,哈哈哈哈,当然,这是玩笑话. 不过之前学过java,来 ...

  3. JS高级---逆推继承看原型

    逆推继承看原型 function F1(age) { this.age = age; } function F2(age) { this.age = age; } F2.prototype = new ...

  4. 用js面向对象思想封装插件

    js是基于原型的面向对象语言,如果你学过java,c#等正统面向对象语言,你会难以理解js的面向对象,他和普通的面向对象不太一样,今天,我们通过封装一个toast插件,来看看js面向对象是如何运行的. ...

  5. 从零开始的全栈工程师——JS面向对象( 六大继承 )

    一.对象克隆 var obj = { name:'li', age:23 } var obj2 = obj; // 这不是对象克隆 只是把obj的内存地址给obj2 1.for in克隆(浅拷贝)  ...

  6. java面向对象(封装-继承-多态)

    框架图 理解面向对象 面向对象是相对面向过程而言 面向对象和面向过程都是一种思想 面向过程强调的是功能行为 面向对象将功能封装进对象,强调具备了功能的对象. 面向对象是基于面向过程的. 面向对象的特点 ...

  7. objective-c自学总结(三)---面向对象的封装,继承与多态

    面向对象的三大特性 封装 继承 多态 1.封装: 隐藏属性,方法或实现细节的过程称为封装 信息隐藏,隐藏对象的实现细节,不允许用户看到 将东西包装在一 然后以新的完整形式呈现出来 例如,两种或多种化学 ...

  8. JavaScript 对象的原型扩展(JS面向对象中的继承)

    <script type="text/javascript"> function person(name, age) { this._name = name; this ...

  9. 实例了解js面向对象的封装和继承等特点

    1.面向对象特点 相比之前按照过程式写法,面向对象有以下几个特点; 1.抽象:抓住核心问题,就是将很多个方法放在一个对象上.对象由属性和方法组成,属性就是我们定义的变量,它是静态的:方法就是行为操作, ...

随机推荐

  1. 微服务与DevOps关系

    随着IT技术的不断发展,从传统的IT建设模型逐步向新型IT建设模型过渡,建设模式的改变,必然影响应用系统的全生命周期.应用系统的建设经过单体应用.SOA应用.逐步走向微服务应用,至于何为单体应用.SO ...

  2. Intellij IDEA run coverage之覆盖率测试

    Intellij IDEA run coverage之覆盖率测试 idea 的coverage + 我们自己写的测试用例.最后看一下,我们要测的代码有没有测试到,这是一个不错的提高代码质量的方法. i ...

  3. Maven 项目管理从未如此通畅

    一,写在前面 Maven到底是什么?它能做些什么?能为我们的开发工作提供什么样的帮助?为什么会有如此大的知名度?另外,常听大厂的人说“私服”,工具管理吧啦吧啦的一堆也是不明觉厉.相信仁者见仁,着智者见 ...

  4. 列表 enumerat 解包, 针对索引和元素

    dic = [1,2,3,4,5] for a,b in enumerate(dic): print(a,b) # a就是索引 b是元素

  5. MySql基本学习知识点:

    1.Mysql的简介: (1):常识: MySQL是一种关系数据库管理系统,是一种开源软件 由瑞典MySQL AB公司开发,2008年1月16号被Sun公司收购.2009年,SUN又被Oracle收购 ...

  6. Fatal error: Call to undefined function curl_init()解决办法

    问题描述: 在Windows SERVER 2012RC 64 bit OS, php 5.6.3的环境下,搭建好了php运行环境.但是在调用 curl_init() 方法时却报错了. 检查了一下,p ...

  7. 移动端h5实现拍照上传图片并预览&webuploader

    .移动端实现图片上传并预览,用到h5的input的file属性及filereader对象:经测除了android上不支持多图片上传,其他基本ok实用: 一:先说一下单张图片上传(先上代码): html ...

  8. C# 2个List<T>比较内部项是否相等(全部相等则相等,反之不相等)

    static void Main(string[] args) { List<string> a = new List<string>() { "a", & ...

  9. 【Python】Java程序员学习Python(二)— 开发环境搭建

    巧妇难为无米之炊,我最爱的还是鸡蛋羹,因为我和鸡蛋羹有段不能说的秘密. 不管学啥,都要有环境,对于程序员来说搭建个开发环境应该不是什么难题.按顺序一步步来就可以,我也只是记录我的安装过程,你也可以滴. ...

  10. zookeeper应用 - FIFO 队列 分布式队列

    使用ZooKeeper实现的FIFO队列,这个队列是分布式的. package fifo; import java.util.Collections; import java.util.List; i ...