大家好,今天我带大家学习一下js的OOP,

大家都知道,面向对象有三个基本特征,继承,封装和多态,面向对象的语言有那么几种,C++,PHP,JAVA等,而功能强大的JS可以模拟实现面向对象的两大特征,继承,和封装,无法实现多态,所以当有人对问你,js是一门面向对象的语言,你应该反驳他,js是一门基于对象的语言,不是面向对象,他就会觉得你很有学问。哈哈!

首先,我们学习一下,什么是对象呢,那就先了解一下类和对象是什么?

1、类:一类具有相特征(属性)和行为(方法)的集合
eg:人类--->属性,身高,体重,性别,方法:吃饭,说话,走路
2、对象:从类中,拿出具有确定属性值和方法的个体。
eg:张三--->属性,身高180 体重180,方法:说话-->我叫张三,身高180

大家知道什么是类什么是对象了吗?

两者有什么关系呢?

类是抽象的,对象是具体的,类是对象的抽象化,对象是类的具体化
类是一个抽象的概念只能说类有属性和方法,但是不能给属性附具体的值,
对象是一个具体的个例,是将类中的属性,进行具体赋值而来的个体
eg:张三是人类的一个个体,可以说张三的姓名叫张三,也就是张三对人类的每一个属性进行了具体的赋值,那么张三就是由人类产生的一个对象。

是不是通俗易懂呢。

下面我来使用一下类和对象:

首先创建一个类,这里要注意的是,类名必须使用大驼峰法则,即每一个单词的首字母都要大写,这是我说知道唯一一个使用大驼峰法则的地方

方法:

function 类名(属性1){
this.属性1=属性1;
this.方法=function(){
方法中要调用自身属性,必须使用this.属性。
}
}

function Person(name,age){
this.name=name;
this.age=age;
this.say=function(content){
//在类中,要访问类自身的属性,必须使用this,属性调用。
alert("我叫"+this.name+",今年"+this.age+"了!"+content);
}
}

这样我们就创建好了一个类

下面我们实例化出一个对象,

通过 obj=new类名(属性1的具体值);
obj.属性;调用属性
obj.方法();调用方法

var zhangsan = new Person("张三",18);

下面我们要学习一下三个属性和三个方法

【成员属性和成员方法】
1、在构造函数中,使用this.属性声明。或者在实例化出对象以后,使用“对象.属性追加的,都属于成员属性或成员方法”。也叫实例属性,和实例方法。
成员属性和方法是属于由类new出的对象的。需要使用“对象名.属性名”调用。

【静态属性与静态方法】
2、 通过“类名.属性”、“类名.方法”声明的属性和方法,称为静态属性,静态方法。也就类属性和类方法:

类属性/类方法,是属于类的(属于构造函数的)
通过“类名.属性名”调用

3、成员属性时属于实例化出的对象的,只能使用对象调用。
静态属性时属于构造函数的,只能使用类名调用。

【私有属性和私有方法】
4、在构造函数中,使用var声明的变量称为私有属性;
在构造函数中,使用function声明的函数,称为私有方法;
function Person(){
var num = 1;//私有属性
function func(){}//私有方法
}
私有属性和私有方法的作用域,只能在构造函数内容有效,即,只能在构造函数内部使用,在构造函数外部,无论使用对象名还是类名都无法调用。

举个栗子,

function Person(name){
this.name=name;//声明成员属性
var sex = "男";
this.satTime=function(){
alert("说出当前时间是"+getTime());
}
this.writeTime = function(){
alert("我写了当前时间是"+getTime());
}
function getTime(){
return new Data();
} }
var zhangsan = new Person("张三");
zhangsan.age = 14;//追加成员属性 //alert(zhangsan.age);//调用成员属性
Person.count = "60亿";//声明静态属性
console.log(Person.count);//调用静态属性
var lisi = new Person("李四");
console.log(lisi.count);//undefined 静态属性时属于类的,只能用类名调用
console.log(lisi.sex);
console.log(Person.sex);

通俗易懂的,好了下面我们重点来了,就是标题的两大内容之一,封装

  封装

1、 什么叫封装?
① 方法的封装: 将类内部的函数进行私有化处理,不对外提供调用接口,无法在类外部使用的方法,称为私有方法,即方法的封装。
② 属性的封装: 将类中的属性进行私有化处理,对外不能直接使用对象名访问(私有属性)。 同时,需要提供专门用于设置和读取私有属性的set/get方法,让外部使用我们提供的方法,对属性进行操作。 这就叫属性的封装。
2、 注意: 封装不是拒绝访问,而是限制访问。 要求调用者,必须使用我们提供的set/get方法进行属性的操作,而不是直接拒绝操作。
因此,单纯的属性私有化,不能称为封装!必须要私有化之后,提供对应的set/get方法。

