我感兴趣的源码

  1. Array.prototype.push()
    1. Array.prototype.push(x){
    2. this[this.length] = x;
    3. this.length++;
    4. }

    巩固练习


1函数、对象的嵌套问题

题目1.1

会输出什么?

  1. var func = new Function("console.log('我是func')");
  2. console.log(func());

题目1.2

会输出什么

  1. var Cache1 = (function(){
  2. var cache = {};
  3. return {
  4. getObj1:function(name){
  5. if(name in cache){
  6. return cache[name];
  7. }
  8. var temp = new Object(name);
  9. cache[name] = temp;
  10. return temp;
  11. },
  12. getObj2:function(name){
  13. if(name in cache){
  14. return cache[name];
  15. }
  16. var temp = new Object(name);
  17. cache[name] = temp;
  18. return temp;
  19. }
  20. }
  21. })();
  22. console.log(Cache1);
  23. console.log(Cache1.getObj1('巧碧螺'));

2this相关的问题

2.1

  1. var num = 20;
  2. var obj = {
  3. num:30,
  4. fn:(function (num) {
  5. this.num *= 3;
  6. num += 15;
  7. var num = 45;
  8. return function () {
  9. this.num *= 4;
  10. num += 20;
  11. console.log(this);
  12. console.log(num);
  13. }
  14. })(num)
  15. }
  16. var fn = obj.fn;
  17. fn();
  18. obj.fn();

2.2

  1. function a(xx){
  2. this.x=xx;
  3. return this;
  4. }
  5. var x=a(5);
  6. console.log(x.x);
  7. var y=a(6);
  8. console.log(x.x);
  9. console.log(y.x);

2.3

请说明要输出正确的myName的值要如何修改程序?

  1. Foo = function(){
  2. this.myName = "Foo function.";
  3. }
  4. Foo.prototype.sayHello = function(){
  5. alert(this.myName);
  6. }
  7. Foo.prototype.bar = function(){
  8. setTimeout(this.sayHello, 1000);
  9. }
  10. var f = new foo;
  11. f.bar();

2.4

  1. var length = 10;
  2. function fn () {
  3. console.log(this.length);
  4. }
  5. var obj = {
  6. length: 5,
  7. method: function (fn) {
  8. fn();
  9. arguments[0]();
  10. },
  11. fn:function(){
  12. console.log(this);
  13. console.log(this.length);
  14. }
  15. };
  16. obj.method(obj.fn, 1);

2.5

  1. window.val = 1;
  2. var obj = {
  3. val: 2,
  4. dbl: function () {
  5. this.val *= 2;
  6. val *= 2;
  7. console.log('val:', val);
  8. console.log('this.val:', this.val);
  9. }
  10. };
  11. // 说出下面的输出结果
  12. obj.dbl();
  13. var func = obj.dbl;
  14. func();

3闭包相关的问题

