相关链接:

JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式

JS面向对象(2) -- this的使用,对象之间的赋值,for...in语句,delete使用,成员方法,json对象的使用,prototype的使用,原型继承与原型链

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

1.Object类

在JS中,Object是所有类的基类,使用Object类来创建自定义对象时,可以无需定义构造函数(constructor,prototype,hasOwnProperty(property))

  1. 1 var per = new Object();
  2. 2 per.name = 'zhangsan';
  3. 3 per.age = 30;
  4. 4 alert(per.name + per.age);

我们想在程序中得到一个对象变量,只要能存储大量数据即可,这个时候,我们可以考虑使用Object类。Object类避免了对构造器的定义。 Object类下另一个常用的属性:hasOwnProperty

  1. 1 var per = new Object();
  2. 2 per.name = 'zhangsan';
  3. 3 per.age = 30;
  4. 4 if per.hasOwnProperty('email'){
  5. 5 alert('具有email');
  6. 6 }else{
  7. 7 alert('无email');
  8. 8 }

2.静态属性

在有些面向对象的语言当中,可以使用static关键字定义类的静态属性或者静态方法,在JS中,可以进行模拟。

语法:

  类名.属性名

  类名.属性=function(){}

  1. 1 function Person(){
  2. 2 }
  3. 3 Person.count = 0;
  4. 4 var p1 = new Person();
  5. 5 Person.count++;
  6. 6 var p2 = new Person();
  7. 7 Person.count++;
  8. 8 var p3 = new Person();
  9. 9 Person.count++;
  10. 10 alert(Person.count);

添加静态属性和静态方法:

  1. 1 function Person(){
  2. 2 Person.count++; //静态属性
  3. 3 Person.getCount=function(){ //静态方法
  4. 4 alert('当前共有' + Person.count + '个人');
  5. 5 }
  6. 6 }
  7. 7 Person.count = 0;
  8. 8 var p1 = new Person();
  9. 9 var p2 = new Person();
  10. 10 var p3 = new Person();
  11. 11 Person.getCount();

3.闭包

概念:所谓闭包,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因此这些变量也是该表达式的一部分。

提出一个问题:

  1. 1 function display(){
  2. 2 var i=10;
  3. 3 }
  4. 4 display();
  5. 5 //在这里,想访问局部变量i

在全局中,不能访问局部变量i,因为作用域不同,而且,在display函数执行完毕后,局部变量i会被回收。 闭包的功能:“访问局部变量”和“使变量所占的内存不被释放”

  1. 1 //例1
  2. 2 function fn1(){
  3. 3 function fn2(){
  4. 4 alert('hello');
  5. 5 }
  6. 6 return fn2; //返回fn2函数首地址
  7. 7 }
  8. 8 var test=fn1(); //test也指向了fn2函数的首地址
  9. 9 test();

通过例1我们知道:变量是可以指向函数的首地址的,函数也可以返回另一个函数的首地址。

  1. 1 //例2
  2. 2 function fn1(){
  3. 3 var i = 10;
  4. 4 function fn2(){
  5. 5 alert(i);
  6. 6 }
  7. 7 return fn2; //返回fn2函数首地址
  8. 8 }
  9. 9 var test=fn1(); //test也指向了fn2函数的首地址
  10. 10 test();

通过例2我们知道:使用一个拒不函数包含变量i,这样局部变量i的内存不会被回收。

  1. 1 //例3
  2. 2 function fn1(){
  3. 3 var i = 10;
  4. 4 function fn2(){
  5. 5 alert(i++);
  6. 6 }
  7. 7 return fn2; //返回fn2函数首地址
  8. 8 }
  9. 9 var test=fn1(); //test也指向了fn2函数的首地址
  10. 10 test();
  11. 11 test();
  12. 12 test();

在例3中,因为i的内存永远不会被回收,所以每次调用fn2,i的值会+1。运行的结果是弹出10,弹出11,弹出12。

闭包的原理:在例3中,共有三个作用域:全局作用域,fn1的作用域,fn2的作用域。在全局作用域里有test=fn1(),其实这句话就相当于test=fn2。在fn1作用域里有 var i=10和return fn2,在fn2作用域例有alert(i++)。当全局作用域下的test=fn1()执行时,test指向了fn2的作用域,这个时候fn2作用域下的i被全局作用域钩住,根据作用域链的法则,fn2下并没有定义i,所以在fn2下的i往上一层作用域上找,找到了fn1作用域下的var i=10。所以全局的test钩住了fn2的i,fn2的i钩住了fn1的i,所以fn1运行完毕后,不会被回收。

4.私有属性

在面向对象思想中,对于有些敏感的,不想公开的成员可以定义为私有的,在JavaScript中可以模拟这个功能。

语法:

function Person(p_name){

var name = p_name;

  this.age

}

var :私有

this :公有

  1. function Person(p_name,p_age){
  2. this.name = p_name;
  3. var age = p_age;
  4. }
  5. var p1 = new Person('zhangsan',30);
  6. alert(p1.name);
  7. alert(p1.age);