上面是知识点,大家知道了吗,简单的讲,就是将属性保存起来,只让用户通过提供的方法去访问,修改数据,当然,如果你是前端高手,你就可以无视,直接修改源码。这当然是外话了 --!!

下面我们来一段实例代码,让你们感受下封装的过程

function Person(name, age1) {
this.name = name;
// this.age = age;
var age = 0;
this.setAge = function(ages) {
if(ages > 0 && ages <= 120) {
age = ages;
} else {
alert("年龄赋值失败!");
}
}
// 当实例化类拿到对象时,可以直接通过类名的()传入年龄,设置私有属性
if(age1 != undefined) this.setAge(age1);
this.getAge = function() {
  return age;
}
//私有化的方法,只能在类内部被其他方法调用,而不能对外提供功能。 这就是方法的封装! function getTime() {
return new Date();
}
}
// var zhangsan = new Person("张三");
// zhangsan.setAge(99);
// alert("张三的年龄是:"+zhangsan.getAge()); var lisi = new Person("李四", 999);
//lisi.setAge(110);
alert("李四的年龄是:" + lisi.getAge()); function Person(){
var age = 0;
this.getAge=function(){
return age;
}
this.setAge=function(age1){
age = age1;
}
function func(){}
}

封装其实很简单,当我们把属性封装起来之后,我们就不能直接访问类的私有属性,我们只可以通过getAge(),setAge()访问设置age属性,这样就模拟实现了第一个功能,封装,

继承

等等,我忽略了一个重要的问题,那就是this指向问题,大家可能问上面我们出现了this,this到底是什么呢,现在我们详细解释一下

简单来说

1、谁最终调用这个函数,this就指向谁!
①this指向谁,不应该考虑函数在哪里声明,应该考虑函数在哪里调用;
②this指向的永远只可能是对象,不可能是函数;
③this指向的对象,叫做函数的上下文,也叫函数的context;也叫函数的调用者。

2、this指向的规律!!!(跟函数的调用方式息息相关)
①通过函数名()调用的this永远指向window;
②通过对象.方法调用的,this指向这个对象;
③函数作为数组中一个元素,通过数组下标调用的,this指向这个数组;
④函数作为window内置函数的回调函数使用;this指向window;
setInterval setTimeout 等
⑤函数作为构造函数时new关键字调用,this指向新new出的对象。

以上是我所总结的this指向,this也就这几中情况了,其他还没遇到过,如果有其他,请大佬在评论告诉我,先谢了,

在举个栗子

    var fullname = 'John Doe';
var obj = {
fullname: 'Colin Ihrig',
prop: {
fullname: 'Aurelio De Rosa',
getFullname: function() {
return this.fullname;
}
}
};
console.log(obj.prop.getFullname());
// 函数的最终调用者 obj.prop var test = obj.prop.getFullname;
console.log(test());
// 函数的最终调用者 test() this-> window obj.func = obj.prop.getFullname;
console.log(obj.func());
// 函数最终调用者是obj var arr = [obj.prop.getFullname,1,2];
arr.fullname = "JiangHao";
console.log(arr[0]());
// 函数最终调用者数组

吃了这个栗子,是不是清楚多了,不要被歪的所迷惑,你就找谁最终调用了这个函数就行,

然后是原型和原型链,这个是很重要的知识点,大家一定要掌握好,因为继承需要准备很多知识点,大家耐心学完,

【__proto__与prototype】
1、prototype,函数的原型对象;
①只有函数才有prototype,而且所有函数,必有prototype
②prototype本身也是一个对象!
③prototype指向了当前函数所在的引用地址!

2、__proto__:对象的原型
①只有对象才有__proto__,而且所有对象必有__proto__
②__proto__也是一个对象,所以也有自己的__proto__,顺着这条线向上找的顺序,就是原型链
③函数、数组都是对象,都有自己的__proto__;

3、实例化一个类,拿到对象的原理?
实例化一个类,实际上是将新对象的__proto__,指向构造函数所在的prototype。
也就是说:zhangsan.__proto__==Person.prototype √

4、所有对象的__proto__延原型链向上查找,都将指向Object的prototype
Object的prototype的原型,指向null

