一、对象的链式调用

对象的链式调用,需要在方法末尾返回this;return this

  1. // 对象的链式调用,需要在方法末尾返回this;return this
  2. var sched = {
  3. wakeup: function(){
  4. console.log('Running');
  5. return this;
  6. },
  7. morning: function(){
  8. console.log('Going shopping');
  9. return this;
  10. },
  11. noon: function(){
  12. console.log('Having a rest');
  13. return this;
  14. },
  15. afternoon: function(){
  16. console.log('studying');
  17. return this;
  18. },
  19. evening: function(){
  20. console.log('walking');
  21. return this;
  22. },
  23. night: function(){
  24. console.log('sleeping');
  25. return this;
  26. }
  27. }
  28. sched.wakeup().morning().noon().afternoon().evening().night();

二、对象的成员访问

  • 对象的成员访问有两种方式

    • 对象.属性名; 这种方法最后JS引擎都会隐式转换为 对象[‘属性名’] 的方式
    • 对象[‘属性名’];如果要访问的对象属性名是数字,那就只能通过这种方式来进行成员访问,且要主要中括号中的属性名必须是字符串格式才行
    • 在使用 对象.属性名 进行成员访问的时候,JS引擎会隐式转换为 对象[‘属性名’] ```javascript // 对象的成员访问 // 对象的成员访问有两种方式 // + 对象.属性名 // + 对象[‘属性名’] 注意中括号中必须是字符串 var myLang = {

      1. No1: 'HTML',
      2. No2: 'CSS',
      3. No3: 'JavaScript',
      4. myStudyingLang: function(num){
      5. console.log(this['No' + num]);
      6. }

      }

      myLang.myStudyingLang(1);

  1. // 当对象的属性名是数字的时候,只能通过 对象['属性名'] 来进行成员访问;注意中括号中只能是字符串
  2. var obj = {
  3. name: 'kola',
  4. age: 18,
  5. 10: 20
  6. }
  7. console.log(obj.name);
  8. // console.log(obj.10);
  9. console.log(obj['10']);
  10. // 在使用 对象.属性名 进行成员访问的时候,JS引擎会隐式转换为 对象['属性名']
  11. var person = {
  12. name: '小明',
  13. age: 19
  14. }
  15. // person.name 隐式转换为 => person['name']
  16. console.log(person.name);
  17. console.log(person['name']);
  1. <a name="iYBGG"></a>
  2. # 三、对象属性的枚举「遍历」for in
  3. - for in 不仅会遍历自身的属性,同时还会遍历**原型链上自定义的属性**「只有自定义的才会被遍历」
  4. - for in 会优先遍历数字属性,且会按照数字大小进行排序遍历
  5. - for in 也可以遍历数组,因为数组也是特殊的对象
  6. - 对象的成员访问:JS引擎在早期的对象成员访问的时候,其实是没有点语法的,obj.nam -> 最终都会隐式转换为obj['name']
  7. ```javascript
  8. // 对象成员的枚举「遍历」for in
  9. // for in 不仅会遍历自身的属性,同时还会遍历原型链上自定义的属性「只有自定义的才会被遍历」
  10. // for in 会优先遍历数字属性,且会按照数字大小进行排序遍历
  11. // for in 也可以遍历数组,因为数组也是特殊的对象
  12. // 数组的遍历
  13. var arr = [1, 2, 3, 4];
  14. for(var i = 0; i < arr.length; i++){
  15. console.log(arr[i]);
  16. }
  17. var car = {
  18. brand: 'Benz',
  19. color: 'red',
  20. displacement: '3.0',
  21. lang: '5.0',
  22. width: '2.5'
  23. }
  24. for(var key in car){
  25. // console.log(key);
  26. // console.log(car.key); // 这样是不行的,car.key -> 会转换为 car['key'] 输出undefined
  27. console.log('key' + ':' + car[key]);
  28. }

for in 不仅可以用来遍历对象,同时也可以用来遍历数组

  1. // for in 不仅可以用来遍历对象,同时也可以用来遍历数组
  2. var arr = [11, 22, 33, 44];
  3. for(var i in arr){
  4. console.log(arr[i]);
  5. }

四、hasOwnProperty会排除原型链上的自定义属性

  • 排除原型链上的自定义属性,只寻找对象自身的属性

    1. // hasOwnProperty
    2. // 排除原型链上的自定义属性, 只寻找对象自身的属性
    3. var obj = {
    4. name: 'kola',
    5. age: 19,
    6. sex: 'femal',
    7. }
    8. Object.prototype.height = 175;
    9. console.log(obj.hasOwnProperty(obj.name)); // false
    10. console.log(obj.hasOwnProperty(obj.height)); // false
  • for in 循环是会把原型链上的自定义属性全部循环出来的

  • 现在我只想循环对象自身的属性

    1. // hasOwnProperty: 排除原型链上的自定义属性,只寻找对象自身的属性
    2. var obj = {
    3. name: 'kola',
    4. age: 18
    5. }
    6. function Car(){
    7. this.brand = 'Benz';
    8. this.color = 'red';
    9. }
    10. Car.prototype = {
    11. lang: 5,
    12. width: 2.5
    13. }
    14. Object.prototype.name = 'Object';
    15. var car = new Car();
    16. for(var key in car){
    17. // for in 循环是会把原型链上的自定义属性全部循环出来的
    18. // 现在我只想循环对象自身的属性
    19. if(car.hasOwnProperty(key)){
    20. console.log(car[key]);
    21. }
    22. }

    五、in 不会排除原型链的

  • in 是不会排除原型的

  • ‘属性名’ in 对象
  • 注意:属性名必须是字符串格式的

    1. // in 是不会排除原型链的
    2. // '属性名' in 对象
    3. // 注意属性名必须是字符串
    4. function Car(){
    5. this.brand = 'Benz';
    6. this.color = 'red';
    7. }
    8. Car.prototype = {
    9. displacement : '3.0'
    10. }
    11. var car = new Car();
    12. // in 是不会排除原型链的
    13. // '属性名' in 对象; 注意此处的属性名必须是字符串
    14. // console.log(displacement in car);
    15. // console.log(color in car);
    16. console.log('displacement' in car);
    17. console.log('color' in car);

    六、instanceof 判断对象是否是该构造函数实例化出来的

  • 对象 instanceof 构造函数

    1. // instanceof 判断某个对象是否是该构造函数实例化出来的
    2. function Car(){}
    3. var car = new Car();
    4. function Person(){}
    5. var person = new Person();
    6. console.log(car instanceof Car);
    7. console.log(car instanceof Object);
    8. console.log([] instanceof Array);
    9. console.log([] instanceof Object);
    10. console.log({} instanceof Object);

    如何判断一个变量是否为数组

    1. // 如何判断一个变量是否是数组
    2. var a = [];
    3. console.log(a.constructor);
    4. console.log(a instanceof Array);
    5. console.log(Object.prototype.toString.call(a));
    6. // Object原型上的toString方法通过改变其this指向可以实现数据类型检测「万能的」
    7. // Object.prototype = {
    8. // toString: function(){
    9. // this.toString();
    10. // }
    11. // }

    真实项目中,如何判断一个变量是数组

    1. // 真实项目中,如何判断一个变量是否是数组
    2. var arr = [];
    3. var toStr = Object.prototype.toString;
    4. var arrType = '[object Object]'
    5. if(toStr.call(arr)){
    6. console.log('是数组');
    7. }else{
    8. console.log('不是数组');
    9. }

    七、this指向

  • 函数内部的this默认指向的是window

  • 预编译阶段函数中的this指向window
  • 自执行函数中的this默认指向window
  • 构造函数中的this指向实例化对象本身
  • 可以通过call/apply/bind来改变this指向
  • 箭头函数中是没有this的,而且箭头函数是没有原型的,所以不能被new执行