在上面这个例子中,我们想用var来表示私有成员属性,但Person构造函数执行完毕后,age会被回收,不能当做成员属性来使用。

  1. function Person(p_name,p_age){
  2. this.name = p_name;
  3. var age = p_age;
  4. this.setAge=function(a){
  5. age = a;
  6. }
  7. this.getAge=function(){
  8. return(age);
  9. }
  10. }
  11. var p1 = new Person('zhangsan',30);
  12. p1.setAge(20);
  13. alert(p1.getAge());

this.setAge和this.getAge两个方法使用到了局部变量age,所以age不会被回收。

如果只有set方法,说明该属性是只写属性。

如果只有get方法,说明该属性是只读属性。

5.call和apply的使用

call和apply的功能:使用指定的对象调用当前函数。call和apply的功能完全相同,只是在语法上略有不同。

语法:

call([thisObj[,arg1[,arg2[,argN]]]])

第一个参数:函数执行时,this指向谁

后面的参数:根据需要顺序指定

apply([thisObj[,argArray]])

第一个参数:函数执行时,this指向谁

第二个参数:数组,表示参数集合

在js中,函数有几种调用形式:

Person();                      //Person内的this指向window

var p1=new Person();    //Person内的this指向p1

per.Person();                 //Person内的this指向per

  1. function Person(p_name,p_age){
  2. this.name = p_name;
  3. this.age = p_age;
  4. }
  5. function speak(){
  6. alert(this.name + this.age);
  7. }
  8. var p1 = new Person('zhangsan',30);
  9. //speak(); 这样调用this指向window
  10. //p1.speak(); p1对象没有speak属性

使用call和apply来调用

  1. function Person(p_name,p_age){
  2. this.name = p_name;
  3. this.age = p_age;
  4. }
  5. function speak(){
  6. alert(this.name + this.age);
  7. }
  8. var p1 = new Person('zhangsan',30);
  9. speak.call(p1);
  10. speak.apply(p1);

call和apply在执行时做了两件事:1)将函数内部this指向了第一个参数   2)调用函数

另外:还可以这样解决问题:

P1.say=speak;

P1.say();

这样解决和上面解决方法有本质上的区别:

上面的解决办法是直接调用speak函数,只不过函数内部this的指向发生改变。

下面的解决办法会为p1对象增加属性,p1对象的“体积”会变大。

举例说明:

  1. <script>
  2. function fn1(){
  3. this.style.color='red';
  4. }
  5. function fn2(){
  6. this.style.fontSize='50px';
  7. }
  8. window.onload=function(){
  9. document.getElementById('btn').onclick=function(){
  10. var div1 = document.getElementById('div1');
  11. fn1.call(div1);
  12. fn2.apply(div1);
  13. };
  14. };
  15. </script>
  16. <div id='div1'>hello javascript</div>
  17. <input type='button' id='btn' value='确定'>

6.继承的三种实现方法

概念:在有些面向对象语言中,可以使用一个类(子类)继承另一个类(父类),子类可以拥有父类的属性和方法,这个功能可以在js中进行模拟。

三种方法:

第一种:扩展Object方法

  1. Object.prototype.方法=function(父类对象){
  2. for(var i in 父类对象){
  3. this[i] = 父类对象[i];
  4. } 
  5. };

举例说明:

  1. Object.prototype.ext=function(parObject){
  2. //循环遍历父类对象所有属性
  3. for(var i in parObject){
  4. //为子类对象添加这个遍历到的属性
  5. //它的值是父类对象这个属性的属性值
  6. this[i] = parObject[i];
  7. }
  8. }
  9. function Person(p_name,p_age){
  10. this.name=p_name;
  11. this.age=p_age;
  12. this.speak=function(){
  13. alert(this.name+this.age);
  14. }
  15. }
  16. function Student(p_no){
  17. this.no=p_no;
  18. this.say=function(){
  19. alert(this.no+this.name_this.age);
  20. }
  21. }
  22. var stu = new Student(101);
  23. stu.ext(new Person('xiaoqiang',20));
  24. stu.speak();
  25. stu.say();

第二种:使用call和apply方法

语法:

父类构造器.call(this,.......);

  1. function Person(p_name,p_age){
  2. this.name=p_name;
  3. this.age=p_age;
  4. this.speak=function(){
  5. alert(this.name+this.age);
  6. }
  7. }
  8. function Student(p_no,p_name,p_age){
  9. this.no=p_no;
  10. this.say=function(){
  11. alert(this.name+this.age+this.no);
  12. }
  13. Person.call(this,p_name,p_age);
  14. }
  15. var stu = new Student(8,'zhagsan',18);
  16. stu.speak();
  17. stu.say();

第三种:原型继承

语法:

