[关闭]
@GivenCui 2016-05-28T14:13:54.000000Z 字数 14819 阅读 772

第一课 JS中的面向对象(0523)_JS高级教程

js高级



目录



JS课程合集跳转链接


待整理内容



第一课 JS中的面向对象(0523)


一、JS中的相关概念

  1. 内置对象 Object、String、Math、Array、Function、Number
  2. 宿主对象 BOM / DOM 等对象
  3. 自定义对象
  1. // 用字面量语法创建了一个对象
  2. // 注意: {}
  3. var obj = {
  4. // 属性
  5. name : "小明",
  6. age : 18
  7. };

1. 面向过程思想

  • 思想:解决某个问题,看的是"如何"解决这个问题,是一种数学逻辑的映射,按照步骤执行.
  • 定义:

2. 面向对象思想(封装/继承/多态)

  • 思想: 解决某个问题,看的是"谁"来解决这个问题,把问题拆解成各个对象处理相应的功能逻辑(回到了面向过程),"对象"之间协同完成工作,是一种生活逻辑的映射.

经典的例子--盖房子


面向对象盖房子.gif-19.5kB


传统的面向对象必须提及的两个概念: 类 和 对象

唯独JS, JS没有类的对象(最新版有类的概念但是与其他程序不一样);
[类] : 是一类事物的抽象,是创建对象的模板.
[对象] : 是某个类抽象的一个实例. (真实的产物)

例子 对象
亚洲人 奥巴马
跑车 布加迪威龙限量版
hero 葫芦娃 美国队长,钢铁侠,绿巨人

封装 :例如函数,引用.js的文件等(例如c语言的结构体)
函数,从封装的角度讲,是对功能逻辑的一种封装,在面向对象中叫做方法
,是对属性(特征)方法(行为)的一种封装.


[总结] : js中没有"类"的概念,但是我们做的是面向对象编程,我们最更本的是要利用"对象"去编程,"对象"是编程的基本单位.js中虽然没有"类",但我们可以模拟"类"的概念.有"对象"的前提一定得先有"类"


内存的五大类

C语言中程序存储时分三类:
分为 代码区(text)、数据区(data)和未初始化数据区(bss) 3个部分
程序运行时候分五类 :
分为 代码区、初始化数据区、未初始化数据区、堆区和栈区 5个部分

1.栈内存

  • var变量实际上是个指针,是通过指针指向某个对象.
  • 栈中存储的是指针变量.

2.堆内存

  • 通过new关键字创建的对象都会存储在堆内存中.
  • 堆内存中存放的是数据块.

对象内存分析图.gif-13kB

相关知识链接 : C语言中内存分配

二、创建对象

