博客列表 >JavaScript的面向对象初体验

JavaScript的面向对象初体验

Pharaoh
Pharaoh原创
2022年07月24日 07:05:33321浏览

构造函数

  • 构造函数就是一个普通的函数,但具有自己的特征和用法
  1. var Vehicle = function () {
  2. this.price = 1000;
  3. };
  • 上面代码中,Vehicle 就是构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写
  • 构造函数的特点有两个
    • 函数体内部使用了 this 关键字,代表了所要生成的对象实例
    • 生成对象的时候,必须使用 new 命令
  • 构造函数内部,this 指的是一个新生成的空对象,所有针对 this 的操作,都会发生在这个空对象上。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即 this 对象),将其“构造”为需要的样子。
  • 如果构造函数内部有 return 语句,而且 return 后面跟着一个对象,new 命令会返回 return 语句指定的对象;否则,就会不管 return 语句,返回 this 对象
  1. var Vehicle = function () {
  2. this.price = 1000;
  3. return 1000;
  4. };
  5. (new Vehicle()) === 1000
  6. // false
  • 上面代码中,构造函数 Vehicle 的 return 语句返回一个数值。这时,new 命令就会忽略这个 return 语句,返回“构造”后的 this 对象

  • 如果 return 语句返回的是一个跟 this 无关的新对象,new 命令会返回这个新对象,而不是 this 对象。这一点需要特别注意

  1. var Vehicle = function (){
  2. this.price = 1000;
  3. return { price: 2000 };
  4. };
  5. (new Vehicle()).price
  6. // 2000
  • 上面代码中,构造函数 Vehicle 的 return 语句,返回的是一个新对象。new 命令会返回这个对象,而不是 this 对象

  • 如果对普通函数(内部没有 this 关键字的函数)使用 new 命令,则会返回一个空对象

  1. function getMessage() {
  2. return 'this is a message';
  3. }
  4. var msg = new getMessage();
  5. msg // {}
  6. typeof msg // "object"
  • 上面代码中,getMessage 是一个普通函数,返回一个字符串。对它使用 new 命令,会得到一个空对象。这是因为 new 命令总是返回一个对象,要么是实例对象,要么是 return 语句指定的对象。return 语句返回的是字符串,所以 new 命令就忽略了该语句

new 命令

  • new 命令的作用,就是执行构造函数,返回一个实例对象
  1. var Vehicle = function () {
  2. this.price = 1000;
  3. };
  4. var v = new Vehicle();
  • 使用 new 命令时,它后面的函数依次执行下面的步骤
    1. 创建一个空对象,作为将要返回的对象实例
    2. 将这个空对象的原型,指向构造函数的 prototype 属性
    3. 将这个空对象赋值给函数内部的 this 关键字
    4. 开始执行构造函数内部的代码

this 关键字

  • 个人理解,只有函数调用的时候,才可以确定 this 指向,谁调用指向谁;未调用,在哪调用没关系,只和谁在调用有关
    • 全局环境下的 this ,指向全局对象
    • 全局作用域里函数其实就是 window (全局对象)的方法,所以全局作用域调用函数 this 指向 windows,
    • 内部函数中的 this,指向全局对象
    • 箭头函数在哪里定义就指向谁,箭头函数外部指向谁就指向谁,或者箭头函数没有 this
    • 构造函数的 this 指向实例对象
    • 对象里的方法 this 指向对象
    • 对象的副属性里的方法中 this 指向副属性
    • 对象里属性的值中 this,指向全局对象

prototype 属性:原型对象

每个函数都有一个 prototype 属性,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数实例共享的方法和属性,也就是说将函数用作构造函数调用(使用 new 操作符调用)的时候,新创建的对象会从原型对象上继承属性和方法

  • 每个函数都有一个 prototype 属性,指向一个对象

    • 对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型
  • 原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上

  • 原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象

原型链

  • 所有对象都有自己的原型对象(prototype),任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”:对象到原型,再到原型的原型

  • 原型链的尽头就是 null

constructor 属性

prototype 对象下有个 constructor 属性,默认指向 prototype 对象的构造函数

  • 实例对象里原型对象的 constructor 指向构建对象
  • 普通对象的 constructor 指向 Object

公有属性/方法,私有属性/方法,静态属性/方法,共享属性/方法

  • 公有是指,在外部环境中可以获取的,可以直接通过实例对象用”.”运算符操作获得。(在构造函数中用 this 进行声明)

  • 私有是指,在外部环境中不能直接访问,该属性/方法只能在对象的构造函数内访问。(声明在构造函数里的变量和方法,没有用到 this)

  • 静态是指,属性/方法是归属于构建函数/类的,而非实例对象。可以直接通过类名来调用得到func.静态方法名 = function () {....}; func.静态方法名()

  • 共享是指,实例对象之间,共享属性和方法,借助向原型对象添加属性和方法,可以实现继承