子类.prototype = new 父类();

  1. function Person(p_name,p_age){
  2. this.name=p_name;
  3. this.age=p_age;
  4. this.speak=function(){
  5. alert(this.name+this.age);
  6. }
  7. }
  8. function Student(p_no){
  9. this.no=p_no;
  10. this.say=function(){
  11. alert(this.name+this.age+this.no);
  12. }
  13. }
  14. Student.prototype = new Person('wangwu',21);
  15. var stu = new Student(10);
  16. stu.speak();
  17. stu.say();

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

  1. python基础-类的属性(类属性,实例属性,私有属性)

      一:类的属性 类的属性分为:类属性(公有属性),实例属性和私有属性. 1)类属性(公有属性(静态字段): 类定义时直接指定的属性(不是在__init__方法中),可以通过类名直接访问属性,并且保存 ...

  2. day16-封装(私有静态属性、私有属性、私有方法、类方法、静态方法)

    # 一: class P: __age = 30 #私有静态属性 def __init__(self,name): self.__name = name #私有属性:属性名前面加上双下划线是私有属性. ...

  3. 洗礼灵魂,修炼python(33)--面向对象编程(3)—特殊类方法__init__,公有属性,私有属性

    在上一篇博文里,传入参数时,是在实例化对象后且在调用方法时才传入参数,感觉是不是有点繁琐对吧?可以在实例化的时候就传入参数吗?可以的,这就是本篇博文的要讲到的构造器——__init__(两边双下划线) ...

  4. 【python】-- 类的实例化过程、特征、共有属性和私有属性

    实例化过程 1.类的定义和语法 class dog(object): #用class定义类 "dog class" #对类的说明 def __init__(self,name): ...

  5. Python的程序结构[0] -> 属性/Property[0] -> 类属性、实例属性和私有属性

    类属性.实例属性和私有属性 Python中类的属性主要包括类属性,实例属性和私有属性,下面是对三种属性的简单介绍 类属性 / Class Property 类属性在__init__()之外初始化,在外 ...

  6. JavaScript面向对象(三)——继承与闭包、JS实现继承的三种方式

      前  言 JRedu 在之前的两篇博客中,我们详细探讨了JavaScript OOP中的各种知识点(JS OOP基础与JS 中This指向详解 . 成员属性.静态属性.原型属性与JS原型链).今天 ...

  7. js面向对象(对象/类/工厂模式/构造函数/公有和原型)

    https://www.cnblogs.com/sandraryan/ 什么是对象 js中一切都是对象(有行为和特征).js允许自定义对象,也提供了内建对象(string date math等) 对象 ...

  8. python面向对象的特点,类定义等,私有属性、公有属性、成员属性

    引子:类的对象在内存中的表示def dog(name,dog_type): def bark(d): print(d,'wang wang wang ...') data = { 'name':nam ...

  9. JS面向对象编程创建类的方式

    js创建类的方式有几种,大致如下: 1,构造函数方式: function Car(parameters) { this.name = "objectboy"; } var cat1 ...

随机推荐

  1. JAVA基础研究

    package Test; public class L3_1 { public static void main(String[] args) { C c1=new C(100); C c2=new ...

  2. LINUX 根目录说明

    linux目录:/bin      bin是Binary的缩写.这个目录存放着最经常使用的命令./boot 这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件./data / ...

  3. Vue - 自定义指令

    1.Vue.directive(id,definition)注册一个全局自定义指令,接收两个参数,指令ID以及定义对象 2.钩子函数:将作用域与DOM进行链接,链接函数用来创建可以操作DOM的指令 b ...

  4. 一些关于HTML与CSS的总结与实际应用

    //学习前端也快一年了,觉得有必要好好总结一下这一年来学过的知识.一些是前辈们的精华,文章最后会讲地址一一放出,若原作者有任何介意,请及时联系我删除. 关于DOCTYPE 1.DOCTYPE的作用是什 ...

  5. kafka的log存储解析——topic的分区partition分段segment以及索引等

    转自:http://blog.csdn.net/jewes/article/details/42970799 引言 Kafka中的Message是以topic为基本单位组织的,不同的topic之间是相 ...

  6. 泛型的排序问题(Collections.sort及Comparable的应用)

    一.前言    java中对泛型(集合类型)排序的问题,主要采用了两张方式一种是对要排序的实体类,实现Comparable接口,另一种方式,Collections集合工具类进行排序. 二.实现Comp ...

  7. UVALive-4839 HDU-3686 Traffic Real Time Query System 题解

    题目大意: 有一张无向连通图,问从一条边走到另一条边必定要经过的点有几个. 思路: 先用tarjan将双连通分量都并起来,剩下的再将割点独立出来,建成一棵树,之后记录每个点到根有几个割点,再用RMQ求 ...

  8. 做 Web 开发少不了这些的

    抱歉,似乎有些标题党了.最近做服务器的热备,整理了些李纳斯工具的适用方法.看看还有不错的. 基本命令 sleep 500 暂停 ctrl + z 暂停 progress & 后台运行 jobs ...

  9. MVC Razor视图引擎的入门

    首先我们来说说他的给我们开发者带来那些好处吧: Razor语法易于输入,易于阅读,微软当时是这样定义的:简洁,富有表现力和灵活性,支持所有文本编辑器,强大的智能提示功能,单元测试. Rozor文件类型 ...

  10. MongoDB和Redis-NoSQL数据库-文档型-内存型

    1NoSQL简述 CAP(Consistency,Availabiity,Partitiontolerance)理论告诉我们,一个分布式系统不可能满足一致性,可用性和分区容错性这三个需求,最多只能同时 ...