1.构造函数方式创建对象

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. </head>
  6. <body>
  7. <script type="text/javascript">
  8. //通过构造函数创建对象
  9. /*
  10. 注意:构造函数和普通的函数一样,但为了区分,我们往往把构造函数的首字母大写。
  11. */
  12. //声明“类”,用来创建对象
  13. //一般构造函数的参数就是属性需要什么,我们传什么
  14. function Person (name, age) {
  15. //声明属性
  16. //this代表当前对象实例
  17. // this.name = "林心如";
  18. // this.age = 40;
  19. //这样不会把名字和年龄写死,通过构造函数的参数变活了。
  20. this.name = name;
  21. this.age = age;
  22. //声明一个私有属性
  23. //私有属性就是外部函数无法直接访问到
  24. var _height = 172;
  25. //模拟JS中set 和 get访问器 来访问私有属性
  26. //设值方法 (访问私有变量)
  27. this.setHeight = function (height) {
  28. _height = height;
  29. }
  30. //取值方法 (访问私有变量)
  31. this.getHeight = function () {
  32. return _height;
  33. }
  34. //声明方法
  35. this.sayHello = function () {
  36. console.log("大家好,我是:" + this.name + ",我的年龄是:" + this.age);
  37. }
  38. }
  39. //给Person添加一个静态方法(类方法),静态方法是直接通过构造函数的名字调用的,不关心有没有对象实例的存在。
  40. //例如:Math.random();
  41. Person.staticFn = function () {
  42. console.log("这仅仅是一个直接用构造函数名字调用的静态方法.");
  43. }
  44. //一般我们可以用静态方法去创建对象,这样可以简化代码,实质上还是用new + 构造函数创建对象
  45. Person.createPerson = function (name, age) {
  46. var tempPerson = new Person(name, age);
  47. return tempPerson;
  48. }
  49. //通过Person构造函数创建一个对象实例
  50. //注意:通过new 和 构造函数 去创建对象
  51. /*
  52. 来看下new Person() 在内存中都做了什么?
  53. 通过new关键字创建的对象 都会存储在 堆内存中。
  54. */
  55. /*
  56. 只要看到new + 构造函数,就代表在堆内存中开辟了一块空间(对象),同时会生成一个地址。我们想访问这块空间(对象),只能通过变量指针(person1)来访问,有的时候我们会说person1就是对象,其实是不对的,person1是指向了那个对象的一个指针而已。
  57. */
  58. var person1 = new Person("林心如" , 40);
  59. //用对象调用方法
  60. person1.sayHello();
  61. // 这里没有生成新的对象,而是person2指针指向了和person1指针相同的内存地址。也就是搜,person1 和person2 都可以操作这个内存地址生成的对象。
  62. var person2 = person1;
  63. //修改person2的名字 和 年龄
  64. person2.name = "范冰冰";
  65. person2.age = 36;
  66. //调用person2的sayHello方法
  67. person2.sayHello();
  68. //这里调用person1的sayHello方法
  69. person1.sayHello(); //经验证,person1 和person2指向的是一个对象,因为修改了person2的name值,person1的值也跟着改变了。
  70. //还可以直接判断两个指针是否指向同一块内存空间
  71. console.log(person1 === person2);
  72. //再创建一个新的对象
  73. var person3 = new Person("随便叫", 50);
  74. person3.name = "尔康";
  75. person3.sayHello();
  76. person1.name = "孟丹";
  77. person2.sayHello();
  78. person1.sayHello();
  79. //instanceof 运算符用来判断 一个变量指针是否是通过某个构造函数创建出来的。
  80. //Object 是万物的根本,是所有对象的根(基)对象
  81. console.log(person1 instanceof Person); //true
  82. console.log(person1 instanceof Object); //true
  83. console.log(person1 instanceof String); //false
  84. //typeof 判断类型
  85. console.log(typeof person1);
  86. console.log(typeof "");
  87. //测试能否直接访问到私有属性
  88. // person3._height = 555; 这个代表动态的插入一个可以直接访问到的属性_height,和 构造函数中的 var _height 不是一个。
  89. // console.log(person3._height); //undefined
  90. //通过自己写的一个set和get访问器来访问_height
  91. console.log(person3.getHeight());
  92. person3.setHeight(555);
  93. console.log(person3.getHeight());
  94. //使用静态方法
  95. Person.staticFn();
  96. //通过静态方法创建对象
  97. //静态方法创建对象,纯属是为了简化代码,其核心内部还是用new去创建对象
  98. var person4 = Person.createPerson("尔泰", 88);
  99. person4.sayHello();
  100. </script>
  101. </body>
  102. </html>

2. 原型模式创建对象

【原型模式创建对象】
每个构造函数都有一个原型属性(prototype),这个原型属性指向一个原型对象,可以给这个原型对象声明属性和方法,这个属性和方法可以给通过构造函数创建出来的对象实例使用。换句话说,也可以理解为,每个构造函数创建出来的对象实例,继承于这个原型对象的属性和方法。

【总结】所谓原型模式创建对象其核心还是通过构造函数创建对象,只不过方法是通过原型模式创建的

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>原型模式创建对象</title>
  6. <script type = "text/javascript">
  7. //狗的构造函数
  8. function Dog (name) {
  9. this.name = name;
  10. // this.bark = function () {
  11. // console.log("旺旺旺");
  12. // }
  13. //全局函数虽然能解决函数共享的问题,但不适合
  14. // this.bark = globalFn;
  15. }
  16. //弄一个全局函数,这样可以解决每次创建对象都开辟一个空间去存储function。
  17. function globalFn () {
  18. console.log("汪汪汪");
  19. }
  20. //通过Dog的原型对象声明bark方法,这样可以达到函数共享,节约性能
  21. Dog.prototype.bark = function () {
  22. console.log("原型 汪汪汪");
  23. }
  24. //创建一只狗的对象
  25. var dog1 = new Dog("妞妞");
  26. //在创建一只狗的对象
  27. var dog2 = new Dog("Nimo");
  28. //验证一下这两只狗的bark方法是否指向同一个function对象的方法
  29. console.log(dog1.bark === dog2.bark);
  30. </script>
  31. </head>
  32. <body>
  33. </body>
  34. </html>