闭包相关题目套路

  1. 先判断是否构成闭包(两个条件)。
  2. 如果构成闭包,观察外部函数是否只执行了一次。
    1. 每一个外部函数对应一组缓存(一组对应变量的最终值
    2. 往难了走,难点会变成找到外部函数、找到闭包。
  3. 根据外部函数执行次数,找到最终值,
    1. 注意区分var和let。
    2. 只需关注真正处于闭包中的变量。

      3.1

      1. var i = 0;
      2. function outerFn(){
      3. function innnerFn(){
      4. i++;
      5. console.log(i);
      6. }
      7. return innnerFn;
      8. }
      9. var inner1 = outerFn();
      10. var inner2 = outerFn();
      11. inner1();
      12. inner2();
      13. inner1();
      14. inner2();

      3.2

      1. function outerFn(){
      2. var i = 0;
      3. function innerFn(){
      4. i++;
      5. console.log(i);
      6. }
      7. return innerFn;
      8. }
      9. var inner = outerFn();
      10. inner();
      11. var inner2 = outerFn();
      12. inner2();
      13. inner2();
      14. inner();

      3.3

      1. function fn(){
      2. var arr = [];
      3. for(var i = 0; i < 5; i++){
      4. arr[i]= function(){
      5. return i;
      6. }
      7. }
      8. return arr;
      9. }
      10. var list = fn();
      11. for(var i = 0; i < list.length; i++){
      12. console.log(list[i]());
      13. }
      14. //----
      15. function fn(){
      16. var arr = [];
      17. for(let i = 0; i < 5; i++){
      18. arr[i]= function(){
      19. return i;
      20. }
      21. }
      22. return arr;
      23. }
      24. var list = fn();
      25. for(var i = 0; i < list.length; i++){
      26. console.log(list[i]());
      27. }

      3.4

      1. (function() {
      2. var m = 0;
      3. function getM() { return m; }
      4. function seta(val) { m = val; }
      5. window.g = getM;
      6. window.f = seta;
      7. })();
      8. f(100);
      9. console.log(g())

      3.5

      ```javascript <!DOCTYPE html>
  • 1
  • 2
  • 3

  1. <a name="n1HKR"></a>
  2. ### 3.6
  3. ```javascript
  4. var fn = (function(){
  5. var i=10;
  6. function fn(){
  7. console.log(++i);
  8. }
  9. return fn;
  10. })()
  11. fn();
  12. fn();

答案


1

1.1

  1. 我是func
  2. undefined

解析:

  1. console.log(函数的执行) ——>会先执行一次函数,再打印它的return对象
  2. 函数没有return或者没有返回值时会返回undefined
  3. console.log(函数的名字,但不执行) ——>直接打印函数的代码

    1.2

    image.png
    解析:

  4. 输出1:

    1. Cache1本身是立即执行,所以console.log(函数的执行) ——>会先执行一次函数,再打印它的return对象
    2. 这次的return对象,是一个字面量表达的对象,分别有obj1和obj2两个方法。
  5. 输出2:
    1. 当把一个string包装成一个对象再输出时,会输出一个string对象,格式如图。

      2

      2.1

  • 解析

    • 自执行函数的this指向window
    • 闭包涉及的局部变量会常驻内存
      1. var num = 20; //window.num
      2. var obj = { //obj.num
      3. num:30,
      4. fn:(function (num) { //自执行函数新开的num,随便叫什么都可以
      5. this.num *= 3; //自执行函数的this指向window
      6. num += 15;
      7. var num = 45; //会声明提前,但由于var可以反复声明,因此没有影响。
      8. //且因为不在最外层的window里,this.num和num是独立的、无关的
      9. return function () { //函数新开的num形成了闭包,会“常驻内存”
      10. this.num *= 4;
      11. num += 20;
      12. console.log(this);
      13. console.log(num);
      14. }
      15. })(num)//往上找,由于没有函数作用域,直接找到全局作用域。
      16. }
      17. var fn = obj.fn;//自执行函数只会执行一次,从此fn和obj.fn都是return值
      18. fn();
      19. obj.fn(); //!<==>fn();对于fn()而言,调用它的对象是window
  • 答案:

    1. window
    2. 65
    3. obj
    4. 85

    2.2

  • 解析:对于window,定义在最外层window上的var变量 和 window./this. 是一体的

    1. function a(xx){
    2. this.x=xx;
    3. return this;
    4. }
    5. var x=a(5);//window.x = 5; window.x = window;
    6. console.log(x.x);//window.x = window,因此window
    7. var y=a(6);//window.x = 6; window.y = window
    8. console.log(x.x);//第一个x是6,因此undefined
    9. console.log(y.x);//window.y = window,而window.x = 6,因此6
  • 答案:

    1. window
    2. undefined
    3. 6

    2.3

  • 解析:普通函数的this根据调用者动态改变,而回调函数在执行时已经找不到调用者了(即使setTimeOut设置s),会指向window,因此需要改变的就是回调函数的this指向 / 把myName放在全局上。

  • 方法
    • 法一:箭头函数

因为箭头函数里面所有的this会与其第一层的this保持一致,在定义时静态决定,不会动态改变。

  1. foo = function(){
  2. this.myName = "Foo function.";
  3. }
  4. foo.prototype.sayHello = function(){
  5. alert(this.myName);
  6. }
  7. foo.prototype.bar = function(){
  8. setTimeout(()=>{this.sayHello}, 1000);
  9. }
  10. var f = new foo;
  11. f.bar();
  • 法二:使用bind,修改this指向。

    • 注意这里不能用call和apply,否则setTimeOut会失去意义
    • bind会储存this
      1. foo = function(){
      2. this.myName = "Foo function.";
      3. }
      4. foo.prototype.sayHello = function(){
      5. alert(this.myName);
      6. }
      7. foo.prototype.bar = function(){
      8. setTimeout(this.sayHello.bind(this), 1000);
      9. }
      10. var f = new foo;
      11. f.bar();
  • 法三:调用一次foo()

相当于把myName放到windows对象上

  1. foo = function(){
  2. this.myName = "Foo function.";
  3. }
  4. foo.prototype.sayHello = function(){
  5. alert(this.myName);
  6. }
  7. foo.prototype.bar = function(){
  8. setTimeout(this.sayHello, 1000);
  9. }
  10. var f = new foo;
  11. foo();
  12. f.bar();
  • 法四:添加参数that
    1. foo = function(){
    2. this.myName = "Foo function.";
    3. }
    4. foo.prototype.sayHello = function(that){
    5. alert(that.myName);
    6. }
    7. foo.prototype.bar = function(){
    8. var that = this;
    9. setTimeout(function(){that.sayHello(that)}, 1000);
    10. }
    11. var f = new foo;
    12. foo();
    13. f.bar();

    2.4

  • 解析:
    • 两次fn调用都调用的是obj.fn,但this指向都不是obj
    • 对象方法中的方法指向window
    • arguments 是一种特殊的对象,因此第二次fn的指向是arguments,而arguments.length = 2。 ```javascript var length = 10;

function fn () { console.log(this.length); }

var obj = { length: 5, method: function (fn) { fn(); arguments0; }, fn:function(){ console.log(this); console.log(this.length); } };

obj.method(obj.fn, 1);

  1. - 答案:
  2. ```javascript
  3. window
  4. 10
  5. 2

2.5

  • 解析
    • 因为js不存在块级作用域的概念,因此在非window作用域(即全局作用域)中调用不带this的变量时,会先从当前块中找,没有的话就从父块中找,直到找到window(window的挂载和var定义的变量是一体的)。
    • 最后调用func()和obj.dbl是不一样的。 ```javascript window.val = 1;

var obj = { val: 2, dbl: function () { this.val = 2; val = 2;
console.log(‘val:’, val); console.log(‘this.val:’, this.val); } };

// 说出下面的输出结果 obj.dbl(); var func = obj.dbl; func();

  1. - 答案:
  2. ```javascript
  3. 2 4 8 8

3

3.1

  • 解析
    • 没有形成闭包
      • 每次内部函数执行时的i,是炫从全局变量中获取的
  • 答案

    1. 1 2 3 4

    3.2

  • 解析

    • 构成闭包、外部函数执行两次、var
      • 每重新执行一次外部函数,就会创建一组新的缓存。
        1. function outerFn(){
        2. var i = 0;
        3. function innerFn(){
        4. i++;
        5. console.log(i);
        6. }
        7. return innerFn;
        8. }
        9. var inner = outerFn();
        10. inner();//1
        11. var inner2 = outerFn();
        12. inner2();//1
        13. inner2();//2
        14. inner();//2
  • 答案

    1. 1 1 2 2

    3.3

  • 解析

    • 构成闭包、外部函数只执行一次、需要区分var和let
      • ①和②中外部函数都只执行了一次,则分别对应一组缓存,只不过①中只缓存了一个i值,②中缓存了5个i值
        1. //①
        2. function fn(){
        3. var arr = [];
        4. for(var i = 0; i < 5; i++){
        5. arr[i]= function(){
        6. return i;//真正受缓存影响的只有这个i
        7. }
        8. }
        9. return arr;
        10. }
        11. var list = fn();
        12. for(var i = 0; i < list.length; i++){
        13. console.log(list[i]());
        14. }
        15. //②
        16. function fn(){
        17. var arr = [];
        18. for(let i = 0; i < 5; i++){
        19. arr[i]= function(){
        20. return i;//真正受缓存影响的只有这个i
        21. }
        22. }
        23. return arr;
        24. }
        25. var list = fn();
        26. for(var i = 0; i < list.length; i++){
        27. console.log(list[i]());
        28. }
  • 答案

    1. 55555
    2. 01234

    3.4

  • 解析

    • 每一次外部函数的执行会对应一组缓存。
  • 答案

    1. 100

    3.5

  • 解析

    • 构成闭包、外部函数执行了3次
    • 该题目是事件处理函数总闭包的写法
  • 答案

    1. //需要点击3次: 0 1 2

    3.6

  • 解析