【原型链的指向问题】
研究原型链的指向,就是要研究各种特殊对象的__proto__的指向问题。
1、通过构造函数,new出的对象。新对象的__proto__指向构造函数的prototype
2、函数的__proto__,指向了function()的prototype
3、函数的prototype的__proto__指向Object的prototype
(直接使用{}字面量声明。或使用new Object拿到的对象的__proto__ 直接指向Object的prototype)
4、Object的prototype的__proto__,指向null
Object作为一个特殊函数,他的__proto__指向function()的prototype

这是点先放这里了解释的很清楚,大家看了之后就清楚原型了,继承就需要几个知识点而已,

一、扩展Object实现继承

     ①声明父类
function Parent(){}
声明子类
function Son(){}
②通过prototype给object类添加一个扩展方法:
Object.prototype.extend=function(parent){
for(var i in parent){
this[i]=parent[i];
}
}
③分别拿到父类对象,和子类对象;
var p = new Person();
var s = new Student();
④用子类对象,调用扩展方法,实现继承操作;
s.extend(p);
3、实现继承的原理:
通过循环,将父类对象的所有属性和方法全部付给子类属性,关键点在for-in循环,即使不扩张object,也能通过简单的循环实现操作
4、扩展Object继承的缺点,
①,无法通过一次实例化,直接拿到完整的子类对象,而需要先拿到父类对象和子类对象两个对象,在手动合并
②扩展Object的继承方法,也会保留只在子类的对象上
/**/
function Person(name,age){
this.name = name;
this.age = age;
this.say = function(){
alert("我叫"+this.name);
}
} function Student(no){
this.no = no;
this.Study = function(){
alert("我在学习!");
}
} Object.prototype.extend1 = function(parent){
for(var i in parent){
this[i]=parent[i];
}
}
var p = new Person("张三",12);
var s = new Student("123456");
s.extend1(p);
console.log(s);

扩展继承我感觉很简单,以后要用的时候,只需要拿出扩展的extend1方法,就可以继承了,这个名字大家不要抄啊,可以.a.b都行,高兴就好

二 使用原型实现继承

     ①定义父类:
function Parent(){}
定义子类:
function Son(){}
②将父类对象,赋值给子类的prototype
son.prototype = new Person();
③拿到子类对象,就会将父类对象的所有属性和方法,添加到__proto__
var s = new Son();
使用原型继承的原理:
将父类对象,赋值给子类的prototype,那么父类对象的属性和方法就会出现在子类的prototype中。那么。实例化子类时,子类的prototype又回到子类对象的__proto__中,最终,父亲对象的属性和方法,会出现在子类的对象的__proto__中;
这种继承的特点
①子类自身的所有属性,都是成员属性,父类继承过来的属性,都是原型属性;
②依然无法通过一步实例化拿到完整的子类对象。
        function Person(name,age){
this.name = name;
this.age = age;
this.say = function(){
alert("我叫"+this.name);
}
}
function Student(no){
this.no = no;
this.Study = function(){
alert("我在学习!");
}
} Student.prototype = new Person("zhangsan",14);
var s = new Student();
console.log(s);

原型继承是比较简单的,子类的Prototype指向父类new的对象,就可以实现继承啦!

三,

[call/bind/apply]
1、三个函数的作用:通过函数名调用着三个函数,可以强行将函数中的this指定为某个对象。
2、三个函数的写法(区别):
call写法:func.call(func的this指向的obj,func参数1,func参数2,...);
apply写法:func.apply(func的this指向的obj,[func参数1,func参数2,...]);
bind写法:func.bind(func的this指向的obj)(func参数1,func参数2,...);
3、三个函数的唯一区别,在与接受func的参数列表的方式不同,除此之外,功能上没有任何差异!!

[使用call/bind/apply实现继承]
1、实现步骤:
①定义父类
function Perent(name){}
②定义子类时,在子类中使用三个函数,调用父类,将父类函数的this,指向为子类函数的this:
function Son(no,name){
this.no=no;
Person,call(this,name);
}
③实例化子类时,将自动继承父类属性,
var s = new Son(12,"zhangsan")

function Person(name,age){
this.name = name;
this.age = age;
this.say = function(){
alert("我叫"+this.name);
}
}
function Student(no){
this.no = no;
this.study=function(){
alert("我在学习");
}
Person.call(this.name,age);
}
var s =new Student(12,"张三",24);
console.log(s);

以上就是js的继承和封装,多态是无法实现的,上面两个方法在实际运用中能起到很不错的效果,让我们少码很多字,

今天就到这里,谢谢大家

