博客列表 >210402 JavaScript 作用域 闭包 原型 构造函数

210402 JavaScript 作用域 闭包 原型 构造函数

xyphpblog
xyphpblog原创
2021年04月21日 19:41:57499浏览

1. 作用域

  • 全局
  • 函数

1.1 全局作用域

  1. <script>
  2. let a = 1;
  3. console.log(a);
  4. //1
  5. </script>

1.2 函数作用域

  1. let a = 1;
  2. //console.log(a);
  3. function foo() {
  4. let a = 5;
  5. return a;
  6. }
  7. console.log(foo());
  8. //5

1.3 块作用域

  • 只有在块作用域中使用let或const声明才有效,使用var无效(作用域会提升)
  1. {
  2. let m = 8;
  3. const M = 9;
  4. }
  5. console.log(M);
  6. console.log(m);
  7. //均会报错

2. 闭包

  • 用来访问函数内部的局部变量
  1. function foo() {
  2. let a = 0;
  3. return function f(params) {
  4. return a;
  5. }
  6. }
  7. let f = foo();
  8. console.log(f());

3. 循环

  • 用于遍历数组,对象

3.1 while loop

  • 数组
  1. const arr = ["cat", "dog", "pig"];
  2. let i = 0;
  3. while (i < arr.length) {
  4. console.log(`animal: ${arr[i]}`);
  5. i += 1;
  6. }
  7. //animal: cat
  8. //animal: dog
  9. //animal: pig

3.2 do…while loop

  • 数组
  1. let i = 1;
  2. do {
  3. i += 1;
  4. console.log(`animal: ${arr[i]}`);
  5. } while (i < arr.length - 1);
  6. //animal: pig

3.3 for…in

  • 对象
  1. const stu = {
  2. id: 1,
  3. name: "Jack",
  4. gender: "male",
  5. graduate: false
  6. }
  7. for (const key in stu) {
  8. console.log("%c%s", "color:green", stu[key]);
  9. }
  10. //1
  11. //Jack
  12. //male
  13. //false

3.3 迭代器

  1. for (const item of arr) {
  2. console.log(item);
  3. }
  4. //animal: cat
  5. //animal: dog
  6. //animal: pig

4. 构造函数和原型

JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。

准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype属性上,而非对象实例本身。

  • 函数本身是对象,其中一个属性为prototype
  • 可作为对象的构造器,构造函数
  • javascript没有“类”的概念,都是通过原型来实现继承

4.1 构造函数

  • 在函数中不再创建对象并返回
  • 命名一般以大写字母开头,以区分构建函数和普通函数
  • 函数作为构造函数使用时,必须使用new关键字
  • 类的实例化:通过构造函数创建对象的过程(此时构造函数可看成类)
  1. function User(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. this.info = function () {
  5. return { name: this.name, age: this.age };
  6. }
  7. }

4.2 原型

  • 每一个函数的特殊属性:prototype
  • 原型函数的实例的proto属性,相当于原型函数的prototype属性
  • 每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数。
  1. function User(params) {
  2. this.p = params;
  3. }
  4. const user = new User("hehe");
  5. console.log(user);
  6. //user对象的原型
  7. console.log(user.__proto__);
  8. //user构造函数的原型
  9. console.log(User.prototype);
  10. console.log(user.__proto__ === User.prototype);

原型链

  1. 当访问原型函数实例的属性时,会先检查该实例是否具有要访问的属性。
  2. 如果 实例 没有这个属性, 然后浏览器就会在 实例 的 proto 中查找这个属性(也就是 原型函数的.prototype)
  3. 如果 实例 的 proto 有这个属性, 那么它的 proto 上的这个属性就会被使用.
  4. 否则, 如果 实例 的 __proto 没有这个属性, 浏览器就会去查找它的 protoproto ,看它是否有这个属性.
  5. 默认情况下, 所有函数的原型属性的 proto 就是 window.Object.prototype.
  6. 所以 实例 的 protoproto (也就是 原型函数的.prototype 的 proto (也就是 Object.prototype)) 会被查找是否有这个属性.
  7. 如果没有在它里面找到这个属性, 然后就会在 实例 的 protoprotoproto 里面查找.
  8. 然而这有一个问题: 实例 的 protoprotoproto 不存在.
  9. 最后, 原型链上面的所有的 proto 都被找完了, 浏览器所有已经声明了的 proto 上都不存在这个属性
  10. 然后就得出结论,这个属性是 undefined.

常见定义做法:

  • 在构造函数内定义属性
  • 在其prototype属性上定义方法
  1. function User(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. // this.info = function () {
  5. // return { name: this.name, age: this.age };
  6. // }
  7. }
  8. //将info()放到原型prototype属性中
  9. User.prototype.info = function () {
  10. return { name: this.name, age: this.age };
  11. };
  12. //生成对象
  13. const user = new User("Tom", 23);
  14. console.log(user);
  15. //User {name: "Tom", age: 23}
  16. console.log(user.info());
  17. //{name: "Tom", age: 23}

5. 类与继承

  • 子类继承父类的属性
  • 可以重写父类方法
  • 可以有新的属性
  • 不能继承父类的私有属性
  1. class Animal {
  2. //构造方法
  3. constructor(name, leg) {
  4. this.name = name;
  5. this.leg = leg;
  6. }
  7. //原型方法
  8. info() {
  9. return { name: this.name, leg: this.leg, isPet: this.#isPet };
  10. }
  11. //静态方法
  12. static eat() {
  13. return "food";
  14. }
  15. //静态属性
  16. static nature = "creature";
  17. //私有属性
  18. #isPet = false;
  19. //访问器方法 getter, setter
  20. get isPet() {
  21. return this.#isPet;
  22. }
  23. set isPet(value) {
  24. this.#isPet = value;
  25. }
  26. }
  27. const cat = new Animal("Cat", 4);
  28. const bird = new Animal("Bird", 2);
  29. console.log(cat.info());
  30. //{name: "Cat", leg: 4, isPet: false}
  31. console.log(bird.info());
  32. //{name: "Bird", leg: 2, isPet: false}
  33. console.log(`动物吃:${Animal.eat()}`);
  34. //动物吃:food
  35. console.log(`动物本身是:${Animal.nature}`);
  36. //动物本身是:creature
  37. console.log(`猫是宠物吗? ${cat.isPet}`);
  38. //猫是宠物吗? false
  39. cat.isPet = true;
  40. console.log(`猫是宠物吗? ${cat.isPet}`);
  41. //猫是宠物吗? true
  42. //继承
  43. class Dog extends Animal {
  44. //继承
  45. //第一步必须执行父类构造方法,否则无法使用this
  46. constructor(name, type) {
  47. super(name, 4);
  48. //新成员初始化
  49. this.type = type;
  50. }
  51. info() {
  52. return { name: this.name, leg: this.leg, type: this.type };
  53. }
  54. //父类的私有属性不会被继承
  55. }
  56. const dog = new Dog("Dog", "哈士奇");
  57. console.log(dog.info());
  58. //{name: "Dog", leg: 4, type: "哈士奇"}
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议