JavaScript学习笔记-实例详解-类(一)
实例详解-类(一):
//每个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学习笔记-实例详解-类(一)的更多相关文章
- JavaScript学习笔记-实例详解-类(二)
实例详解-类(二) //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...
- Java程序猿的JavaScript学习笔记(10—— jQuery-在“类”层面扩展)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
- Angular6 学习笔记——路由详解
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- Angular6 学习笔记——组件详解之组件通讯
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- Angular6 学习笔记——组件详解之模板语法
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- Android学习笔记-Dialog详解
1.对话框的使用 1.1AlertDialog的显示 简单对话框以及监听的设置:重点掌握三个按钮(也就是三上单词): PositiveButton(确认按钮);NeutralButton(忽略按钮) ...
- C++并发与多线程学习笔记--unique_lock详解
unique_lock 取代lock_quard unique_lock 的第二个参数 std::adopt_lock std::try_to_lock std::defer_lock unique_ ...
- SIP学习(实例详解)
本文摘自:http://blog.chinaunix.net/uid-20655530-id-1589483.html 学习 SIP 协议最快捷的方法是通过范例来学习, 找到了一个完整的呼叫流程,le ...
- [CSS3] 学习笔记-选择器详解(三)
1.UI元素状态伪类选择器 在CSS3的选择器中,除了结构性伪类选择器外,还有一种UI元素伪类选择器.这些选择器的共同特征是:指定的样式只有当元素处于某种状态时才起作用,在默认状态下不起作用.在CSS ...
随机推荐
- 2014牡丹江网络zoj3816Generalized Palindromic Number(dfs或者bfs)
#include <iostream> #include <stdio.h> #include <cmath> #include <algorithm> ...
- jQuery.validationEngine.js学习
项目中使用到了这个插件,抽了个空,看了一下. (function($){ var method ={} $.fn.validationEngine = function(){} $.validatio ...
- 决战JS
经过这几日的学习,测试和摸索,算是了解了一些关于javascript 的相关知识吧.学习过程中做出了一些小DEMO,现总结一下实现这些DEMO的基本思路,如有不妥或更为简便的方法,还希望大神拍砖,共同 ...
- 【Android】学习记录<1> -- 初识ffmpeg
工作需要用到ffmpeg来进行Android的软编码,对这玩意儿一点都不了解,做个学习记录先. FFmpeg:http://www.ffmpeg.org Fmpeg is the leading mu ...
- 使用国内镜像加速下载Android SDK
本文转自:http://blog.kuoruan.com/24.html.感谢原作者. 什么是Android SDK SDK:(software development kit)软件开发工具包.被软件 ...
- 12套有用的免费 PSD 格式 Android UI 素材
在这里,我们向大家呈现一些有用的和免费的 Android 用户界面 PSD 素材.由于 Android 市场迅速增长,设计人员和开发人员正在寻找一些快速和容易的方法来创建 Android 友好的应用和 ...
- .NET Core中使用Razor模板引擎
一.简介 在MVC以外的场景中,我们往往需要完成一些模板引擎生成代码或页面的工作:在以前我们一般常用的有Razor.NVeocity.VTemplate.虽然所有的模板系统都具有一些共同特征,但 Ra ...
- 【Swift学习】Swift编程之旅---Subscripts下标(十六)
类.结构体和枚举可以定义下标,他可以快速简单地访问集合(set,array,dict)的元素,你可以使使用下标来获取和设置集合元素. 你可以定义一个类型的多个下标,通过索引值类型的不同来进行重载,而且 ...
- github.com/dotnet/orleans
Orleans is a framework that provides a straight-forward approach to building distributed high-scale ...
- 【原创】Kakfa serializer包源代码分析
这个包很简单,只有两个scala文件: decoder和encoder,就是提供序列化/反序列化的服务.我们一个一个说. 一.Decoder.scala 首先定义了一个trait: Decoder[T ...