三、对象的属性详解

全局属性

全局属性类似全局变量,只不过全局变量是window的属性,而全局属性是某个创建对象的属性

  1. // 全局变量
  2. var x = 3;
  3. console.log(x); // 在全局环境中可以访问
  4. console.log(window.x);
  5. // 全局属性
  6. function Person () {
  7. this.name = "我是全局属性";
  8. }
  9. var xiaoMing = new Person();
  10. console.log(xiaoMing.name); // 在全局环境中可以访问

私有属性

类似于局部变量,不能在全局环境中正常访问到

  1. function Person () {
  2. var name = "我是私有属性";
  3. // 不是指私有于某个具体对象
  4. // 是指在访问权限受限,不能被正常访问
  5. // 可以通过 getter 和 setter 来访问和操作
  6. }

私有属性访问器

自定义属性访问器

  1. function Person (name, age) {
  2. //声明全局属性
  3. //this代表当前对象实例
  4. this.name = name;
  5. this.age = age;
  6. //声明一个私有属性
  7. //私有属性就是外部函数无法直接访问到
  8. var _height = 172;
  9. //模拟JS中set 和 get访问器 来访问私有属性
  10. //设值方法 (访问私有变量)
  11. this.setHeight = function (height) {
  12. _height = height;
  13. }
  14. //取值方法 (访问私有变量)
  15. this.getHeight = function () {
  16. return _height;
  17. }
  18. }

原生JS定义访问器方法
Object.defineProperty(this,"私有变量名",{ 字面量对象的方法 });
用的时候直接正常调用即可

  1. ```javascript
  2. // 人的构造函数
  3. function Person() {
  4. // 私有属性
  5. var name = "能看见我不???";
  6. // 给当前对象的name属性添加 set 和 get 访问器或构造器
  7. /**
  8. * [set description]
  9. *
  10. *
  11. */
  12. Object.defineProperty(this,"name",{
  13. set : function(newName){
  14. // 其牛逼之处!!能filter
  15. if(newName === "小明"){
  16. name = newName;
  17. return;
  18. }
  19. console.log("不好意思,我们只要小明!");
  20. },
  21. get : function(){
  22. console.log("这是name属性的get访问器");
  23. return name;
  24. }
  25. });
  26. }

四、prototype相关概念

原型模式

每一个构造函数都有一个原型属性(prototype),这个原型属性指向一个原型对象,可以给这个原型对象声明属性和方法,该属性和方法可以给通过构造函数创建出来的对象实例使用.换句话说,也可以理解为,每个构造函数创造出来的对象实例,继承于原型对象的属性和方法.所谓原型模式创建对象的核心还是通过构造行数创建对象,只不过方法是通过原型模式创建的.

原型链

每个对象都有一个原型对象,而原型对象它也是个对象,既然是对象也会相应的原型对象,以此类推,直到Object.prototype. Object.prototype它的原型是null(到头了).

prototype有一个属性 __proto__

例如: a对象是b对象的原型对象,b对象是c对象的原型对象,那么a/b/c就在一条原型链了,那么abc对象都可以访问原型链上的任何对象和属性.

  1. // 猫的构造函数
  2. function Cat() {
  3. }
  4. // 动物的构造函数
  5. function Animal(){
  6. this.name = "动物";
  7. }
  8. // 给Animal构造函数设置原型对象
  9. Animal.prototype = {
  10. sex: "女",
  11. sayHello : function(){
  12. console.log("大家好");
  13. }
  14. };
  15. // 给Cat构造函数设置原型对象 (绑在了原型链子上)
  16. Cat.prototype = new Animal(); // 为了简化开发
  17. // 创建一只猫的对象
  18. var cat1 = new Cat();
  19. // cat1对象先去查找自身构造函数是否有name/sex等属性和方法,如果有就直接用自己,如果没有,一直沿着原型链找到Object.prototype为止.如果还没有,就会报undefined;
  20. console.log(cat1.name); // 访问的是Animal的name属性
  21. console.log(cat1.sex);
  22. cat1.sayHello();

五、通过prototype的字面量对象方式创建方法

demo举例

  1. // {} 表示字面量创建对象,其内部的语法符合JSON语法格式
  2. Animal.prototype = {
  3. sex: "女",
  4. sayHello : function(){
  5. console("大家好");
  6. }
  7. };

注意事项

函数表达式的创建方法,每新new一个对象就会默认添加一个prototype属性,同时添加一个constructor属性,而用对象字面量的方式相当于完全重写了prototype对象,所以constructor属性指向了Object,而不再指向它的构造函数了!!!!
添加 constructor : 构造函数名来修正这个问题

  1. // {} 表示字面量创建对象,其内部的语法符合JSON语法格式
  2. Animal.prototype = {
  3. constructor : Animal; // 修正指向的问题
  4. sex: "女",
  5. sayHello : function(){
  6. console("大家好");
  7. }
  8. };

总结

总结 : 编程时务必要遵守。下文都遵循这一点,即如果替换了prototype对象,

  1. O.prototype = {};

那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。

  1.   O.prototype.constructor = O;
  2.  // 或
  3.   O.prototype = {
  4.    constructor : O,
  5.   };

六、原型相关的属性和方法

obj.prototype.constructor属性 :

每个对象都有一个constructor属性,这个属性默认是指原型对象所在的构造函数.

  1. // 人的构造函数
  2. function Person(){
  3. }
  4. // 给人的原型对象设置一个方法
  5. Person.prototype.sayHello = function(){
  6. console.log("大家好");
  7. }
  8. // 创建一个人的对象
  9. var person1 = new Person();
  10. // 测试
  11. console.log(Person.prototype.constructor);
  12. /*
  13. person1本身没有constructor属性,是通过原型链往上找的,找到Person.prototype里才发现有的
  14. */
  15. console.log(person1.constructor);

obj.hasOwnProperty属性 :

判断某个对象是否存在某个属性.

  1. // > > 接上面
  2. // 验证了constructor只是prototype原型链中的属性
  3. console.log(person1.hasOwnProperty("constructor")); // false
  4. console.log(Person.prototype.hasOwnProperty("constructor")); //true

Object.getPrototypeOf(obj)方法 :

返回一个对象的原型对象

  1. // 返回person1的原型对象
  2. console.log(Object.getPrototypeOf(person1));

Object.create(obj)方法 :

根据接收参数对象,来创建一个新的对象,前者是这个新对象的原型.

  1. // 字面量创建一个对象
  2. var o1={};
  3. // 通过Object.create()方法创建新的对象
  4. // 内部的实现是 new + 构造函数名
  5. var o2 = Object.create(o1);
  6. var o3 = Object.create(o2);

obj1.isPrototypeOf(obj2)方法 :

判断一个对象是否是另外一个对象的原型对象.

  1. // 判断o1是否是o2的原型对象
  2. console.log(o1.isPrototypeOf(o2));
  3. console.log(o1.isPrototypeOf(o3));

Object.defineProperty(this,"name",{ })的方法

  • 写在私有属性的下面
  • 参数1: this
  • 参数2: "私有属性变量名"
  • 参数3: {}里面是个json的对象
  1. // 人的构造函数
  2. function Person() {
  3. // 私有属性
  4. var name = "能看见我不???";
  5. // 给当前对象的name属性添加 set 和 get 访问器或构造器
  6. /**
  7. * [set description]
  8. *
  9. *
  10. */
  11. Object.defineProperty(this,"name",{
  12. set : function(newName){
  13. // 其牛逼之处!!能filter
  14. if(newName === "小明"){
  15. name = newName;
  16. return;
  17. }
  18. console.log("不好意思,我们只要小明!");
  19. },
  20. get : function(){
  21. console.log("这是name属性的get访问器");
  22. return name;
  23. }
  24. });
  25. }
  26. // 创建一个人的对象
  27. var person1 = new Person();
  28. console.log(person1.name); // 取值操作
  29. //person1.name = "小红"; // 赋值操作 (是错的)
  30. person1.name = "小明"; // 赋值操作 (是对的)
  31. console.log(person1.name); // 取值操作

七、实现继承的几种方法

--> 构造函数的继承

需求 : 需要猫去继承动物,如下代码如何实现??

  1. // 构造函数之动物
  2. function Animal(){
  3.     this.species = "动物";
  4.   }
  5.   
  6. // 构造函数之猫 (猫是动物的子类)
  7. function Cat(name,color){
  8.     this.name = name;
  9.     this.color = color;
  10.   }
方法一 : 构造函数绑定

第一种方法也是最简单的方法,使用call或apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:

  1. function Cat(name,color){
  2.     Animal.apply(this, arguments); // 继承的关键
  3.     this.name = name;
  4.     this.color = color;
  5.   }
  6.   var cat1 = new Cat("大毛","黄色");
  7.   alert(cat1.species); // 动物
方法二 : prototype模式

第二种方法更常见,使用prototype属性。如果"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了。

  1. Cat.prototype = new Animal(); // 实现继承的关键
  2. Cat.prototype.constructor = Cat; // 修正constructor问题
  3. var cat1 = new Cat("大毛","黄色");
  4. alert(cat1.species); // 动物
方法三 : 直接继承prototype

第三种方法是对第二种方法的改进。由于Animal对象中,不变的属性都可以直接写入Animal.prototype。所以,我们也可以让Cat()跳过 Animal(),直接继承Animal.prototype。但是也带来了相关问题

  1. function Animal(){ }
  2.   Animal.prototype.species = "动物";
  3. // 将Cat的prototype对象,然后指向Animal的prototype对象,这样就完成了继承。
  4.   Cat.prototype = Animal.prototype;
  5.   Cat.prototype.constructor = Cat;
  6.   var cat1 = new Cat("大毛","黄色");
  7.   alert(cat1.species); // 动物
  8. /*
  9. 与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存。
  10. 缺点是 Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype。
  11. 所以,上面这一段代码其实是有问题的。请看第三行
  12.   Cat.prototype.constructor = Cat;
  13. 这一句实际上把Animal.prototype对象的constructor属性也改掉了!
  14.   alert(Animal.prototype.constructor); // Cat
  15. */
方法四 : 利用空对象做中介

由于"直接继承prototype"存在上述的缺点,所以就有第四种方法,利用一个空对象作为中介。

  1. var F = function(){}; // 空对象
  2.   F.prototype = Animal.prototype;
  3.   Cat.prototype = new F(); // 空对象是"中介"
  4.   Cat.prototype.constructor = Cat;
  5. // F是空对象,所以几乎不占内存。这时,修改Cat的prototype对象,就不会影响到Animal的prototype对象。
  6.   alert(Animal.prototype.constructor); // Animal

方法四:封装成一个函数来使用

  1. // 我们将上面的方法,封装成一个函数,便于使用。
  2.   function extend(Child, Parent) {
  3.     var F = function(){};
  4.     F.prototype = Parent.prototype;
  5.     Child.prototype = new F();
  6.     Child.prototype.constructor = Child;
  7.     Child.uber = Parent.prototype;
  8.   }
  9. // 使用的时候,方法如下
  10.   extend(Cat,Animal);
  11.   var cat1 = new Cat("大毛","黄色");
  12.   alert(cat1.species); // 动物
  13. // 这个extend函数,就是YUI库如何实现继承的方法。
  14. // 另外,说明一点,函数体最后一行
  15.   Child.uber = Parent.prototype;
  16. /*
  17. 意思是为子对象设一个uber属性,这个属性直接指向父对象的prototype属性(uber是一个德语词,意思是"向上"、"上一层")。
  18. 这等于在子对象上打开一条通道,可以直接调用父对象的方法。
  19. 这一行放在这里,只是为了实现继承的完备性,纯属备用性质。
  20. */
方法五 : 拷贝继承

上面是采用prototype对象,实现继承。我们也可以换一种思路,纯粹采用"拷贝"方法实现继承。简单说,如果把父对象的所有属性和方法,拷贝进子对象,不也能够实现继承吗?这样我们就有了第五种方法。

  1. // Animal的所有不变属性,都放到它的prototype对象上
  2.   function Animal(){}
  3.   Animal.prototype.species = "动物";
  4. // 然后,再写一个函数,实现属性拷贝的目的。
  5.   function extend2(Child, Parent) {
  6.     var p = Parent.prototype;
  7.     var c = Child.prototype;
  8.     for (var i in p) {
  9.       c[i] = p[i];
  10.       }
  11.     c.uber = p;
  12.   }
  13. /*
  14. 这个函数的作用,就是将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype对象。
  15. 使用的时候,这样写:
  16. */
  17.   extend2(Cat, Animal);
  18.   var cat1 = new Cat("大毛","黄色");
  19.   alert(cat1.species); // 动物

--> 非构造函数的继承

比如 实现字面两对象的继承 举例: 医生是中国人

  1. // 字面量对象 "中国人"
  2. var Chinese = {
  3.     nation:'中国'
  4.   };
  5. // 字面量对象 "医生"
  6.   var Doctor ={
  7.     career:'医生'
  8.   }
方法一 : object()方法
方法二 : 浅拷贝
方法三 : 深拷贝

第一课的作业

作业1: 求长方形的面积

  1. /*
  2. 作业 1 ( 版本1 ) :
  3. 构造函数:长方形(有参数)
  4. 公有属性:
  5. 长:length
  6. 宽:width
  7. 求面积的方法。(原型)
  8. */
  9. function Rectangle ( length , width ) {
  10. // 公有属性
  11. this.length = length;
  12. this.width = width;
  13. }
  14. // 面积的方法
  15. Rectangle.prototype.area = function () {
  16. return this.length * this.width; // 对象中的this
  17. }
  18. // 创建一个长方形对象实例
  19. var rect1 = new rectangle(20,30); // 可以直接传参给
  20. // rect1.length = 20; // 可以后给属性赋值
  21. // rect1.width = 30; // 可以后给属性赋值
  22. console.log(rect1.area()); // 因为this,所以....
  1. /*
  2. 作业 1 (版本2) :
  3. 构造函数:长方形(无参数)
  4. 私有属性:
  5. 长:length
  6. 宽:width
  7. 属性的set 和 get访问器
  8. 求面积的方法。(原型)
  9. */
  10. // 创建长方型的类
  11. function Rectangle () {
  12. var length = 0;
  13. var width = 0;
  14. // length 属性访问器
  15. Object.defineProperty(this,"length",{
  16. set : function (x) {
  17. length = x;
  18. },
  19. get : function () {
  20. return length;
  21. }
  22. });
  23. // width 属性访问器
  24. Object.defineProperty(this,"width",{
  25. set : function (x) {
  26. width = x;
  27. },
  28. get : function () {
  29. return width;
  30. }
  31. });
  32. }
  33. // 求面积的方法
  34. Rectangle.prototype.area = function () {
  35. return this.length * this.width; // 对象中的this
  36. }
  37. // 创建一个长方形实例
  38. var rect1 = new Rectangle() ;
  39. rect1.length = 30 ;
  40. rect1.width = 20 ;
  41. console.log(rect1.area());

作业2:银行账户存取款

  1. /*
  2. 作业 2 :
  3. 构造函数:银行账户
  4. 私有属性:
  5. 账户名,
  6. 存储金额
  7. 属性访问器:
  8. 存款和取款的方法(原型)
  9. */
  10. // 创建银行账户类
  11. function BankAccount (name , money) {
  12. this.accoutName = name;
  13. this.money = money;
  14. }
  15. // 存款方法
  16. BackAccount.prototype.saveMoney = function (saveMoney) {
  17. console.log("您的" + this.accountName + "当前余额为:" + this.money+"元");
  18. this.money += saveMoney;
  19. console.log("您的" + this.accountName + "存款之后余额为:" + this.money + "元");
  20. }
  21. // 取款方法
  22. BankAccount.prototype.takeMoney = function (takeMoney) {
  23. if(takeMoney > this.money){
  24. console.log("您的账户余额不足"+"最多能取"+this.money+"元");
  25. return ;
  26. }
  27. if(takeMoney < 0){
  28. console.log("请不要逗我玩")
  29. return;
  30. }
  31. console.log("您的"+this.accountName+"当前余额为:"+this.money+"元");
  32. this.money -= takeMoney; // 注意-=而不是赋值
  33. console.log("您的" + this.accountName + "取款之后的余额为:" + this.money+"元");
  34. }
  35. // 创建银行账户实例
  36. var GivenCui_account = new BankAccount("Given Cui",100000);
  37. // 存款
  38. GivenCui_account.saveMoney(50000); // 150000
  39. GivenCui_account.saveMoney(12000); // 162000
  40. // 取款
  41. GivenCui_account.takeMoney(300);
  42. GivenCui_account.takeMoney(500000); // 真实的需求

作业3:汽车公路

以对象作为做小单位设计的好处
1. 方便以后的程序的功能扩展
2. 子功能的添加独立于其它功能
3. 更有利于团队的协同开发,有封装的思想

  1. /*
  2. 作业 3 :
  3. 构造函数:汽车、公路
  4. 私有属性:
  5. 速度(汽车)
  6. 路程长度(公路)
  7. 属性访问器:
  8. 业务方法:求车跑在路上所有时长
  9. */
  10. // 汽车类
  11. function Car (speed) {
  12. // 公有属性
  13. this.speed = speed;
  14. }
  15. // 车在路上的方法_star
  16. /*
  17. // 第一种写法
  18. // 普通的传参
  19. Car.prototype.carOnRoad = function (length) {
  20. return length / this.speed;
  21. }
  22. */
  23. // 第二种写法
  24. // 彻底的面向对象是指所有的基本单位都是对象
  25. // 所以 参数 ===>对象.属性 , 所以把对象作为参数传入
  26. Car.prototype.carOnRoad = function (road) {
  27. return road.length / this.speed;
  28. }
  29. // 车在路上的方法_end
  30. // 公路的类
  31. function Road (length) {
  32. // 公有属性
  33. this.length = length;
  34. }
  35. // 路的对象实例
  36. var road1 = new Road(100);
  37. // 车的对象实例
  38. var car1 = new Car(20);
  39. // 求解需求
  40. // console.log(car.carOnRoad(road1.length)) // 调用第一种方法
  41. console.log(car.carOnRoad(road1)) // 调用第二种方法

作业4: 左手、右手、牌

  1. /*
  2. 作业 4 :
  3. 一个人手里有两张牌,左手红桃A,右手方片K,现在让这个人交换手里的两张牌。
  4. 构造函数:人、牌
  5. 私有属性:
  6. 左手 :(人,注意:左手就是一个字符串,表示左手抓的牌是什么花色和大小)
  7. 右手 :(人,注意:同上)
  8. 牌的花色号码(牌)
  9. 业务方法:
  10. 抓拍、
  11. 交换拍、
  12. 展示牌
  13. */
  14. // 创建类"人"
  15. function Person (l_poker,r_poker) {
  16. var leftHand = l_poker.pokerType;
  17. var rightHand = r_poker.pokerType;
  18. // leftHand访问器
  19. Object.defineProperty(this, "leftHand", {
  20. set : function (x) {
  21. leftHand = x;
  22. // return // 这里不用写return
  23. },
  24. get : function () {
  25. return leftHand;
  26. }
  27. });
  28. // rightHand访问器
  29. Object.defineProperty(this,"rightHand", {
  30. set : function (x) {
  31. rightHand = x;
  32. },
  33. get : function () {
  34. return rightHand;
  35. }
  36. });
  37. }
  38. // 抓牌的方法
  39. // 传入扑克牌对象
  40. Person.prototype.fetchPoker = function (l_poker ,r_poker ) {
  41. // 传入了牌对象的pokerType属性
  42. this.leftHand = l_poker.pokerType ;
  43. this.rightHand = r_poker.pokerType ;
  44. }
  45. // 展示牌的方法
  46. // 不需要参数
  47. Person.propotype.showPoker = function () {
  48. console.log("左手的牌是" + this.leftHand + ",右手的牌是:" + this.rightHand);
  49. }
  50. // 交换牌的方法
  51. Person.propotype.swapPoker = function () {
  52. // 中间值互换
  53. var temp = this.leftHand;
  54. this.leftHand = rightHand;
  55. this.rightHand = temp;
  56. // 位操作互换
  57. }
  58. // 创建类"poker"
  59. function Poker () {
  60. > var pokerType = '';
  61. // pokerType访问器
  62. Object.defineProperty(this, "pokerType", {
  63. set : function (x) {
  64. pokerType = x;
  65. } ,
  66. get : function () {
  67. return pokerType;
  68. }
  69. });
  70. }
  71. // 创建扑克牌对象实例
  72. var poker1 = new Poker ("红桃A");
  73. var poker2 = new Poker ("方片K");
  74. var poker3 = new Poker ("大鬼");
  75. var poker4 = new Poker ("小鬼");
  76. // 创建人对象实例
  77. var xm = new Person (poker1, poker2); // 小明 ==> xm
  78. // 展示牌
  79. xm.showPoker();
  80. // 抓牌
  81. xm.fetchPoker(poker3, poker4);
  82. // 再显示
  83. xm.showPoker();
  84. // 交换牌
  85. xm.swapPoker();

(补充) JSON

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注