您的位置:首页 > Web前端 > JavaScript

js之JavaScript 面向对象介绍 ----谷营中西软件科技园

2016-04-11 00:10 597 查看

1. 面向对象介绍

1.1. 对象

在面向对象思想中,一切皆对象。所谓的对象,实质上是指“事物”(包括人和物)在程序设计

语言中的表现形式。这里的“事物”可以是任何东西。例如,我们将一名女生作为对象的话,那么她

可能是一名美丽的、高挑的、可爱的等等,这些形容这名女生的词,我们就叫做属性。那么她可能要

上学、工作、出国等等,这些女生要做的事情,我们就叫做方法。

所以,简单来说对象,可以这样描述。我们将世界上任何的人和物都理解成对象,用来描述对象

的特征叫做属性,用来描述对象的动作叫做方法。

1.2. 类

上面我们说了一名女生,而在现实生活中会有许许多多的女生。那么女生我们就可以叫做类,而

范冰冰就是女生这个类中的一个对象,苍井空就是女生这个类中的另一个对象。

所以,简单来所类,可以这样描述。相似的对象之间具有一些共同的组成特征,我们将之归成“类”。

而在一个类中的一个对象,我们也可以叫做“实例”。

但是,我们需要知道的是 JavaScript 与 Java 这种传统的面向对象语言不同,它实际上就没有“类”

这个概念。JavaScript 语言的一切都是基于对象的,其所依靠的是一套原型系统(原型的概念,我们

会在后面的内容详细学习)。

1.3. 封装

封装主要用于阐述对象中所包含(或封装)的内容,它们通常由两部分组成:

教程 相关的数据(用于存储属性)

 基于这些数据所能做的事情

我们还是以女生为例来说,一个女生可以哭、可以笑、可以生气等等,但是我们并不清楚为什么

会哭、笑还是生气,我们只知道什么情况下会哭、什么情况下会笑或是什么情况下会生气。那如果一

个女生就是一个对象的话,那么哭、笑或生气就是封装在这个对象内部的。我们只能按照要求输入并

得到对应的输出结果,但是具体是如何实现的并不清楚。而且,我们甚至不需要这些都是如何实现的,

只需要掌握如何使用或调用即可。

1.4. 聚合

所谓聚合,也可以叫做组合,实际上就是将现有的几个对象合并成一个新对象的过程。总之,聚

合这个概念强调的是将多个对象合而为一的能力。通过聚合这种强有力的方法,可以将一个问题分解

成成多个更小的问题。

我们依旧以女生为例来说,假设某个女生就是一个对象,那么可能是陌生的女生、认识的女生、

熟悉的女生、女朋友或老婆等。那么这样我们就可以将某个女生称为聚合对象,她是由几个对象组合

而成。或者,我们将电脑作为一个对象来看,那么这个对象是由屏幕对象、鼠标对象、键盘对象等组

合而成的。

1.5. 继承

继承通常是指类与类之间的关系。如果两个类都有相同的属性或方法,那么可以让一个类继承于

另一个类,这样就不需要在前者再次定义同样的属性或方法。

比如把女生作为一个类的话,那么女生都喜欢逛街,这就是女生这类的一个方法。那么漂亮的女

生也同样喜欢逛街,所以,我们可以将漂亮的女生也作为一个类。然后,让漂亮的女生这个类继承于

女生这个类。这样,漂亮的女生这个类就具有了逛街这个方法,不再需要重新定义逛街这个方法。

1.6. 多态

在上面的例子中,我们将漂亮的女生这个类继承于女生这个类。这就意味着无论是漂亮的女生还

是女生都具有实现“逛街”方法。那么,即便不知道逛街是女生这个类还是漂亮的女生这个类的方法,

我们依然可以直接调用“逛街”方法。类似这种不同对象通过相同方法调用来实现各自行为的能力,

我们就称之为多态。

1.7. OOP 概述

面向对象其实是一种思想,是一种对现实世界理解和抽象的方法。我们以“一切皆对象”的思想

来看待世界上的任何人和物,然后通过封装、继承、多态等方式来解决问题。



2. 函数

