大家好,今天我带大家学习一下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. 201521123060 《Java程序设计》第13周学习总结

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

  2. 201521123092《java程序设计》第十三周学习总结

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

  3. 三分钟深入TT猫之故障转移

    结束了一周繁忙的工作,趁着周末,小编手中的键盘早已饥渴难耐了,想知道上期省略号中发生了什么有趣的故事么?且听小编娓娓道来,结尾有彩蛋. 目录 风月前场 梦回现实 模拟老鸨 会话机制 故障转移 总结 风 ...

  4. HTTP请求的header头解析

    Request Headers: 下图是我访问一个URL:http://www.hzau.edu.cn的一个header,根据具体实例来分析一下各部分的功能及其作用. Accept 作用: 浏览器端可 ...

  5. 再起航,我的学习笔记之JavaScript设计模式24(备忘录模式)

    备忘录模式 概念介绍 备忘录模式(Memento): 在不破坏对象的封装性的前提下,在对象之外捕获并保存该对象内部的状态以便日后对象使用或者对象恢复到以前的某个状态. 简易分页 在一般情况下我们需要做 ...

  6. thinkphp5.0无限极分类及格式化输出

    首先我们来看数据表 从上图中可以发现,中国下有贵州,北京两个子节点,而北京有天安门一个子节点,纽约的子节点是"纽约的子类". 从pid为0看出,中国和纽约是顶级节点. 因为贵州的p ...

  7. es6函数的rest参数和拓展运算符(...)的解析

    es6的新特性对函数的功能新增加了rest参数和...的拓展运算符.这是两个什么东西呢? 先来看一个问题:如何获取一个函数除了定义的参数之外的其他参数?传统的做法是借助函数的arguments关键字来 ...

  8. C#设计模式之五创建者模式(Builder)【创建型】

    一.引言  今天我们要讲讲Builder模式,也就是建造者模式,当然也有叫生成器模式的.在现实生活中,我们经常会遇到一些构成比较复杂的物品,比如:电脑,它就是一个复杂的物品,它主要是由CPU.主板.硬 ...

  9. OpenVPN server端配置文件详细说明(转)

    本文将介绍如何配置OpenVPN服务器端的配置文件.在Windows系统中,该配置文件一般叫做server.ovpn:在Linux/BSD系统中,该配置文件一般叫做server.conf.虽然配置文件 ...

  10. Canal 同步异常分析:Could not find first log file name in binary log index file

    文章首发于[博客园-陈树义],点击跳转到原文Canal同步异常分析:Could not find first log file name in binary log index file. 公司搜索相 ...