链式操作

如是实现「对象.方法.方法.方法」这样的链式反操作呢?
可以在方法内返回对象的形式。

  1. var sched = {
  2. wakeup: function () {
  3. console.log("跑步");
  4. return this;
  5. },
  6. morning: function () {
  7. console.log("去购物");
  8. return this;
  9. },
  10. noon: function () {
  11. console.log("休息一下");
  12. return this;
  13. },
  14. };
  15. sched.wakeup().morning().noon();

对象相关的方法和属性

for…in…

:::info for...in...方法可以用来遍历对象。 :::

  1. var car = {
  2. brand: "Benz",
  3. color: "red",
  4. displacement: "3.0",
  5. lang: 5,
  6. width: 2.5,
  7. };
  8. for (const key in car) {
  9. console.log(car[key]); // "Benz" "red" "3.0" 5 2.5
  10. }

**for...in...**遍历会把对象原型上的属性都打印出来!!!

  1. Object.prototype.name = "TestPrototypeAttribute"
  2. var car = {
  3. brand: "Benz",
  4. color: "red",
  5. displacement: "3.0",
  6. lang: 5,
  7. width: 2.5,
  8. };
  9. for (const key in car) {
  10. console.log(car[key]); // "Benz" "red" "3.0" 5 2.5 TestPrototypeAttribute
  11. }

**ECMAScript**中对象的属性是无序的,所有可枚举的属性都会返回一次,但返回的顺序可能会因浏览器而异。
如果for...in...循环要迭代的变量是nullundefined,则不执行循环体。

for...in...也可以用来遍历数组:

  1. var arr = [1, 2, 3, 4, 5];
  2. for (const key in arr) {
  3. console.log(key); // 1 2 3 4 5
  4. }

obj.hasOwnProperty()

:::info Object的原型方法。
hasOwnProperty()用来判断实例对象本身是否包含某个属性(该方法不会到原型上进行查询) :::

  1. var obj = {
  2. name: "job",
  3. age: 32,
  4. };
  5. console.log(obj.hasOwnProperty(obj.name)); // true
  1. Object.prototype.name = "Object";
  2. Car.prototype = {
  3. lang: 5,
  4. width: 2.5,
  5. };
  6. function Car() {
  7. this.brand = "Benz";
  8. this.color = "red";
  9. this.displacement = "3.0";
  10. }
  11. var car = new Car();
  12. console.log(car); // Car {brand: 'Benz', color: 'red', displacement: '3.0'}
  13. // 如果不用 hasOwnProperty() 方法然后遍历 car 实例对象的属性
  14. for (const key in car) {
  15. console.log(car[key]); // "Benz" "red" "3.0" 5 2.5 Object
  16. }
  17. // 使用 hasOwnProperty() 方法判断属性是否属于实例对象本身
  18. for (const key in car) {
  19. // 只要实例化对象本身的属性
  20. if (car.hasOwnProperty(key)) {
  21. console.log(car[key]); // "Benz" "red" "3.0"
  22. }
  23. }

in 语句

:::info in用来判断实例对象是否包含某个属性,该语句和hasOwnProperty最大的区别就是in语句会到实例对象的原型上查找属性(会到原型上寻找) :::

  1. var car = {
  2. brand: "Benz",
  3. color: "red",
  4. };
  5. // 类似 car["displacement"]
  6. console.log("displacement" in car); // false
  1. Car.prototype.displacement = "3.0";
  2. function Car() {
  3. this.brand = "Benz";
  4. this.color = "red";
  5. }
  6. var car = new Car();
  7. console.log("displacement" in car); // true

instanceof 语句

:::info instanceof语句用来判断某个对象是否是某个构造函数的实例对象。(类似A对象的原型里到底有没有B构造函数的原型,原型链的关系) ::: instanceof 的原理

  1. function Car() {}
  2. var car = new Car();
  3. console.log(car instanceof Car); // true
  4. console.log(car instanceof Object); // true
  5. console.log([] instanceof Array); // true
  6. console.log([] instanceof Object); // true
  7. console.log({} instanceof Object); // true

所以这就导致了关系不是特别的明确,因为任何对象的原型链顶端都是Object.prototype