2.1. Arguments 对象

在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。

a.检测参数个数

function howManyArgs() {
alert(arguments.length);
}
howManyArgs("string", 45);
howManyArgs();
howManyArgs(12);


b.模拟函数重载

function doAdd() {
if(arguments.length == 1) {
alert(arguments[0] + 5);
} else if(arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //输出 "15"
doAdd(40, 20); //输出 "60"


2.2. 变量的作用域

2.2.1全局变量与局部变量

var global = 1;
function f(){
var local = 2;
global++;
return "global = "+global;
}
alert(f()); //output global = 2
alert(f()); //output global = 3
alert(local); //output local is undefined


2.2.2 声明局部变量(没有使用 var)

function f(){
local = 2;
}
alert(local); //output local is undefined
f();
alert(local); //output global = 2


在函数 f() 中定义了一个变量 local。在该函数被调用之前,这个变量是不存在的。

local 变量会在 f() 函数首次被调用时创建,并赋予全局作用域。

2.2.3 函数域与全局域

var a = 123;
function f(){
alert(a); //output undefined
var a = 1;
alert(a); //output 1
}
f();


函数域始终优先于全局域,所以局部变量 a 会覆盖与它同名的全局变量。

2.3. 几个特殊函数

2.3.1 匿名函数

javascript 可以将函数作为数据使用。作为函数本体,它像普通的数据一样,不一定要有名字。默

认名字的函数被称之为“匿名函数”。例如:

function (a){return a;}


匿名函数的两种用法:

 可以将匿名函数作为参数传递给其他函数。这样,接收方函数就能利用所传递的函数来完成

某些事情。

 可以定义某个匿名函数来执行某些一次性任务。

2.3.2 回调函数

function add(a, b){
return a() + b();
}
var one = function(){return 1;}
var two = function(){return 2;}
alert(add(one,two)); //output 3

//可以直接使用匿名函数来替代one()和two(),以作为目标函数的参数
alert(add(function(){return 1;}, function(){return 2;}));


在这个例子中,函数 one 和 two 都是回调函数。

 当将函数 A 传递给函数 B,并由 B 来执行 A 时,A 就成了一个回调函数(callback function)。

如果 A 还是一个无名函数,就称之为匿名回调函数。

回调函数的优点:

 它可以在不做命名的情况下传递函数(这意味着可以节省全局变量)。

 可以将一个函数调用操作委托给另一个函数(这意味着可以节省一些代码编写工作)。

 回调函数也有助于提升性能。

eg:

//该函数通过一个循环将其所接收的三个参数分别乘以2,并以数组的形式返回结果
function two(a, b, c){
var i, arr = [];
for(i = 0;i < 3; i++){
arr[i] = arguments[i] * 2;
}
return arr;
}
//将接收的参数加一后返回
function addone(a){
return a + 1;
}
//测试上面的两个函数
alert(two(1, 2, 3)); //output [2, 4, 6]
alert(addone(100)); //output 101
//将三个数据在两个函数之间传递
var myarr = [];
myarr = two(10, 20, 30);
for(var i = 0; i < 3; i++){
myarr[i] = addone(myarr[i]);
}
alert(myarr); //output [21, 41, 61]
/*
* 以上代码可以工作,但是显然不够优化。
* 这里使用了两次循环。如果处理的数据量很大火循环操作很复杂的话,开销一定不小。
*/
//优化之后的代码(修改two函数)
function two(a, b, c, callback){
var i, arr = [];
for(i = 0;i < 3; i++){
arr[i] = callback(arguments[i] * 2);
}
return arr;
}
myarr = two(1, 2, 3, addone);
alert(myarr); //output [3, 5, 7]
//还可以使用匿名函数来替代addone函数
myarr = two(1, 2, 3, function addone(a){return a + 1;});


2.3.3 自调函数

自调函数 —— 其实就是在定义函数后自行调用。例如:

(
function(){
alert("javascript");
}
)()


第一对括号,放置的是一个匿名函数。

 第二对括号的作用,是“立即调用”。

 自调函数只需:将匿名函数的定义放进一对括号中,然后外面再跟一对括号即可。

(
function(name){
alert("Hello " + name + "!");
}
)("javascript")
//output Hello javascript!


第一个括号中的匿名函数接受一个参数。

 第二个括号,在调用时,向匿名函数传递参数内容。

2.3.4 内部(私有)函数

function a(param){
function b(input){
return input * 2;
};
return "The result is " + b(param);
}

alert(a(2)); //The result is 4


当调用全局函数 a ( ) 时,本地函数 b ( ) 也会在其内部被调用。由于 b ( ) 是本地函数,它在

a ( ) 以外的地方是不可见的,所以将 b 称之为私有函数。

私有函数的优点:

 有助于确保全局名字空间的纯净性(这意味着命名冲突的机会很小)。

 私有性 —— 只将一些必要的函数暴露给“外面世界”,并保留属于自己的函数,使它们不为

该应用程序的其他部分所用。

2.3.5 返回函数的函数

function fn(){
var a = "a";

return function(){
return a;
}
}


就是内部函数的一种特殊用法。

 在不多定义另外的函数时,可以执行两个逻辑体(外部的函数不能具有真实的返回值)。

2.4. 预定义函数



3. 闭包

3.1. 作用域链

javascript 不存在大括号级的作用域,但具有函数作用域。

 在函数内定义的变量在函数外是不可见的。但如果该变量是在某个代码块中定义的(如在某个 if

或 for 语句中),它在代码块外是可见的。

var a = 1;
function f(){
var b = 2;
return a;
}

alert(f()); //output 1
alert(b); //output b is undefined


变量 a 是属于全局域的,变量 b 的作用域是属于函数 f ( ) 内。

 在 f ( ) 内,a 和 b 都是可见的。

 在 f ( ) 外,a 是可见的,b 则是不可见的。

var a = 1;
function f(){
var b = 2;
function n(){
var c = 3;
alert(a); //output 1
alert(b); //output 2
alert(c); //output 3
}
return n();
}
f();


函数 n ( ) 可以访问的变量可以是自身的作用域,也可以是其“父级”的作用域。这就形成了一条 作用域链。

function f1(){
var a = 1;
f2();
}
function f2(){
return a;
}

alert(f1()); //output a is undefined


在定义函数 f1 ( ) 和 f2 ( ) 时,只能访问全局作用域和其自身的作用域。

在定义函数 f2 ( ) 时,变量 a 是不可见的。

var a = 5;
function f1(){
var a = 1;
f2();
}
function f2(){
return a;
}

alert(f1()); //output 5


在定义函数 f1 ( ) 和 f2 ( ) 时,都是可以访问全局作用域的。

3.2. 闭包

定义:指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。

闭包的实现:

var b;
function a(){
var a = "a";
b = function(){
return a + "b";
}
return a;
}

//测试
alert(a()); //output a
alert(b()); //output ab


在 a ( ) 函数中定义了 b ( ) 函数,所以 b ( ) 函数可以访问 a ( ) 函数的作用域。

 将 b ( ) 函数升级到全局函数,但依然保留可以对 a ( ) 函数作用域的访问权。

3.3. 循环中的闭包

function f(){
var a = [];
var i;
for(i = 0; i < 3; i++){
a[i] = function(){
return i;
}
}
return a;
}

var fun = f();

alert(fun[0]()); //output 3
alert(fun[1]()); //output 3
alert(fun[2]()); //output 3


按照预期,最终结果应该输出 [0 , 1 , 2 ],但是却是[ 3 , 3 , 3 ]。

在函数 f ( ) 中,我们通过循环,创建了三个闭包,它们都指向了共同的局部变量 i 。

但是,闭包并不会记录它们的值,它们所拥有的只是一个 i 的连接(即引用),因此只能返回 i 的

当前值。

function f(){
var a = [];
var i;
for(i = 0; i < 3; i++){
a[i] = (function(x){
return x;
})(i);
}
return a;
}

var fun = f();

alert(fun[0]); //output 0
alert(fun[1]); //output 1
alert(fun[2]); //output 2


在这里,我们不再直接创建一个返回 i 的函数,而是将 i 传递给了一个自调函数。

 在该自调函数中,i 就被赋值给了局部变量 x ,这样一来,每次迭代中的 x 就会拥有各自不同的

值了。

function f(){
function n(x){
return x;
}
var a = [];
var i;
for(i = 0; i < 3; i++){
a[i] = n(i);
}
return a;
}

var fun = f();

alert(fun[0]); //output 0
alert(fun[1]); //output 1
alert(fun[2]); //output 2


3.4. Getter 与 Setter

利用闭包的概念,实现 Getter 与 Setter。假设现在有一个属于特殊区间的变量,不想暴露给外部。

可以利用闭包为这个变量定义 Getter 与 Setter 方法实现调用和设置的功能。

var getValue, setValue;
(function f(){
var secret = 0;
getValue = function (){
return secret;
}
setValue = function (x){
secret = x;
};
})();

getValue(); //output 0
setValue(123);
getValue(); //output 123


- 对象

4.1. 定义对象的三种方式

- 第一种构造法:new Object

var a = new Object();
a.x = 1, a.y = 2;


第二种构造法:对象直接量

var b = { x : 1, y : 2 };


第三种构造法:定义类型

function Point(x, y){
this.x = x;
this.y = y;
}
var p = new Point(1,2);


4.2. 对象的属性和方法

访问对象的属性  中括号表示法:hero[‘name’]。  点号表示法:hero.name。  如果访问的属性不存在,会返回 undefined。  访问对象的方法  方法名后加一对括号:hero.say()。  像访问属性一个访问方法:hero‘say’。

修改属性与方法

//创建一个空对象
var hero = {};

//为hero对象增加属性和方法
hero.name = "javascript";
hero.value = "helloworld";
hero.sayName = function(){return "hello " + hero.name;};

//测试
alert(hero.name); //output javascript
alert(hero.sayName()); //output hello javascript

//删除hero对象的name属性
delete hero.name;

//测试
alert(hero.sayName()); //output hello undefined


4.3. this 用法

//创建一个空对象
var hero = {};

//为hero对象增加属性和方法
hero.name = "javascript";
hero.value = "helloworld";
hero.sayName = function(){return "hello " + this.name;};

//测试
alert(hero.name); //output javascript
alert(hero.sayName()); //output hello javascript


这里的 this 实际上引用的是“这个对象”或“当前对象”。  this 的用法,大部分人的使用问题都比较多。所以不建议过多使用!

4.4. 内建对象

内建对象大致上可以分为三个组:  数据封装类对象 —— 包括 Object、Array、Boolean、Number 和 String。这些对象代表着 javascript 中不同的数据类型,并且都拥有各自不同的 typeof 返回值,以及 undefined 和 null 状态。  工具类对象 —— 包括 Math、Date、RegExp 等用于提供遍历的对象。  错误类对象 —— 包括一般性错误对象以及其他各种更特殊的错误类对象。它们可以在某些异常 发生时帮助我们纠正程序工作状态。 Object 对象:  Object 是 javascript 中所有对象的父级对象,这意味着所有对象都继承于 Object 对象。

 创建一个空对象:

var object = {};
var obj = new Object();


Array 对象:

Array 对象用于在单个的变量中存储多个值。

创建一个空 Array 对象:

var object = [];
var obj = new Array();


//反转字符串示例

//定义一个字符串
var str = "a,b,c,d,e,f,g";
//利用String对象的split()方法,将字符串切割成一个数组
var arr = str.split(",");
//利用Array对象的reverse()方法,将数组中元素的顺序颠倒。
arr = arr.reverse();
//测试打印
alert(arr.toString());


String 对象:

String 对象与基本的字符串类型之间的区别:

var str = "hello";
var obj = new String("world");

alert(typeof str); //typeof string
alert(typeof obj); //typeof object


//判断字符串是否包含指定字符串示例

//定义两个要判断的字符串
var str = "abcdefg";
var substr = "efg";
/*
* 定义判断字符串是否包含指定字符串的函数
* * 第一个参数:要判断的字符串
* * 第二个参数:指定的字符串
*/
function sub(str,substr){
//将判断的字符串定义成String对象
var string = new String(str);
//截取判断的字符串
var result = string.substr(string.indexOf(substr),substr.length);

if(result==null||result==""){
return false;
}else{
return true;
}
}

alert(sub(str,substr));


5. 原型

函数本身也是一个包含了方法和属性的对象。而现在我们要研究的就是函数对象的另一个属性

—— prototype。

5.1. 利用原型添加方法与属性

下面创建一个新的函数对象,并设置一些属性和方法:

function Hero(name, color){
this.name = name;
this.color = color;
this.whatareyou = function(){
return "I am a " + this.color + " " + this.name;
}
}

var hero = new Hero("javascript","red");

alert(hero.whatareyou()); //output I am a red javascript


为上面的 Hero 函数对象增加一些属性和方法

Hero.prototype.price = 100;
Hero.prototype.rating = 3;
Hero.prototype.getInfo = function(){
return "Rating: " + this.rating + " , Price: " + this.price;
}

alert(hero.getInfo()); //output Rating: 3 , Price: 100


上面的方式,也可以这样去做:

Hero.prototype = {
price : 100,
rating : 3,
getInfo : function(){
return "Rating: " + this.rating + " , Price: " + this.price;
}
};


5.2. 利用自身属性重写原型属性

如果对象的自身属性与原型属性同名该怎么办呢?答案是对象自身属性的优先级高于原型属性。

function Hero(){
this.name = "jscript";
}
Hero.prototype.name = "javascript";
var hero = new Hero();
alert(hero.name); //output jscript
delete hero.name;
alert(hero.name); //output javascript


5.3. 扩展内建对象

//为原型 Array对象增加一个判断的函数
Array.prototype.inArray = function(color){
for(var i = 0, len = this.length; i < len; i++){
if(this[i] === color){
return true;
}
}
return false;
}

//定义一个Array对象
var a = ["red", "green", "blue"];

//测试
alert(a.inArray("red")); //true
alert(a.inArray("yellow")); //false


6. 继承

 如果两个类都是同一个实例的类型,那么它们之间存在着某些关系,我们把同一个实例的类型之 间的泛化关系称为“继承”。

 继承关系至少包含三层含义:

 子类可以覆盖父类的方法或扩展新的方法。

 在 javascript 中,并不支持“继承”。也就是说,javascript 中没有继承的语法。从这个意义上来说, javascript 并不是直接的面向对象语言。

6.1. 原型链

原型链是 ECMAScript 标准制定的默认继承方式。

function A(){
this.name = "a";
this.toString = function(){return this.name};
}
function B(){
this.name = "b";
}
function C(){
this.name = "c";
this.age = 18;
this.getAge = function(){return this.age};
}

B.prototype = new A();
C.prototype = new B();


 将对象直接创建在 B 对象的 prototype 属性中,并没有去扩展这些对象的原有原型。

 通过 new A ( ) 另创建了一个新的实体,然后用它去覆盖该对象的原型。

 javascript 是一种完全依靠对象的语言,其中没有类(class)的概念。

 因此,需要直接用 new A ( ) 创建一个实体,然后才能通过该实体的属性完成相关的继承工作。

 完成这样的继承实现之后,对 A ( ) 所进行的任何修改、重写或删除,都不会对 B ( ) 产生影响。

6.2. 只继承于原型

function A(){}
A.prototype.name = "a";
A.prototype.toString = function(){return this.name};

function B(){}
B.prototype = A.prototype;
B.prototype.name = "b";

function C(){}
C.prototype = B.prototype;
C.prototype.name = "c";
C.prototype.age = 18;
C.prototype.getAge = function(){return this.age};


6.3. 对象之间的继承

//该函数接受一个对象并返回它的副本
function extendCopy(p){
var z = {};
for(var i in p){
z[i] = p[i];
}
//uber属性设置指向其父级原型的引用
z.uber = p;
return z;
}

var a = {
name : "a"
}

var b = extendCopy(a);
b.toStr = function(){return this.name;};

alert(b.toStr()); //output a


wanzuwodoule sleep…………………. good goods study ,day day up.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: