js面向对象设计之function类

/*本文并非是介绍JavaScript的原型的原理的文章,
**仅仅讨论function作为类来使用时如何近似传统的面向对象设计
**/

/*function作为类的用法
**下面是一个最简单的类
**实例将有自己的属性val和pVal,也有方法printVal和pMethod
**/

function Class01( val, pVal )
{
    this.val = val; /*实例可直接读写的属性*/

    var pVal = pVal; /*实例无法直接读写的属性*/
}

Class01.prototype.printVal = function ()
{
    var _this = this;

    /*尽管此处并不会出现this丢失的情况,但推荐总是这么做*/
    console.log( _this.val );
};

/*实例可直接读写的属性和方法不再多说
**对于不可直接读写的属性pVal(这是传统面向对象语言中的私有属性)
**需要通过公有接口来访问pVal,如下面的getpVal和setpVal
**这样做的弊端十分明显,每一个实例都将拥有getpVal和setpVal
**是否可以在原型上定义getpVal和setpVal,先来试试
**/

function Class01( val, pVal )
{
    this.val = val; /*实例可直接读写的属性*/

    var pVal = pVal; /*实例无法直接读写的属性*/

    this.getpVal = function ()
    {
        return pVal;
    };

    this.setpVal = function ( v )
    {
        pVal = v;
        return this;
    }
}

/*下面的例子是通过原型方法读取“私有”属性pVal
**试过发现,运行报错,pVal并不存在
**路子都被堵死了,采用这种方式定义“私有”属性将只能通过实例方法读写
**这种方式显然不能在工程中使用,下面介绍另外一种方法
**/

function Class01( val, pVal )
{
    this.val = val; /*实例可直接读写的属性*/

    var pVal = pVal; /*实例无法直接读写的属性*/
}

Class01.prototype.printVal = function ()
{
    var _this = this;

    /*尽管此处并不会出现this丢失的情况,但推荐总是这么做*/
    console.log( _this.val );
};

Class01.prototype.getpVal = function ()
{
    console.log( pVal );
};

var ins01 = new Class01( 1, 2 );

ins01.getpVal(); /*此处报错*/

/*采用高阶函数的方式,return Class的方式
**在Class01的内部只定义可直接读写的属性
**把“私有”属性或方法放到Class作用域外部
**/

var Class01 = ( function ()
{
    var pValue = ‘‘; /*实例无法直接读写的属性*/

    function hello ()
    {
        console.log( ‘欢迎来到nDos的博客‘ );
    }

    function Class( val, pVal )
    {
        this.val = val; /*实例可直接读写的属性*/

        pValue = pVal;
    }

    Class.prototype.printVal = function ()
    {
        var _this = this;

        /*尽管此处并不会出现this丢失的情况,但推荐总是这么做*/
        console.log( _this.val );
    };

    Class.prototype.getpVal = function ()
    {
        console.log( pValue );

        return pValue;
    };

    Class.prototype.setpVal = function ( v )
    {
        pValue = v;

        return this;
    };

    Class.prototype.sayHello = function ()
    {
        hello();

        return this;
    };

    return Class;
} )();

var ins01 = new Class01( 1, 2 );

ins01.getpVal();

ins01.setpVal( ‘2222‘ ).getpVal();

ins01.sayHello();

/*小问题:
**实例ins01是由Class实例化而来
**还是由Class01实例化而来
**读者可先自行思考
**/

console.log( ins01.constructor.name ); /*此处是Class*/

/*Class01这个变量在ins01中找不到任何的痕迹
**想要搞清楚可能需要到JS引擎中去找
**本文目的显然并不是要搞清楚这个问题,留给读者研究或者持续关注本博客
**console.log( ins01 )
**在Google的开发者工具中找到如下的属性
**Class.__proto__.constructor["[[Scopes]]"]
**Google工具显示了与Class有关的闭包,在内部可以看到pValue和hello()
**显然Class在全局作用域中也不存在
**/

/*该类已经实现的内容有
**公有、私有属性和方法、原型方法
**至于公有方法,实例化之后在定义
**对于工程化来讲,私有属性和方法这么写维护会很困难
**可以将私有属性和方法都放到object中方便维护
**var pV = { pVal:‘‘, hello:()=>console.log(‘ok‘) }
**/

/*类还有静态方法和静态属性
**通过Class.staticVal和Class.staticMethod来定义
**原型上也可以定义属性,该属性被所有的实例所共享
**原型上的属性只能是引用(array和object)时,才能被存储
**/

var Class01 = ( function ()
{
    /*代码略*/

    Class.prototype.nDos = {

        name: ‘nDos‘,

        sayHello: hello
    };

    Class.prototype.noChangeVal = ‘实例拿我没办法‘;

    Class.staticVal = ‘Class的静态属性‘;

    Class.staticMethod = function ()
    {
        console.log( ‘Class的静态方法‘ );
    };

    return Class;
} )();