函数内部中的this默认指向window,预编译阶段函数中的this默认指向的是window

  1. // this指向
  2. // + 函数内部的this默认指向的是window
  3. // + 预编译阶段函数中的this指向window
  4. // + 自执行函数中的this默认指向window
  5. // + 构造函数中的this指向实例化对象本身
  6. // + 可以通过call/apply/bind来改变this指向
  7. // 函数内部的this默认指向window
  8. function func(b){
  9. this.d = 3;
  10. var a = 1;
  11. function c(){}
  12. }
  13. func(123);
  14. console.log(d);
  15. console.log(this.d);
  16. console.log(window.d);
  17. // AO = {
  18. // arguments: [123],
  19. // this: window,
  20. // b: undefined -> 123,
  21. // a: undefined -> 1,
  22. // c: function c(){}
  23. // }

构造函数中的this指向实例化对象本身

  1. // 构造函数中的this指向实例化对象本身
  2. function Test(){
  3. // var this = {
  4. // name: 'kola',
  5. // __proto__: Test.prototype
  6. // }
  7. this.name = 'kola'
  8. // 系统默认隐式返回this
  9. // return this
  10. }
  11. var test = new Test();
  12. // GO = {
  13. // Test: function Test(){},
  14. // test: {
  15. // name: 'kola',
  16. // __proto__: Test.prototype
  17. // }
  18. // }
  19. // AO = {
  20. // name: 'kola',
  21. // __proto__: Test.prototype
  22. // }

call和apply可以更改this指向

  1. // call和apply可以更改this指向
  2. function Person(name, age){
  3. this.name = '良雨';
  4. this.age = 38;
  5. }
  6. function Programmer(){
  7. Person.apply(this);
  8. this.work = 'programming';
  9. }
  10. var programmer = new Programmer();
  11. console.log(programmer);

7.1、this指向的总结

  • 全局作用域下的this指向window
  • 预编译阶段函数中的this指向window
  • 函数内部中的this默认指向window
  • 自执行函数中的this指向window
  • 构造函数中的this指向实例化对象本身
  • 可以通过call/apply/bind来改变this的指向
  • 箭头函数中没有自己的this,而且构造函数没有原型,所以不能被new执行

    八、callee和caller

  • callee,实参集合arguments在哪个函数里,就指向哪个函数

  • caller,返回当前被调用函数的函数引用;在被调用函数里面调用被调用函数的caller,就知道谁在调用它,必须调用了才有效

    8.1、callee是arguments下的一个属性

  • callee是实参集合arguments下的一个属性;arguments在哪个函数里面就指向哪个函数

  • arguments: 实参集合
  • arguments.length: 函数的实参长度
  • func.length: 函数的形参长度
  • arguments.callee.length: 函数的形参长度

    1. // arguments: 实参集合
    2. // arguments.length: 函数的实参长度
    3. // func.length: 函数的形参长度
    4. // arguments.callee.length: 函数的形参长度
    5. function func(a, b, c){
    6. console.log(arguments.callee);
    7. console.log(arguments.callee.length);
    8. console.log(func.length);
    9. console.log(arguments.length);
    10. }
    11. func();
    1. function test1(){
    2. console.log(arguments.callee); // 打印函数1本身
    3. function test2(){
    4. console.log(arguments.callee); // 打印函数2本身
    5. }
    6. test2();
    7. }
    8. test1();

    8.2、用递归实现一个数的累加

    ```javascript

    1. // 实现一个数的累加
    2. function sum(num){
    3. if(num <= 1){
    4. return 1;
    5. }
    6. return num + sum(num - 1);
    7. }
    8. var res = sum(10);
    9. console.log(res);
  1. // 利用模块化编程模式实现一个数的累加
  2. var add = (function(num){
  3. if(num <= 1){
  4. return 1;
  5. }
  6. return num + arguments.callee(num - 1);
  7. })(100);
  8. console.log(add);
  1. <a name="PSAFF"></a>
  2. ## 8.3、caller返回当前被调用函数的函数引用
  3. - caller:返回当前被调用函数的函数引用
  4. ```javascript
  5. // caller:返回当前被调用函数的函数引用
  6. function func1(){
  7. func2();
  8. function func2(){
  9. console.log(func2.caller);
  10. }
  11. }
  12. func1();

