JavaScript学习笔记-实例详解-类(一)

时间:2023-02-14 17:01:15
实例详解-类(一):
//每个javascript函数(除了bind())都自动拥有一个prototype对象
// 在未添加属性或重写prototype对象之前,它只包含唯一一个不可枚举属性constructor
// constructor的值是一个函数对象,指代函数对象自身(构造函数)
//原型对象是类的'唯一标识',而构造函数是类的'公共标识',因此这个constructor属性为对象提供了类
function Range(from,to){
this.from = from||0;
this.to = to||0;
}
console.log(Range.prototype.constructor); //[Function: Range] //未重写原型之前,它的constructor指代它自身
//==第一种方式:重写Range的原型对象prototype,若没有指定constructor属性,那么类将采用原型对象的默认原型Object类的constructor
Range.prototype = {
//====constructor:Range; //可以显式的给原型添加一个constructor构造函数,这里反向引用自身的构造函数
includes: function(x){return this.from<=x && x<=this.to;},
foreach: function(f){
for(var x = Math.ceil(this.from);x<=this.to;x++) f(x);
},
toString: function(){return '('+this.from+'...'+to+')';}
};
/*==第二种方式:除了显式的添加constructor,还可以使用预定义原型对象,它包含属性consturctor,然后逐个的给原型添加自定义的属性:
Range.prototype.includes = function(){...};
Range.prototype.foreach = function(){...};
Range.prototype.toString = functon(){...};
*/
var r = new Range(2,4);
console.log(r.constructor); //[Function: Object]
console.log(r.constructor === Object); //true //====这里的类F1和上面的类Range比较,
var F1 = function(){};
var p = {constructor:F1,a:1,b:2,c:function(){}}; //显式指定对象p的构造函数constructor为F1,若未指定则p.constructor===Object;
F1.prototype = p;
var p2 = new F1();
console.log(p2.constructor === p.constructor); //true 对象p2是类F1的实例,类F1重写了它的原型为对象p,所以对象p2继承了对象p的constructor;
console.log(p2.constructor === F1); //true
//====
var F2 = function(){};
//F2.sum = function(x,y){return x+y;}; //无效,不能直接为方法添加属性,只能通过它的原型对象为它添加属性
F2.prototype.sum = function(x,y){return x+y;};
var o = new F2();
console.log(o.constructor === F2); //true 因为F2使用自身的默认原型,它的constructor属性(构造函数)就是指代F2自身;
console.log(o.sum(1,2)); //3
//==========创建一个定义类的函数defineClass(函数式编程风格)=========================
function extend(o,p){ //定义一个复制对象属性的函数
for(var x in p){
o[x] = p[x];
}
return o;
}
function defineClass(constructor,methods,statics){ //该函数接收3个对象参数
if(methods) extend(constructor.prototype,methods); //添加所有实例属性
if(statics) extend(constructor,statics); //添加所有类属性
return constructor; //最后要返回构造函数
}
var Range1 = defineClass(
function(f,t){this.f=f;this.t=t;},
{
includes:function(x){return this.f<=x&&x<=this.t;},
toString:function(){return this.f+'...'+this.t;}
},
{
upto:function(t){return new Range1(0,t);}
}
);
var r3 = new Range1(5,7);
r3.includes(6);
console.log(r3.toString());
//==普通方法创建一个类:(调用时首先查找实例中是否直接定义了这个属性,有则返回实例属性;如果实例属性中没有就去构造函数中查找,有则返回;如果前面两者都没有就去原型对象中查找,如果没有则返回undefined)
//1.构造函数,定义对象属性
var Range2 = function(x,y){
if(isNaN(x)||isNaN(y)) throw new TypeError('not a number');
var self = this;
this.r = x;
this.i = y;
};
//2.原型属性(实例共享的属性、方法,通过实例对象来调用),也可将原型属性写进构造函数内动态的添加,但没创建一个实例就会执行一次,需要加判断是否已经创建;
Range2.prototype.add = function(that){return new Range2(this.r+that.r,this.i+that.i);};
Range2.prototype.mul = function(that){return new Range2(this.r*that.r,this.i*that.i);};
Range2.prototype.mag = function(){return Math.sqrt(this.r*this.r + this.i*this.i);};
Range2.prototype.neg = function(){return new Range2(-this.r,-this.i);};
Range2.prototype.toString = function(){return '{'+this.r+','+this.i+'}';};
Range2.prototype.equals = function(that){
return that != null &&
that.constructor === Range2 &&
this.r === that.r &&
this.i === that.i;
};
//3.类属性,方法(通过类直接调用)
Range2.ZERO = new Range2(0,0);
Range2.ONE = new Range2(1,0);
Range2.I = new Range2(0,1);
Range2._format = /^\{([^,] +),([^}] +)\}$/;
Range2.parse = function(s){
try{
var m = Range2._format.exec(s);
return new Range2(parseFloat(m[1],parseFloat(m[2])));
}catch(x){
throw new TypeError("can not parse");
}
};
//4.创建实例
var c = new Range2(2,3);
var d = new Range2(c.i, c.r);
//==可以随时为类(包括内置类)的原型扩展或更改属性,类的所有实例对象将随之改变==
Range2.prototype.divide = function(){return this.r-this.i;};
var str = c.add(d).toString();
console.log(Range2.ONE); //{ r: 1, i: 0 }
console.log(str); //{5,5}
//Range2.parse(c.toString()).add(c.neg()).equals(Range2.ZERO); //函数返回自身,可实现链式调用
//=========检测对象的类==========
//(一)o instanceof p 检测对象o是不是p得实例 ,
// (二) p.isPrototypeOf(o)检测p是不是o的原型,
// (三)有constructor的函数可通过他来判断属于哪个类
// 他们只能检测对象是否属于指定的类,而无法通过对象获得类名
//在客户端JS中,每个窗口/框架子页面都具有单独的执行上下文,每个上下文都包含独立的全局变量和一组独立的构造函数
// 他们之间的实例即使继承自相同的原型对象,但也是相互独立的原型对象,他们之间互不为实例
function typeAndValue(x){
if(x == null)return ''; //Null,undefined类型没有构造函数
switch (x.constructor){
case Number:return 'Number: '+x;
case String:return 'String: '+x;
case Date: return 'Date: ' +x;
case RegExp:return 'RegExp: '+x;
case Range2:return 'Renge2: '+x; //处理自定义类型
}
}
//(四)通过构造函数名字来识别对象的类(但并不是所有对象都有构造函数,并不是所有函数有名字)
function classof(o){
return Object.prototype.toString.call(o).slice(8,-1); //获取类名
}
Function.prototype.getName = function(){ //返回函数名字,可能为空,非函数返回null
if('name' in this) return this.name;
return this.name = this.toString().match(/function\s*([^(] *)\(/)[1];
};
function type(o){
var t, c,n;
if(o === null)return 'null'; //处理null值
if(o !== o ) return 'nan'; //处理NaN
if((t = typeof o) !== 'object') return t; //typeof可以辨认除了object之外的类型
if((c = classof(o)) !== 'Object') return c;//识别出大部分内置对象的类名,排除值为'Object'
if(o.constructor && typeof o.constructor === 'function' && //若构造函数名字存在则返回它
(n = o.constructor.getName())) return n;
return 'Object'; //其它无法判别的一律返回'Object'
}
//=========鸭式辩型:不需要特意去检测它是什么类,只检测它是否具备我们所需要的特性就行!
// "把会游泳,会嘎嘎叫的鸟都当着是鸭子对待!"

JavaScript学习笔记-实例详解-类(一)的更多相关文章

  1. JavaScript学习笔记-实例详解-类(二)

    实例详解-类(二)   //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...

  2. Java程序猿的JavaScript学习笔记(10—— jQuery-在&OpenCurlyDoubleQuote;类”层面扩展)

    计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...

  3. Angular6 学习笔记——路由详解

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  4. Angular6 学习笔记——组件详解之组件通讯

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  5. Angular6 学习笔记——组件详解之模板语法

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  6. Android学习笔记-Dialog详解

    1.对话框的使用 1.1AlertDialog的显示 简单对话框以及监听的设置:重点掌握三个按钮(也就是三上单词): PositiveButton(确认按钮);NeutralButton(忽略按钮) ...

  7. C&plus;&plus;并发与多线程学习笔记--unique&lowbar;lock详解

    unique_lock 取代lock_quard unique_lock 的第二个参数 std::adopt_lock std::try_to_lock std::defer_lock unique_ ...

  8. SIP学习(实例详解)

    本文摘自:http://blog.chinaunix.net/uid-20655530-id-1589483.html 学习 SIP 协议最快捷的方法是通过范例来学习, 找到了一个完整的呼叫流程,le ...

  9. &lbrack;CSS3&rsqb; 学习笔记-选择器详解(三)

    1.UI元素状态伪类选择器 在CSS3的选择器中,除了结构性伪类选择器外,还有一种UI元素伪类选择器.这些选择器的共同特征是:指定的样式只有当元素处于某种状态时才起作用,在默认状态下不起作用.在CSS ...

随机推荐

  1. android中的ellipsize设置(省略号的问题)

    textview中有个内容过长加省略号的属性,即ellipsize,可以较偷懒地解决这个问题,哈哈~ 用法如下: 在xml中 android:ellipsize = "end"   ...

  2. &period;NET十年回顾

    一.   引子 从我还是编程菜鸟时起,.NET就从来没让我失望过.总是惊喜不断. 当年我第一个项目是做个进销存.用的Winform.当时我是机电工程师.编程只是业余心血来潮而已. .NET的低门槛.V ...

  3. Docker容器学习梳理 - 容器时间跟宿主机时间同步

    在Docker容器创建好之后,可能会发现容器时间跟宿主机时间不一致,这就需要同步它们的时间,让容器时间跟宿主机时间保持一致.如下: 宿主机时间 [root@slave-1 ~]# date Fri M ...

  4. npm 包管理器的使用

    1. 权限问题 Warning "root" does not have permission to access the dev dir · Issue #454 · nodej ...

  5. 手游开发Android平台周边工具介绍

    1.渠道接入 主要是需要接入各平台的登录.充值接口,各家SDK又不统一,Android渠道都是鱼龙混杂,就算小渠道你看不上,但量多了,加起来也还可观,所以大家都拿出吃奶的尽去铺渠道.国内几大主要的An ...

  6. winetricks 用WineTricks令你的Wine更完整

    Linux下最有名的Windows环境模拟器就是WINE了.它提供了一个可以模拟WINDOWS环境的基本平台,在这上面你几乎可以运行任何你想运行的windows程序. 什么?你不相信?不要告诉我你的程 ...

  7. 可视化Echarts的使用示例

    1.照着官方文档简单做两个图表,感受一下. <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...

  8. Struts2拦截器配置和使用

    拦截器是Struts2最强大的特性之一,它是一种可以让用户在Action执行之前和Result执行之后进行一些功能处理的机制. 说到拦截器interceptor,就会想到过滤器filter: 过滤器f ...

  9. 题解【bzoj3240 &lbrack;NOI2013&rsqb;矩阵游戏】

    挖坑2333 等我把代码写完了再写

  10. Android(java)学习笔记110:Java中操作文件的类介绍(File &plus; IO流)

    1.File类:对硬盘上的文件和目录进行操作的类.    File类是文件和目录路径名抽象表现形式  构造函数:        1) File(String pathname)       Creat ...