var ins01 = new Class01( 1, 2 ),
    ins02 = new Class01( ‘a‘, ‘b‘ );

ins01.nDos.name = ‘ins01 say hello nDos‘; /*对于数组也是一样的*/

console.log( ‘ins02中的name值:‘ + ins02.nDos.name );

try {
    ins01.noChangeVal = ‘实例1改变原型属性值‘;

    console.log( ins01.noChangeVal );

    console.log( ins02.noChangeVal );

    ins01.prototype.noChangeVal = ‘我就是想改变它‘; /*报错*/

} catch ( e ) {

    console.Error( e );
}

/*Class的静态属性和方法都可以在Class01上找到
**原型上的属性通过上述的了解也学习过了
**是时候来一波总结
**并不是总结学习了什么,而是思考可以用来干什么
**以及其中可能存在的缺陷
**/

/*总结
**1、静态属性和原型属性,都可以用来储存实例化次数
** 同样也可以用来储存每个实例的引用
此处建议将实例化次数和对实例的引用都储存在静态属性中
因为原型属性在编程过程中
并不容易分清楚它究竟是原型属性还是实例属性
**2、显然,function也是可以被当作函数而执行
** 避免这种情况,需要加入防御性代码
if ( this.constructor.name !== ‘Class‘ )
{
throw new Error( ‘类只能被实例化‘ );
}
** 就算这么做了,还是可以绕过去,比如
function fakeClass () {
Class01.call(this, ‘1‘, ‘2‘);
}
fakeClass.prototype = Class01.prototype;
var ins = new fakeClass();
** 当然这也可以算是继承的一种
**3、为避免2中出现的情况,就是加入以下代码
if ( !new.target || new.target.name !== ‘Class‘ )
{
throw new Error( ‘类只能被实例化‘ );
}
**4、只有函数才能被实例化
实例化之后得到的变量是实例并不是函数或者说是object
**5、function类实例化过程,实际上是函数体的执行过程
这个执行过程也就是初始化的过程
在这种过程当中可以做相当多的事情
上述的防御性代码
实例(this)的传递与储存
使用Object.create给this扩充功能(Mixin)
加入钩子函数,让类消费者自行决定如何实例化
**6、function类一般不会有return当然也可以存在
这也是实例化的变化所在
通过不同的钩子从而决定返回什么样的实例
希望下一篇能学懂并讲解这种方式
这种实例化方式与多态继承等也有关系
**/

/*function与类的学习希望对你有帮助
**下篇文章介绍Class(ES2015新语法)与类
**最后附上最终的Class源代码
**/

var Class01 = ( function ()
{
    var pValue = ‘‘; /*实例无法直接读写的属性*/

    function hello ()
    {
        console.log( ‘欢迎来到nDos的博客‘ );
    }

    function Class( val, pVal )
    {
        if ( this.constructor.name !== ‘Class‘ )
        {
            throw new Error( ‘类只能被实例化‘ );
        }

        if ( !new.target || new.target.name !== ‘Class‘ )
        {
            throw new Error( ‘类只能被实例化‘ );
        }

        this.val = val; /*实例可直接读写的属性*/

        pValue = pVal;
    }

    Class.prototype.printVal = function ()
    {
        var _this = this;

        /*尽管此处并不会出现this丢失的情况,但推荐总是这么做*/
        console.log( _this.val );
    };

    Class.prototype.getpVal = function ()
    {
        console.log( pValue );

        return pValue;
    };

    Class.prototype.setpVal = function ( v )
    {
        pValue = v;

        return this;
    };

    Class.prototype.sayHello = function ()
    {
        hello();

        return this;
    };

    Class.prototype.nDos = {

        name: ‘nDos‘,

        sayHello: hello
    };

    Class.prototype.noChangeVal = ‘实例拿我没办法‘;

    Class.staticVal = ‘Class的静态属性‘;

    Class.staticMethod = function ()
    {
        console.log( ‘Class的静态方法‘ );
    };

    return Class;
} )();

var ins01 = new Class01( 1, 2 ),
    ins02 = new Class01( ‘a‘, ‘b‘ );

ins01.nDos.name = ‘ins01 say hello nDos‘; /*对于数组也是一样的*/

console.log( ‘ins02中的name值:‘ + ins02.nDos.name );

try {
    ins01.noChangeVal = ‘实例1改变原型属性值‘;

    console.log( ins01.noChangeVal );

    console.log( ins02.noChangeVal );

    /* ins01.prototype.noChangeVal = ‘我就是想改变它‘; 报错*/

} catch ( e ) {

    console.error( e );
}