class 类

  • class 可以看作只是一个语法糖,完全可以看作构造函数的另一种写法
  • 使用的时候,也是直接对类使用 new 命令,跟构造函数的用法完全一致

constructor()方法

  • constructor()方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法
  • constructor()方法默认返回实例对象,也就是 this 的指向

super 关键字

  • super 这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同

    • super 作为函数调用时,代表父类的构造函数,子类的构造函数必须执行一次super 函数,且只能用在构造函数中,用在其他地方就会报错
  • super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类

实例

  1. <script>
  2. // 构造函数
  3. let Animal = function (name) {
  4. this.height = 120;
  5. this.name = name;
  6. };
  7. // 通过原型对象给实例添加共享方法
  8. Animal.prototype.walk = function () {
  9. return `${this.name} 在缓慢行动`;
  10. };
  11. Animal.prototype.foot = function () {
  12. return this.name + "有四条腿";
  13. };
  14. let tigger = new Animal("tigger");
  15. console.log(tigger);
  16. console.log(tigger.foot());
  17. console.log(tigger.walk());
  18. let cat = new Animal("cat");
  19. console.log(cat);
  20. console.log(cat.walk());
  21. </script>

  1. <script>
  2. // class用法
  3. class animal {
  4. // 私有属性 只能在类内部使用
  5. #foot = 4;
  6. // constructor 引用构造函数
  7. constructor(name) {
  8. // this指向animal的实例化对象
  9. // 公有属性
  10. this.name = name;
  11. }
  12. // 共享方法/属性,和构造函数的prototype对象的一样
  13. walk() {
  14. return this.name + "开始行走";
  15. }
  16. run() {
  17. return this.name + "跑向猎物";
  18. }
  19. // 静态只需要在前面机上static关键字
  20. // 如果静态方法包含this关键字,这个this指的是类,而不是实例
  21. static eat() {
  22. console.log("快跑野兽要进食了");
  23. }
  24. }
  25. // 静态属性
  26. animal.live = "live";
  27. // new一个对象
  28. let tigger = new animal("tigger");
  29. // 调用静态方法
  30. animal.eat();
  31. console.log(tigger.walk());
  32. console.log(tigger.run());
  33. console.log(animal.live);
  34. // 继承
  35. class Dog extends animal {
  36. constructor(name, color) {
  37. // 子类必须使用一次super函数
  38. super(name);
  39. this.color = color;
  40. }
  41. growl() {
  42. console.log("growl");
  43. }
  44. // 访问器属性 get set方法读写
  45. get dogColor() {
  46. console.log(this.color);
  47. }
  48. set reColor(value) {
  49. this.color = value;
  50. }
  51. }
  52. // 父类的静态方法会也被子类继承
  53. Dog.eat();
  54. let lucky = new Dog("lucky", "black");
  55. console.log(lucky.walk());
  56. lucky.reColor = "white";
  57. lucky.dogColor;
  58. </script>

解构赋值

从数组和对象中提取值,对变量进行赋值,这被称为解构

实例

  1. let [a, b, c] = [1, 2, 3];
  2. // 如果解构不成功,变量的值就等于undefined
  3. var [j, q, k] = [11, 12];
  4. console.log(j, q, k);
  5. // 可以使用默认的值来避免结构不成功造成的undefined
  6. var [j, q, k = 13] = [11, 12];
  7. console.log(j, q, k);
  8. // 使用...rest参数把多余的值,放入一个数组
  9. let [z, x, ...v] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
  10. console.log(z, x, v);
  11. // 两个变量交换值很方便
  12. let [one, two] = [10, 100];
  13. console.log(one, two);
  14. one = one + two;
  15. two = one - two;
  16. one = one - two;
  17. console.log(one, two);
  18. // 上面方法太麻烦了
  19. // 再用解构的方法变回去
  20. [one, two] = [two, one];
  21. console.log(one, two);
  22. // 对象解构
  23. let { name, age, sex } = { name: "terry", age: 28, sex: "male" };
  24. console.log(name, age, sex);
  25. // 更新使用括号当作表达式
  26. ({ name, age, sex } = { name: "marry", age: 26, sex: "female" });
  27. console.log(name, age, sex);
  28. // 变量名冲突
  29. ({
  30. name: nickname,
  31. age,
  32. sex,
  33. } = { name: "jordan", age: 36, sex: "female" });
  34. console.log(nickname, age, sex);
  35. // 函数的参数解构
  36. function pValues({ name, age, sex }) {
  37. console.log(name, age, sex);
  38. }
  39. let userValues = { name: "ice", age: 26, sex: "male" };
  40. pValues(userValues);

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议