更靠谱的方式是调用Object.prototype.toString()方法。

  1. var a = [];
  2. console.log(a.constructor);
  3. console.log(a instanceof Array);
  4. console.log(Object.prototype.toString.call(a)); // 使用 call 改变 this 指向为 a
  5. if(Object.prototype.toString.call(a) === "[object Array]"){
  6. alert("是数组!")
  7. }

因为Array构造函数重写了toString方法,所以我们只能调用Object.prototype.toString()方法。
image.png
image.png

this 指向

再谈谈this指向的问题

普通函数内部的this默认指向window

  1. function test(b) {
  2. var a = 1;
  3. var b = b;
  4. function c() {}
  5. this.d = 3; // window.d = 3
  6. }
  7. test(123);
  8. console.log(d); // 3,函数外部是可以直接访问到 d 变量的
  9. // 预编译的过程
  10. /**
  11. * AO = {
  12. * this: window,
  13. * argument: [123]
  14. * a: undefind,
  15. * b: undefind, => 123
  16. * c: function
  17. * }
  18. * GO = {
  19. * d: 3
  20. * }
  21. */

构造函数内部的this指向实例化对象

  1. function Test() {
  2. this.name = 123;
  3. }
  4. var test = new Test();
  5. /**
  6. * 实例化对象的执行过程
  7. *
  8. * 1、创建 this 对象
  9. * var this = {}
  10. *
  11. * 2、赋值原型
  12. * var this = {__proro__: Test.prototype}
  13. *
  14. * 3、属性赋值
  15. * var this = {__proro__: Test.prototype, name: 123}
  16. *
  17. * 4、返回 this 并指向实例化对象
  18. *
  19. */
  20. // 预编译的过程
  21. /**
  22. * Test 函数的 AO = {
  23. * this: {window 对象} => {__proro__: Test.prototype, name: 123}
  24. * }
  25. * GO = {
  26. * Test: function
  27. * test: undefind => {name: 123}
  28. * }
  29. */

callee

:::info callee的作用是指向当前所在函数的引用 :::

  1. function test(a, b, c) {
  2. console.log(arguments.callee); // 指向当前所在的函数
  3. // ƒ test(a, b, c) { ... }
  4. console.log(arguments.callee.length); // 3,形参的长度
  5. console.log(test.length); // 3,形参的长度
  6. console.log(arguments.length); // 2,实参的长度
  7. }
  8. test(1, 2);
  1. function test1() {
  2. // 指向 test1 函数的引用
  3. console.log(arguments.callee);
  4. // ƒ test1() {
  5. // console.log(arguments.callee);
  6. // function test2() {
  7. // console.log(arguments.callee);
  8. // }
  9. test2()
  10. }
  11. function test2() {
  12. // 指向 test2 函数的引用
  13. console.log(arguments.callee);
  14. // ƒ test2() {
  15. // console.log(arguments.callee);
  16. // }
  17. }
  18. test2()
  19. }
  20. test1()

某些时候在使用立即执行函数+递归时比较有用,比如实现函数实现 n-1 的累加

  1. // 普通函数的实现方式
  2. function test1() {
  3. console.log(arguments.callee);
  4. function test2() {
  5. console.log(arguments.callee);
  6. }
  7. test2()
  8. }
  9. test1()
  10. // 立即执行函数的实现方式
  11. var sum = (function (n) {
  12. if (n <= 1) {
  13. return 1;
  14. }
  15. // 当不知道函数名的时候如何递归?
  16. // 可以调用 callee 属性来拿到当前函数的引用
  17. return n + arguments.callee(n - 1);
  18. })(10);
  19. console.log(sum)

caller

:::info caller属性返回函数被调用是所在的函数的引用 :::

  1. test1();
  2. function test1() {
  3. test2();
  4. }
  5. function test2() {
  6. // 返回当前被调用 test2 函数的函数引用
  7. // 必须放到一个执行函数内,放到全局无效
  8. console.log(test2.caller);
  9. }
  10. // 放在全局下无效
  11. test3()
  12. function test3() {
  13. console.log(test3.caller); // null
  14. }