function fakeClass()
{
    Class01.call( this, ‘1‘, ‘2‘ );
}

fakeClass.prototype = Class01.prototype;

var ins = new fakeClass();

原文地址:https://www.cnblogs.com/ndos/p/8127571.html

时间: 2024-11-07 01:14:59

js面向对象设计之function类的相关文章

javascript 面向对象设计之 Function 普通类

var test = "Class01"; function Class01(privateValue, publicValue) { var _this = this; if (this.constructor.name !== 'Class01') { throw new Error('类只能被实例化'); } /*统计实例化次数的自执行函数*/ (function newClass() { Class01.count++; /*统计实例化的次数*/ Class01.intance

java.面向对象设计的核心——类和对象

面向对象的三条学习主线 java类及类的成员 属性.方法.构造器:代码块.内部类 面向对象的三大特征 封装性.继承性.多态性(抽象性) 其他关键字 this.super.static.final.abstract.interface.package.import等 面向过程(POP)与面向对象(OOP) 二者都是一种思想,面向对象是相对于面向过程而言.面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做.面向对象,将功能封装进对象,强调具备功能的对象,以类/对象为最小单位,考虑谁来做. 面向

JS面向对象设计(1)-理解对象

不同于其他面向对象语言(OO,Object-Oriented),JS的ECMAScript没有类的概念, 它把对象定义为"无序属性(基本值.对象.函数)的集合",类似于散列表. 每个对象都是基于一个引用类型(原生类型.自定义类型)创建的. 1. 理解对象 创建自定义对象(Object构造函数.对象字面量). // Object构造函数:创建一个Object实例,再为实例添加属性和方法. var person = new Object(); person.name = "xia

JS面向对象设计-创建对象

Object构造函数和对象字面量都可以用来创建单个对象,但是在创建多个对象时,会产生大量重复代码. 1.工厂模式 工厂模式抽象了创建具体对象的过程.由于ECMAScript无法创建类,我们用函数来封装以特定接口创建对象的细节. function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function() { console.

js面向对象设计

1.对象   属性     方法    对象往往用名词来表示    方法一般都是些动词    属性值则往往是一些行容词 (例如:黑猫睡在我头上)猫为对象,黑为形容词,我头上为方法,睡为参数 2.类  类更多的是一个模板,而对象就是这些模板的基础上被创建出来的  (例如:老鹰属于鸟类) 3.封装    封装主要有两个部分组成 1.相关的数据(用于储存属性)2.基于这些属性所能做的事    封装还有隐藏信息的概念    如:public(公有)  private(私有) protected(受保护的

【JavaScript】 JS面向对象的模式与实践 (重点整治原型这个熊孩子 (/= _ =)/~┴┴ )

参考书籍 <JavaScript高级语言程序设计>—— Nicholas C.Zakas <你不知道的JavaScript>  —— KYLE SIMPSON 在JS的面向对象编程中,我们最为关注的是两种行为,一是创建对象,二是类继承 JS创建对象 构造函数模式创建对象 第一种创建对象的方式是构造函数模式 如下所示, 将构造函数中的属性和方法赋给一个新对象 /** * description: 构造函数模式创建对象 */ function Type (p) {   this.par

浅谈js面向对象与深入php面向对象

js面向对象: 类?什么是类?类是一些具有相同特征的对象的集合 什么是对象?就是具体到某一个事物了,都可以叫做对象 类,通过function定义类,在js里类的本质是函数 类和函数天生有两个属性,一个是prototype,一个是__proto__ prototype又是一个对象天生就有一个constructor的属性,属性值是函数和类本身 普通对象天生有一个__proto__的属性,这个属性是对象,指向它的父类 什么是原型链?原型链就是操作obj.属性的时候,首先看这个属性是私有的还是公有的,私

JS面向对象(3) -- Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法

相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对象之间的赋值,for...in语句,delete使用,成员方法,json对象的使用,prototype的使用,原型继承与原型链 JS面向对象(3) -- Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法 1.Object类 在JS中,Object是所有类的基

UML类图与面向对象设计原则

1. 引言 从大一开始学习编程,到如今也已经有两年了.从最初学习的Html,Js,JaveSe,再到JavaEE,Android,自己也能写一些玩具.学习过程中也无意识的了解了一些所谓的设计模式,如今打算系统的学习.学习以书<设计模式的艺术——软件开发人员内功修炼之道/刘伟著>为主. 所谓设计模式,即是前人对某类相似问题的抽象给出的解决方案.书中给出了23(Gof)+1(简单工厂模式)种设计模式.每种模式的学习将关注以下几点:名称(Name),问题(Problem),解决方案(Solution