前言:
今天和大家分享一下近期整理的有关JavaScriptOOP的基础知识~~~我们一起来学习一下……
***本章关键词:JavaScriptOOP的入门基础,成员属性,成员方法,原型与原型链……
一、JavaScriptOOP基础
一、面向对象编程OOP
1、语言的分类:
面向机器:汇编语言
面向过程:C语言
面向对象:C++,Java,PHP等
2、面向过程和面向对象
①面向过程:专注于如何去解决一个问题的过程。
编程特点:用一个个函数去实现过程操作,没有类和对象的概念;
②面向对象:专注于有哪一个对象实体去解决这个问题。
编程特点是:出现了一个个的类,由类去生成对象。
二、面向对象的三大特征
继承,封装,多态
三、类&对象的关系
1、类:一群有相同特征(属性)和行为(方法)的集合
eg: 人类
属性:"身高,体重,年龄"
方法:"吃饭,睡觉,敲代码"
2、对象:从类中,new出的具有确定属性值和方法的个体称为对象。
eg:张三:属性:身高:身高178,体重150 方法:说话---我叫张三
3、类和对象的关系:
类是抽象的,对象是具体的。
(!类是对象的抽象化,对象是类的具体化!)
通俗的来讲:
类是一个抽象概念,表示具有相同属性和行为的集合。
但是类仅仅表示表明这类群体具有相同的属性,但是没有具体的属性值。
而对象是对类的属性进行具体赋值后,而得到的一个具体的个体;
eg:人类有身高体重年龄,但不能具体说人类的身高体重具体是多少;而张三是人类的一个具体个体,身高体重等有具体值,则张三就是人类的一个对象。
4、使用类和对象的步骤:
①创建一个类(构造函数):
类名,必须要每个单词首字母都大写
function 类名(属性一){
this.属性 = 属性一;
this.方法= function(){}
//this指向谁?即将调用当前构造函数的对象。
}
②通过类,实例化出一个新的对象;
var obj = new 类名(属性一Value);
//原构造函数中this,指向新创建的obj对象
obj.方法();调用方法
obj.属性();调用属性
实例化对象的时候,会执行构造函数
5、两个重要属性:
constructor:返回当前对象的构造函数。(只有对象才有,返回的是构造函数-类)
>>>zhangsan.constructor == Person
>>>对象的constructor,位于_proto_原型对象上(后续讲解)
instanceof:判断对象是否是某个类的实例
>>>zhangsan instanceof Person true
>>>zhangsan instanceof Object true
>>>Person instanceof Object true(函数也是对象)
6、广义对象与狭义对象:
广义对象:除了用字面量声明的基本数据类型之外,外物皆对象,换句话说,能够添加属性和方法的变量,就是对象;
var s = "1" ; 不是对象
var s = new String("1") ; 就是对象
狭义对象:只有属性,方法,除此之外没有任何东西。
var obj = {}; var obj = new Object();
二、成员属性与成员方法
一、成员属性与成员方法
1、在构造函数中通过this.属性声明;或者实例化出对象后,通过"对象.属性"追加的。
都属于成员属性,或成员方法;也叫实例属性与实例方法。
成员属性/方法,是属于实例化出的这个对象。
通过"对象.属性"调用
二、静态属性与静态方法
2、通过"类名.属性名","类名.方法名"声明的变量,称为静态属性,静态方法;也叫类属性、类方法。
类属性/类方法,是属于类的(属于构造函数的)
通过"类名.属性名"调用
3、成员属性,是属于实例化出的对象的,会出现在新对象的属性上
静态属性,是属于类(构造函数)自己的,不会出现在新对象的属性上
4、JS对象属性的删除:
①对象无需手动删除,JS
②删除对象的属性:delete 对象名.属性名
5、对象是引用数据类型
也就是说,当new出一个对象时,这个obj变量存储的实际上是对象的地址,在对象赋值时,赋的也是地址。
function Person(){}
var xiaoxi = new Person();//xiaoxi对象实际上存的是地址
var ashu = xiaoxi;//赋值时,实际是将xiaoxi存的地址给了ashu
ashu.name = "阿树";//阿树通过地址,修改了地址
console.log(xiaoxi.name);//xiaoxi再通过地址打开对象,实际已经变了
引用数据类型,赋值时传递的是引用(地址)---快捷方式
基本数据类型,赋值时传递的是数据(值)
三、私有属性和私有方法
6、在构造函数中,通过var声明的属性,成为私有属性:
function Person(){var num=1;}
私有属性的作用域,仅在当前函数有效。对外不公开,即通过对象/类都无法调用到。
三、原型与原型链
【__proto__与prototype】
1、prototype(函数的原型):函数才有prototype。
prototype是一个对象,指向了当前构造函数的引用地址。
2、__proto__(对象的原型对象):所有对象都有__proto__属性。当用构造函数实例化(new)一个对象时,
会将新对象的__proto__属性,指向构造函数的prototype。
eg:zhangsan.__proto__==Person.prototype √
所有对象最终都会指向Object()的prototype。
【原型链】
1、通过构造函数,new出的对象,新对象的__proto__指向构造函数的prototype。
2、所有函数的__proto__指向Function()的prototype。
3、非构造函数new出的对象({} new Object() 对象的prototype)的__proto__指向Object的prototype。
4、Object的__proto__指向Null。
四、原型属性与原型方法
【类中属性与方法的声明方式】
1、成员属性、成员方法:
this.name = ""; this.func = function(){}
>>>属于实例化出的对象的。通过"对象.属性"调用。
2、静态属性、静态方法:
Person.name = ""; Person.func = function(){}
>>>属于类(构造函数)的。通过"类名.属性"调用。
3、私有属性、私有方法:
在构造函数中,使用var num = 1;声明
>>>只在构造函数内部能用,在外部无法通过任何方式访问。
4、原型属性、原型方法:
Person.prototype.name = "";
Person.prototype.func = function(){};
>>>写在了构造函数的prototype上,当使用构造函数实例化对象时,该属性方法会进入新对象的__proto__上。
也就是说,1/4使用对象可访问,2使用类名可访问,3只能在函数的{}内使用。
5、习惯上,我们会将属性写为成员属性,而方法写为原型方法;
eg:
1 function Person(){ 2 this.name = "zhangsan"; 3 } 4 Person.prototype.say = function(){}
原因:
①实例化出对象后,所有属性直接在对象上,所有方法都在__proto__上,非常直观清晰。
②方法写到prototype上,要更加节省内存。
③使用for in 循环时,会将对象以及对象原型链上的所有属性和方法打印出来,而方法往往是不需要展示的。
将方法写到__proto__上,可以使用hasOwnProperty将原型上的方法更好的过滤。
④官方都这么写。
6、当访问对象的属性/方法时,会优先使用对象自有的属性和方法。
如果没有找到,便使用__proto__属性在原型上查找,如果找到即可使用。
但是,当对象自身,以及__proto__上有同名方法,执行对象自身的。
7、可以通过prototype扩展内置函数的相关方法。
代码演示:
1 function Person(){ 2 this.name1 = "name1"; //成员属性 3 this.age = "age1"; 4 this.sex = "男"; 5 this.say = function(){ 6 alert("我是大帅哥!"); 7 } 8 var name2 = "name2";//私有属性 9 } 10 Person.name3 = "name3";//静态属性 11 Person.prototype.name4 = "name4";//原型属性 12 13 14 Person.prototype.say = function(){ 15 alert("我叫"+this.name1); 16 } 17 18 var zhangsan = new Person(); 19 // zhangsan.say = function(){ 20 // alert("我是大帅哥!"); 21 // } 22 zhangsan.say(); 23 zhangsan.toString(); 24 25 console.log(zhangsan); 26 27 // console.log(zhangsan.name1); 28 // console.log(zhangsan.name2); 29 // console.log(zhangsan.name3); 30 // console.log(zhangsan.name4); 31 // 32 // console.log(s);
可以通过prototype扩展内置函数的相关方法
代码演示:
1 Number.prototype.add = function(a){ 2 return this+a 3 } 4 5 var num = new Number(10); 6 console.log(num); 7 alert(num.add(3)); 8 9 /* 10 * 为Array类添加一个find(val)方法,当一个Array对象调用该方法的时候,如果能找到val值,则返回其下标,否则返回-1。 11 */ 12 Array.prototype.find = function(val){ 13 for (var i = 0; i<this.length;i++) { 14 if(this[i]==val){ 15 return i; 16 } 17 } 18 return -1; 19 } 20 var arr = new Array(1,2,3,4,5); 21 alert(arr.find(1));
位String类添加一个字符串反转方法
1 String.prototype.fanzhuan = function(){ 2 var arr = this.split(""); 3 arr.reverse(); 4 return arr.join("") 5 } 6 7 8 console.log(str.fanzhuan()); 9 10 11 12 for-in循环 13 14 15 【for-in循环】 16 for-in循环,主要用于遍历对象。 17 for()中格式:for(keys in obj){} 18 19 keys表示obj对象的每一个键值对的键,所以{}中,使用obj[keys]读取每个值; 20 但是,使用for-in循环,不但能遍历对象本身的属性和方法。还能够遍历对象原型链上的所有属性和方法。 21 22 可以使用hasOwnProperty判断一个属性,是否是对象自身的属性。 23 obj.hasOwnProperty(keys)==true 表示:keys是对象自身的一个属性 24 25 代码演示: 26 // foreach 27 function Person(){ 28 this.name1 = "name11111"; //成员属性 29 this.age = "age11111"; 30 this.func2 = function(){ 31 console.log("thisFun") 32 } 33 } 34 Person.name3 = "name333333"; 35 Person.prototype.name4 = "name44444"; 36 Person.prototype.func1 = function(){ 37 console.log("prototypeFun") 38 } 39 var zhangsan = new Person(); 40 for(keys in zhangsan){ 41 if(zhangsan.hasOwnProperty(keys)){ //过滤掉原型上的属性,只打印对象自身属性 42 console.log(zhangsan[keys]) 43 } 44 }
五、JS OOP中的继承(JS模式实现继承的三种方式)
【文档注释】第一行两个星号
/**
* ……
*/
调用函数时,可以看到注释内容
【JS OOP 中的继承】
1、使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方法。
>>>继承的两方,发生在两个类之间。
2、JS模式实现继承的三种方式:
1)扩展Object实现继承
①定义父类:function Parent(){}
②定义子类:function Son(){}
③通过原型给Object对象添加一个扩展方法。
1 Object.prototype.customExtend = function(parObj){ 2 for(var i in parObj){ 3 //通过for-in循环,把父类的所有属性方法,赋值给自己。 4 this[i] = ParObj[i]; 5 } 6 }
④子类对象调用扩展方法
son.customExtend(Parent);
2)使用call和apply
首先,了解一下call和apply:通过函数名调用方法,强行将函数中的this指向某个对象;
call写法:func.call(func的this指向的obj,参数1,参数2...);
apply写法:func.apply(func的this指向的obj,[参数1,参数2...]);
call与apply的唯一区别:在于接收func函数的参数方式不同。call采用直接写多个参数的方式,而apply采用是一个数组封装所有参数。
①定义父类 funtion Parent(){}
②定义子类 function Son(){}
③在子类中通过call方法或者apply方法去调用父类。
function Son(){
Parent.call(this,....);
}
3)使用原型继承
①定义父类function Parent(){}
②定义子类function Son(){}
③把在子类对象的原型对象声明为父类的实例。
Son.prototype = new Parent();
六、闭包
【JS中的作用域】
1、全局变量:函数外声明的变量
局部变量:函数内声明的变量
在JS中,函数为唯一的局部作用域,而if、for等其他{}没有自己的作用域
所以,函数外不能访问局部变量。
其实,变量在函数执行完毕以后,占用的内存就被释放。
2、如何访问函数私有变量?
JS中,提供了一种"闭包"的概念:在函数内部,定义一个子函数,可以用子函数访问父函数的私有变量。执行完操作以后,将子函数通过return返回。
1 function func2(){ 2 var num = 1; 3 function func3(){ 4 var sum = num+10; 5 alert(sum); 6 } 7 return func3; 8 } 9 var f = func2(); 10 f();
3、闭包的作用:
① 访问函数的私有变量;
② 让函数的变量始终存在于内存中,而不被释放。
代码演示:
1 function func1(){ 2 var n = 1; 3 } 4 if(true){ 5 var m = 3; 6 } 7 //alert(m); // 3 8 func1(); 9 //alert(n);// 报错。函数外不能访问局部变量。其实,n变量在func1函数执行完毕以后,占用的内存就被释放。 10 11 12 /*闭包*/ 13 function func2(){ 14 var num = 1; 15 function func3(){ 16 var sum = num+10; 17 alert(sum); 18 } 19 return func3; 20 } 21 var f = func2(); 22 f(); 23 24 // 循环转一次,创建一个lis[i].onclick函数。但是,当点击li执行函数的时候,i已经变为6,所以无论点击哪一个,i都是6 25 // 循环创建lis[i].onclick的时候, 循环一次,li[i]里面的i都被赋为不同值;创建了 li[1] li[2] li[3]... 26 // 但是,创建过程中,并没有执行onlick后面的函数,所以函数里面的i并没有赋值,还是字母i。 27 // 最终,我们点击li[1] li[2]...时,onclick函数里面的i才会赋值。(但此时,全局变量的i ,已经成为6 了) 28 var lis = document.getElementsByTagName("li"); 29 for (var i=0;i<lis.length;i++) { 30 lis[i].onclick = function(){ 31 //alert("您/点击了第"+i+"个li!"); 32 //console.log(lis[i]); 33 //console.log(this); 34 } 35 } 36 37 // 循环转一次,创建一个自执行函数。 38 // 而自执行函数拥有自己的作用域,所以用函数局部作用域j保存当前的全局变量i值。这样,创建第一个自执行函数,它的j=1;创建第二个,它的j=2...不同函数的j互不干扰。 39 // 这样,循环转完以后,相当于创建了6个自执行函数,每个函数中都有一个不同的j变量 40 var lis = document.getElementsByTagName("li"); 41 for (var i=0;i<lis.length;i++) { 42 !function(){ 43 var j = i; 44 lis[j].onclick = function(){ 45 alert("您/点击了第"+j+"个li!"); 46 //console.log(lis[i]); 47 //console.log(this); 48 } 49 }(); 50 } 51 52 var lis = document.getElementsByTagName("li"); 53 for (var i=0;i<lis.length;i++) { 54 !function(j){ 55 lis[j].onclick = function(){ 56 alert("您/点击了第"+j+"个li!"); 57 //console.log(lis[i]); 58 //console.log(this); 59 } 60 }(i); 61 }
..。..。..。..。..。..。..。..。..。END..。..。..。..。..。..。..。..。..。
..。..。..。..。..。..。希望可以帮到你哟..。..。..。..。..。..。
出处:http://www.cnblogs.com/hope666/