JS中OOP之模拟封装和继承和this指向详解的更多相关文章

  1. java 学习笔记——类之间的关系之封装、继承与多态的详解

    封装 一个封装的简单例子 封装就是把对象的属性(状态)和方法(行为)结合在一起,并尽可能隐蔽对象的内部细节,成为一个不可分割的独立单位(即对象),对外形成一个边界,只保留有限的对外接口使之与外部发生联 ...

  2. C++的三大特性:封装、继承和多态性的详解

    封装 所谓封装就是将某些东西包装盒隐藏起来,让外界无法直接使用,只能通过某些特定的方式才能访问.封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是通过外部接口以及特定的访问权限来使 ...

  3. Js中的window.parent ,window.top,window.self ,window.openner详解

    在应用有frameset或者iframe的页面时,parent是父窗口,top是最顶级父窗口(有的窗口中套了好几层frameset或者iframe),self是当前窗口, opener是用open方法 ...

  4. js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解

    1 escape()函数 定义和用法 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法 escape(string) 参数 描述 string 必需.要被转义或 ...

  5. js中OOP小指南

    js中OOP小指南 在指南中,我将尝试解析以面向对象规范聚焦的es6的新特性. 首先, 什么是设计模式 范例是某个事务的例子或模型,在某种情况下,按照一种模式创建了计算机程序. 什么是面向对象 显然你 ...

  6. koa 基础(十七)原生 JS 中的类、静态方法、继承

    1.app.js /** * 原生 JS 中的类.静态方法.继承 * es5中的类和静态方法 */ function Person(name, age) { // 构造函数里面的方法和属性 this. ...

  7. 面向对象(OOP)--OOP基础与this指向详解

      前  言            学过程序语言的都知道,我们的程序语言进化是从“面向机器”.到“面向过程”.再到“面向对象”一步步的发展而来.类似于汇编语言这样的面向机器的语言,随着时代的发展已经逐 ...

  8. java中4种修饰符访问权限的区别及详解全过程

    java中4种修饰符访问权限的区别及详解全过程 http://jingyan.baidu.com/article/fedf0737700b3335ac8977ca.html java中4中修饰符分别为 ...

  9. 《手把手教你》系列基础篇(九十七)-java+ selenium自动化测试-框架设计篇-Selenium方法的二次封装和页面基类(详解教程)

    1.简介 上一篇宏哥介绍了如何设计支持不同浏览器测试,宏哥的方法就是通过来切换配置文件设置的浏览器名称的值,来确定启动什么浏览器进行脚本测试.宏哥将这个叫做浏览器引擎类.这个类负责获取浏览器类型和启动 ...

随机推荐

  1. 201521123030 《Java程序设计》 第13周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...

  2. cityEngine入门(实现数据的预处理以及cityEngine的3维显示)

    一.  实验要求 1.     提供数据: 中田村两个图幅影像数据 DEM提供包含高程数值的文本和矢量数数据 完成内容: 实现中田村两个图幅的拼接,生成一个影像数据(Image.tif) 将DEM数据 ...

  3. Lucene第一篇【介绍Lucene、快速入门】

    什么是Lucene?? Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引 ...

  4. birt IE8 IE9 兼容问题

    我自己的应用,birt展示报表的时候,在firefox和IE下显示的样式: IE8下的: Firefox下的: 我的项目,应用birt部分的结构如下: 1, prototype.js ,查找下面这段代 ...

  5. hibernate中Query的list和iterator区别(续)

    打开cache后query的list和iterator方法区别 将query 的cache打开的话,缓存的是query本身,以hql 生成的 sql ,再加上参数,分页等信息做为key值,而不是que ...

  6. virtualbox修改主机名

    virtualbox修改主机名 /etc/hostname /etc/hosts

  7. DelayQueue使用示例之KTV包厢记时

    在学习Java 多线程并发开发过程中,了解到DelayQueue类的主要作用:是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走. ...

  8. 微信bug:建议了解,不要实验,不要手贱,不要。。。。

    今天下午在群里聊天的时候,群友反应发现微信的一个bug:使用微信给好友发送‘15...............’(数字15后面加15个句号)会导致微信运行缓慢,到最后的应用未响应,退出微信. 解决办法 ...

  9. Redis常见的应用场景解析

    Redis是一个key-value存储系统,现在在各种系统中的使用越来越多,大部分情况下是因为其高性能的特性,被当做缓存使用,这里介绍下Redis经常遇到的使用场景. Redis特性 一个产品的使用场 ...

  10. Writing Science 7.10 (The Opening and The Funnel)

    Opening: 1.文章的第一句话必须要达到如下目标:找出推动研究的问题,介绍内容,并确定本文针对的观众.如果你足够聪明的话甚至可以将遇到的挑战以及结论写进来. 2.通过第一段话建立本文的重点和基调 ...