Blogger Information
Blog 29
fans 1
comment 0
visits 14917
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
JavaScript的面向对象初体验
Pharaoh
Original
328 people have browsed it

构造函数

  • 构造函数就是一个普通的函数,但具有自己的特征和用法
  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);

Correcting teacher:PHPzPHPz

Correction status:qualified

Teacher's comments:理解到位,原型链我们一般用__proto__来称呼,浏览器[[prototype]],存储着对象的构造函数的prototype
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post