九、练习题

9.1、写出下面函数的运行结果

  1. // 练习题
  2. function foo(){
  3. bar.apply(null, arguments);
  4. // bar.apply(arguments);
  5. // bar.call(arguments); -> bar(arguments)
  6. }
  7. function bar(){
  8. console.log(arguments);
  9. }
  10. foo(1, 2, 3, 4, 5);

9.2、typeof可能返回的值有那些

  • ‘number’
  • ‘string’
  • ‘boolean’
  • ‘undefined’
  • ‘object’
  • ‘function’

    9.3、实参集合和形参存在映射关系

    1. // 形参和实参存在映射关系
    2. // 实参只有函数执行时传递了值,才可以在函数内部去修改
    3. function b(x, y, a){
    4. arguments[2] = 10;
    5. alert(a);
    6. }
    7. b(1, 2, 3);
    8. function b(x, y, a){
    9. a = 10;
    10. alert(arguments[2]);
    11. }
    12. b(1, 2, 3);

    9.4、括号运算符练习「逗号运算符」

    逗号运算符类似于逻辑运算符,它只返回逗号后面的最后一个

  1. // 括号运算符练习
  2. // 逗号运算符类似于逻辑运算符,它只返回逗号后面的最后一个
  3. var f = (
  4. function f(){
  5. return '1';
  6. },
  7. function g(){
  8. return 2;
  9. }
  10. );
  11. console.log(f);
  12. var f = (
  13. function f(){
  14. return '1';
  15. },
  16. function g(){
  17. return 2;
  18. }
  19. );
  20. console.log(typeof(f()));

9.5、null和undefined练习题

  • unll和undefined只有在两个等号的情况下才会相等,其余情况这个两个值和任何值都不相等
  • isNaN存在隐式类型转换

    1. // 练习题
    2. // unll和undefined只有在两个等号的情况下才会相等,其余情况这个两个值和任何值都不相等
    3. console.log(null == undefined);
    4. console.log(null === undefined);
    5. // isNaN存在隐式类型转换
    6. console.log(isNaN('100'));
    7. console.log(parseInt('1a') == 1);

    9.6、手写一个简单的isNaN

  • NaN和任何值都不相等,包括和它自己

  • isNaN(val); 此处的val必须是字符串格式的

    1. // 手写一个简单的isNaN
    2. console.log(NaN == NaN);
    3. function isNaN(val){
    4. // isNaN存在隐式类型转换,会把val隐式转换为Number类型,然后再检测
    5. var res = Number(val) + '';
    6. if(res === 'NaN'){
    7. return true;
    8. }else{
    9. return false;
    10. }
    11. }
    12. console.log(isNaN('10'));
    13. console.log(isNaN('10a'));
    14. console.log(isNaN('width: 10px'));

    9.7、空对象等于空对象吗?为什么?如何才能相等?

    1. // 空对象等于空对象吗?
    2. // 为什么?
    3. // 如何让两个空对象相等?
    4. // console.log({} == {});
    5. var obj1 = {};
    6. var obj2 = obj1;
    7. console.log(obj1 == obj2);

    9.8、this面试题

    ```javascript

    1. // 面试题
    2. var a = '1';
    3. function test(){
    4. var a = '2';
    5. this.a = '3';
    6. console.log(a);
    7. }
    8. test();
    9. new test();
    10. console.log(a);
  1. // 面试题
  2. var a = 5;
  3. function test(){
  4. a = 0;
  5. console.log(a);
  6. console.log(this.a);
  7. var a;
  8. console.log(a);
  9. }
  10. test();
  11. new test();

```