美文网首页
JS知识点

JS知识点

作者: 吃肉肉不吃肉肉 | 来源:发表于2020-04-12 21:01 被阅读0次

    1.事件冒泡与事件捕获

    事件冒泡:由最具体的元素(目标元素)向外传播到最不具体的元素
    事件捕获:由最不确定的元素到目标元素

    2.复杂数据类型如何转变为字符串

    • 首先,会调用 valueOf 方法,如果方法的返回值是一个基本数据类型,就返回这个值
    • 如果调用 valueOf 方法之后的返回值仍旧是一个复杂数据类型,就会调用该对象的 toString 方法
    • 如果 toString 方法调用之后的返回值是一个基本数据类型,就返回这个值,
    • 如果 toString 方法调用之后的返回值是一个复杂数据类型,就报一个错误。

    3.javascript 中 this 的指向问题

    • 全局环境、普通函数(非严格模式)指向 window
    • 普通函数(严格模式)指向 undefined
    • 函数作为对象方法及原型链指向的就是上一级的对象
    • 构造函数指向构造的对象
    • DOM 事件中指向触发事件的元素
    • 箭头函数
      解析:
    1、全局环境

    全局环境下,this 始终指向全局对象(window),无论是否严格模式;

    // 在浏览器中,全局对象为 window 对象:
    console.log(this === window); // true
    
    this.a = 37;
    console.log(window.a); // 37
    
    
    2、函数上下文调用
    • 普通函数
      普通函数内部的 this 分两种情况,严格模式和非严格模式。
      (1)非严格模式下,没有被上一级的对象所调用,this 默认指向全局对象 window。
    function f1() {
      return this;
    }
    f1() === window; // true
    
    

    (2)严格模式下,this 指向 undefined。

    function f2() {
      "use strict"; // 这里是严格模式
      return this;
    }
    f2() === undefined; // true
    
    
    • 函数作为对象的方法
      (1)函数有被上一级的对象所调用,那么 this 指向的就是上一级的对象。
      (2)多层嵌套的对象,内部方法的 this 指向离被调用函数最近的对象(window 也是对象,其内部对象调用方法的 this 指向内部对象, 而非 window)。
    //方式1
    var o = {
      prop: 37,
      f: function() {
        return this.prop;
      }
    };
    //当 o.f()被调用时,函数内的this将绑定到o对象。
    console.log(o.f()); // logs 37
    
    
    //方式2
    var o = { prop: 37 };
    function independent() {
      return this.prop;
    }
    //函数f作为o的成员方法调用
    o.f = independent;
    console.log(o.f()); // logs 37
    
    
    //方式3
    //this 的绑定只受最靠近的成员引用的影响
    o.b = { g: independent, prop: 42 };
    console.log(o.b.g()); // 42
    
    

    特殊例子

    // 例子1
    var o = {
      a: 10,
      b: {
        // a:12,
        fn: function() {
          console.log(this.a); //undefined
          console.log(this); //{fn: ƒ}
        }
      }
    };
    o.b.fn();
    
    
    // 例子2
    var o = {
      a: 10,
      b: {
        a: 12,
        fn: function() {
          console.log(this.a); //undefined
          console.log(this); //window
        }
      }
    };
    var j = o.b.fn;
    j();
    // this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子2中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子1是不一样的,例子1是直接执行了fn
    
    
    • 原型链中的 this
      (1)如果该方法存在于一个对象的原型链上,那么 this 指向的是调用这个方法的对象,就像该方法在对象上一样。
    var o = {
      f: function() {
        return this.a + this.b;
      }
    };
    var p = Object.create(o);
    p.a = 1;
    p.b = 4;
    
    console.log(p.f()); // 5
    
    

    上述例子中,对象 p 没有属于它自己的 f 属性,它的 f 属性继承自它的原型。当执行 p.f()时,会查找 p 的原型链,找到 f 函数并执行。因为 f 是作为 p 的方法调用的,所以函数中的 this 指向 p。
    (2)相同的概念也适用于当函数在一个 getter 或者 setter 中被调用。用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。
    (3)call()和 apply()方法:当函数通过 Function 对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的 this 值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript 内部会尝试将其转换成对象然后指向它。

    function add(c, d) {
      return this.a + this.b + c + d;
    }
    var o = { a: 1, b: 3 };
    
    add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
    add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
    
    function tt() {
      console.log(this);
    }
    // 第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。
    tt.call(5); // 内部转成 Number {[[PrimitiveValue]]: 5}
    tt.call("asd");
     // 内部转成 String {0: "a", 1: "s", 2: "d", length: 3, [[PrimitiveValue]]: "asd"}
    
    

    (4)bind()方法:由 ES5 引入, 在 Function 的原型链上, Function.prototype.bind
    通过 bind 方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。

    function f() {
      return this.a;
    }
    
    var g = f.bind({ a: "azerty" });
    console.log(g()); // azerty
    
    var o = { a: 37, f: f, g: g };
    console.log(o.f(), o.g()); // 37, azerty2.4 
    
    

    构造函数中的 this当一个函数用作构造函数时(使用 new 关键字),它的 this 被绑定到正在构造的新对象。构造器返回的默认值是 this 所指的那个对象,也可以手动返回其他的对象。

    function C() {
      this.a = 37;
    }
    
    var o = new C();
    console.log(o.a); // 37
    // 为什么this会指向o?
    //首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。
    
    function C2() {
      this.a = 37;
      return { a: 38 }; // 手动设置返回{a:38}对象
    }
    
    o = new C2();
    console.log(o.a); // 38
    
    

    特殊例子
    当 this 碰到 return 时

    // 例子1
    function fn() {
      this.user = "追梦子";
      return {};
    }
    var a = new fn();
    console.log(a.user); //undefined
    // 例子2
    function fn() {
      this.user = "追梦子";
      return function() {};
    }
    var a = new fn();
    console.log(a.user); //undefined
    // 例子3
    function fn() {
      this.user = "追梦子";
      return 1;
    }
    var a = new fn();
    console.log(a.user); //追梦子
    // 例子4
    function fn() {
      this.user = "追梦子";
      return undefined;
    }
    var a = new fn();
    console.log(a.user); //追梦子
    // 例子5
    function fn() {
      this.user = "追梦子";
      return undefined;
    }
    var a = new fn();
    console.log(a); //fn {user: "追梦子"}
    // 例子6
    // 虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊
    function fn() {
      this.user = "追梦子";
      return null;
    }
    var a = new fn();
    console.log(a.user); //追梦子
    
    // 总结:如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
    
    
    • setTimeout & setInterval
      (1)对于延时函数内部的回调函数的 this 指向全局对象 window;
      (2)可以通过 bind()方法改变内部函数 this 指向。
    //默认情况下代码
    function Person() {
      this.age = 0;
      setTimeout(function() {
        console.log(this);
      }, 3000);
    }
    
    var p = new Person(); //3秒后返回 window 对象
    //通过bind绑定
    function Person() {
      this.age = 0;
      setTimeout(
        function() {
          console.log(this);
        }.bind(this),
        3000
      );
    }
    
    var p = new Person(); //3秒后返回构造函数新生成的对象 Person{...}
    
    
    3、在 DOM 事件中
    • 作为一个 DOM 事件处理函数
      当函数被用作事件处理函数时,它的 this 指向触发事件的元素(针对 addEventListener 事件)。
    // 被调用时,将关联的元素变成蓝色
    function bluify(e) {
      //this指向所点击元素
      console.log("this === e.currentTarget", this === e.currentTarget); // 总是 true
      // 当 currentTarget 和 target 是同一个对象时为 true
      console.log("this === e.target", this === e.target);
      this.style.backgroundColor = "#A5D9F3";
    }
    
    // 获取文档中的所有元素的列表
    var elements = document.getElementsByTagName("*");
    
    // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
    for (var i = 0; i ‹ elements.length; i++) {
      elements[i].addEventListener("click", bluify, false);
    }
    
    
    • 作为一个内联事件处理函数
      (1)当代码被内联处理函数调用时,它的 this 指向监听器所在的 DOM 元素;
      (2)当代码被包括在函数内部执行时,其 this 指向等同于 普通函数直接调用的情况,即在非严格模式指向全局对象 window,在严格模式指向 undefined:
    ‹button onclick="console.log(this)"›show me‹/button›
    ‹button onclick="(function () {console.log(this)})()"›show inner this‹/button›
    ‹button onclick="(function () {'use strict'; console.log(this)})()"›
      use strict
    ‹/button›
    
    
    // 控制台打印
    ‹button onclick="console.log(this)"›show me‹/button›
    Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
    undefined
    
    
    4、箭头函数
    • 全局环境中
      在全局代码中,箭头函数被设置为全局对象:
    var globalObject = this;
    var foo = () =› this;
    console.log(foo() === globalObject); // true
    
    
    • this 捕获上下文
      箭头函数没有自己的 this,而是使用箭头函数所在的作用域的 this,即指向箭头函数定义时(而不是运行时)所在的作用域。
    //1、箭头函数在函数内部,以非方法的方法使用
    function Person() {
      this.age = 0;
      setInterval(() =› {
        this.age++;
      }, 3000);
    }
    var p = new Person(); //Person{age: 0}
    
    //普通函数作为内部函数
    function Person() {
      this.age = 0;
      setInterval(function() {
        console.log(this);
        this.age++;
      }, 3000);
    }
    var p = new Person(); //Window{...}
    
    

    在 setTimeout 中的 this 指向了构造函数新生成的对象,而普通函数指向了全局 window 对象。

    • 箭头函数作为对象的方法
      使用箭头函数作为对象的方法使用,指向全局 window 对象;而普通函数作为对象的方法使用,则指向调用的对象。
    var obj = {
      i: 10,
      b: () =› console.log(this.i, this),
      c: function() {
        console.log(this.i, this);
      }
    };
    obj.b(); // undefined window{...}
    obj.c(); // 10 Object {...}
    
    
    • 箭头函数中,call()、apply()、bind()方法无效
    var adder = {
      base: 1,
      //对象的方法内部定义箭头函数,this是箭头函数所在的作用域的this,
      //而方法add的this指向adder对象,所以箭头函数的this也指向adder对象。
      add: function(a) {
        var f = v =› v + this.base;
        return f(a);
      },
      //普通函数f1的this指向window
      add1: function() {
        var f1 = function() {
          console.log(this);
        };
        return f1();
      },
      addThruCall: function inFun(a) {
        var f = v =› v + this.base;
        var b = {
          base: 2
        };
    
        return f.call(b, a);
      }
    };
    
    console.log(adder.add(1)); // 输出 2
    adder.add1(); //输出全局对象 window{...}
    console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3,其内部的this并没有因为call() 而改变,其this值仍然为函数inFun的this值,指向对象adder
    
    
    • this 指向固定化
      箭头函数可以让 this 指向固定化,这种特性很有利于封装回调函数
    var handler = {
      id: "123456",
    
      init: function() {
        document.addEventListener(
          "click",
          event =› this.doSomething(event.type),
          false
        );
      },
    
      doSomething: function(type) {
        console.log("Handling " + type + " for " + this.id);
      }
    };
    
    

    上面代码的 init 方法中,使用了箭头函数,这导致这个箭头函数里面的 this,总是指向 handler 对象。如果不使用箭头函数则指向全局 document 对象。

    • 箭头函是不适用场景
      (1)箭头函数不适合定义对象的方法(方法内有 this),因为此时指向 window;
      (2)需要动态 this 的时候,也不应使用箭头函数。
    //例1,this指向定义箭头函数所在的作用域,它位于对象cat内,但cat不能构成一个作用域,所以指向全局window,改成普通函数后this指向cat对象。
    const cat = {
      lives: 9,
      jumps: () =› {
        this.lives--;
      }
    };
    
    //例2,此时this也是指向window,不能动态监听button,改成普通函数后this指向按钮对象。
    var button = document.getElementById("press");
    button.addEventListener("click", () =› {
      this.classList.toggle("on");
    });
    
    

    4.ES6 都有什么 Iterator 遍历器

    SetMap
    解析:

    1. 遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)
    2. Iterator 的作用有三个:
    • 一是为各种数据结构,提供一个统一的、简便的访问接口;
    • 二是使得数据结构的成员能够按某种次序排列;
    • 三是 ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费。
    1. 默认部署了 Iterator 的数据有 ArrayMapSetStringTypedArrayargumentsNodeList 对象,ES6 中有的是 Set、Map**、

    5. ES6 中类的定义

    // 1、类的基本定义
    class Parent {
      constructor(name = "小白") {
        this.name = name;
      }
    }
    
    
    // 2、生成一个实例
    let g_parent = new Parent();
    console.log(g_parent); //{name: "小白"}
    let v_parent = new Parent("v"); // 'v'就是构造函数name属性 , 覆盖构造函数的name属性值
    console.log(v_parent); // {name: "v"}
    
    
    // 3、继承
    class Parent {
      //定义一个类
      constructor(name = "小白") {
        this.name = name;
      }
    }
    
    class Child extends Parent {}
    
    console.log("继承", new Child()); // 继承 {name: "小白"}
    
    
    // 4、继承传递参数
    class Parent {
      //定义一个类
      constructor(name = "小白") {
        this.name = name;
      }
    }
    
    class Child extends Parent {
      constructor(name = "child") {
        // 子类重写name属性值
        super(name); // 子类向父类修改 super一定放第一行
        this.type = "preson";
      }
    }
    console.log("继承", new Child("hello")); // 带参数覆盖默认值  继承{name: "hello", type: "preson"}
    
    
    // 5、ES6重新定义的ES5中的访问器属性
    class Parent {
      //定义一个类
      constructor(name = "小白") {
        this.name = name;
      }
    
      get longName() {
        // 属性
        return "mk" + this.name;
      }
    
      set longName(value) {
        this.name = value;
      }
    }
    
    let v = new Parent();
    console.log("getter", v.longName); // getter mk小白
    
    v.longName = "hello";
    console.log("setter", v.longName); // setter mkhello// 
    
    
    6、类的静态方法
    class Parent {
      //定义一个类
      constructor(name = "小白") {
        this.name = name;
      }
    
      static tell() {
        // 静态方法:通过类去调用,而不是实例
        console.log("tell");
      }
    }
    
    Parent.tell(); // tell// 
    
    
    7、类的静态属性:
    
    class Parent {
      //定义一个类
      constructor(name = "小白") {
        this.name = name;
      }
    
      static tell() {
        // 静态方法:通过类去调用,而不是实例
        console.log("tell"); // tell
      }
    }
    
    Parent.type = "test"; // 定义静态属性
    
    console.log("静态属性", Parent.type); // 静态属性 test
    
    let v_parent = new Parent();
    console.log(v_parent); // {name: "小白"}  没有tell方法和type属性
    
    

    6.说说你对 promise 的了解

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件监听——更合理和更强大。
    所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。Promise 对象有以下两个特点:

    1. 对象的状态不受外界影响,Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)
    2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。

    7.Set 数据结构

    es6 方法,

    Set 本身是一个构造函数,它类似于数组,但是成员值都是唯一的。

    const set = new Set([1, 2, 3, 4, 4]);
    console.log([...set]); // [1,2,3,4]
    console.log(Array.from(new Set([2, 3, 3, 5, 6]))); //[2,3,5,6]
    
    

    8.箭头函数需要注意的地方

    箭头函数有几个使用注意点。

    • (1)函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。
    • (2)不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。
    • (3)不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
    • (4)不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

    上面四点中,第一点尤其值得注意。this 对象的指向是可变的,但是在箭头函数中,它是固定的。

    function foo() {
      setTimeout(() =› {
        console.log("id:", this.id);
      }, 100);
    }
    
    var id = 21;
    
    foo.call({ id: 42 });
    // id: 42
    
    

    9.ES6 如何动态加载 import

    import("lodash").then(_ =› {
      // Do something with lodash (a.k.a '_')...
    });
    
    

    10.ECMAScript6 怎么写class么,为什么会出现class这种东西?

    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
      toString() {
         return '('+this.x+', '+this.y+')';
      }
    }
    
    

    11.自执行函数?用于什么场景?好处?

    自执行函数:
    1、声明一个匿名函数
    2、马上调用这个匿名函数。
    作用:创建一个独立的作用域。
    好处:防止变量弥散到全局,以免各种 js 库冲突。隔离作用域避免污染,或者截断作用域链,避免闭包造成引用变量无法释放。利用立即执行特性,返回需要的业务函数或对象,避免每次通过条件判断来处理场景:一般用于框架、插件等场景

    12.多个页面之间如何进行通信

    • cookie
    • web worker
    • localeStorage 和 sessionStorage

    13.css 动画和 js 动画的差异

    • 代码复杂度,js 动画代码相对复杂一些
    • 动画运行时,对动画的控制程度上,js 能够让动画,暂停,取消,终止,css 动画不能添加事件
    • 动画性能看,js 动画多了一个 js 解析的过程,性能不如 css 动画好

    14.数组方法 pop() push() unshift() shift()

    • arr.pop() 从后面删除元素,只能是一个,返回值是删除的元素
    • arr.push() 从后面添加元素,返回值为添加完后的数组的长度
    • arr.unshift() 从前面添加元素, 返回值是添加完后的数组的长度
    • arr.shift() 从前面删除元素,只能删除一个 返回值是删除的元素

    15.事件绑定与普通事件有什么区别

    用普通事件添加相同事件,下面会覆盖上面的,而事件绑定不会

    普通事件是针对非 dom 元素,事件绑定是针对 dom 元素的事件

    16. IE 和 DOM 事件流的区别

    1.事件流的区别

    IE 采用冒泡型事件 Netscape 使用捕获型事件
    DOM 使用先捕获后冒泡型事件
    示例:

    ‹body›
      ‹div›
        ‹button›点击这里‹/button›
      ‹/div›
    ‹/body›
    
    

    冒泡型事件模型: button-›div-›body (IE 事件流)
    捕获型事件模型: body-›div-›button (Netscape 事件流)
    DOM 事件模型: body-›div-›button-›button-›div-›body (先捕获后冒泡)

    2.事件侦听函数的区别

    IE 使用:

    [Object].attachEvent("name_of_event_handler", fnHandler); //绑定函数
    [Object].detachEvent("name_of_event_handler", fnHandler); //移除绑定
    
    

    DOM 使用:

    [Object].addEventListener("name_of_event", fnHandler, bCapture); //绑定函数
    [Object].removeEventListener("name_of_event", fnHandler, bCapture);
     //移除绑定bCapture 参数用于设置事件绑定的阶段,true 为捕获阶段,false 为冒泡阶段。
    
    

    17.变量提升

    js 代码执行的过程
    1. 变量提升
    2. 代码从上到下依次执行
      var 关键字和 function 关键字声明的变量会进行变量提升
    变量提升发生的环境:

    发生在代码所处的当前作用域。
    变量提升

    1. var 关键字进行的变量提升,会把变量提前声明,但是不会提前赋值 。
    2. function 关键字对变量进行变量提升,既会把变量提前声明,又会把变量提前赋值,也就是把整个函数体提升到代码的顶部
    3. 有一些代码是不会执行的但是仍旧会发生变量提升,规则适用于 1,2
    • return 之后的代码依旧会发生变量提升,规则适用于 1,2
    • 代码报错之后的代码依旧会发生变量提升,规则适用于 1,2
    • break 之后的代码依旧会发生变量提升,规则适用于 1,2
    1. 有一些代码是不会执行但是仍旧会发生变量提升,但是规则要发生变化
    • if 判断语句 if 判断语句中 var 关键字以及 function 关键字声明的变量只会发生提前声明,不会发生提前赋值,也就是不会吧函数体整体提升到当前作用域顶部。规则跟 1,2 不适用
    • switch case 规则跟 1,2 不适用
    • 3 do while 规则跟 1,2 不适用
    • try catch catch 中声明的变量只会发生提前声明,不会发生提前赋值。
      在条件判断语句和 try catch 中的声明的变量不管是否能够执行,都只会发生提前声明,不会发生提前赋值。
      解析:
    // 如果一个变量声明了但是未赋值,那么输出这个变量就会输出 undefined
    var num;
    console.log(num);
    
    // 如果一个变量没有声明也没有赋值,那么就会报一个错:
    console.log(num);
     // 输出一个不存在的变量 Uncaught ReferenceError: num is not defined
    
    
    // var 关键字进行的变量提升
    console.log(num);
    var num = 123;
    console.log(num);
    var num = 456;
    console.log(num);
    
    // 变量提升之后的代码:
    var num;
    console.log(num);
    num = 123;
    console.log(num);
    num = 456;
    console.log(num);
    
    
    // function 关键字的变量提升
    console.log(fn);
    function fn() {
      console.log(1);
    }
    
    // 变量提升之后的代码:
    function fn() {
      console.log(1);
    }
    console.log(fn); // 输出fn的函数体
    
    
    // 3.1 return 之后的代码依旧会发生变量提升  规则适用于1,2
    function fn() {
      console.log(num);
      return;
      var num = 123;
    }
    fn();
    
    // 变量提升之后的代码:
    function fn() {
      var num;
      console.log(num);
      return;
      num = 123;
    }
    fn(); // undefined
    
    function fn() {
      console.log(fo);
      return;
      function fo() {}
    }
    fn();
    
    // 变量提升之后的代码:
    function fn() {
      function fo() {}
      console.log(fo);
      return;
    }
    fn(); //输出fo的函数体
    
    
    //3.2 代码报错之后的代码依旧会进行变量提升,规则适用于1,2
    console.log(num);
    xsasfgdsfqdfsdf; //报一个错
    var num = 123;
    console.log(num);
    
    // 变量提升之后的代码:
    var num;
    console.log(num); //输出 undefined
    dsagdsqghdwfh; // 报一个错误 ,错误之后的代码不会被执行
    num = 123;
    console.log(num);//function 关键字
    console.log(fn);
    sasgfdhwhsdqg;
    function fn() {}
    console.log(fn);
    
    // 变量提升之后的代码:
    function fn() {}
    console.log(fn); // 输出 fn 的函数体
    asdgsdgdfgfdg; // 报一个错误,报错之后的代码不会被执行
    console.log(fn);
    
    
    //4 代码不执行,但是会进行变量提升,不过规则不适用于1,2
    //4.1 if判断语句
    console.log(num);
    if (false) {
        var num = 123;
    }
    console.log(num)
    
    //  变量提升之后的代码:
    var num;
    console.log(num); //undefined
    if (false) {
        num = 123;
    }
    console.log(num) //undefined
    
    console.log(fn);
    if (false) {
        function fn() {}
    }
    console.log(fn);
    
    // 变量提升之后的代码:
    var fn;
    function fn;
    console.log(fn) //undefined
    if (false) {
        function fn() {}
    }
    console.log(fn) //undefined
    if(false){
      function fn() {}
    }
    console.log(fn) //undefined
    
    
    // try catch
    try {
      console.log(num);
    } catch (e) {
      var num = 123;
    }
    console.log(num);
    
    var num;
    try {
      console.log(num); // undefined
    } catch (e) {
      num = 123;
    }
    console.log(num); // undefined
    
    try {
      console.log(fn);
    } catch (e) {
      function fn() {}
    }
    console.log(fn);
    
    var fn;
    try {
      console.log(fn); // undefined
    } catch (e) {
      num = 123;
    }
    console.log(fn); // undefined
    
    

    18.如何阻止冒泡与默认行为

    阻止冒泡行为:
    非 IE 浏览器 stopPropagation(),IE 浏览器 window.event.cancelBubble = true
    阻止默认行为:
    非 IE 浏览器 preventDefault(),IE 浏览器 window.event.returnValue = false
    解析:
    当需要阻止冒泡行为时,可以使用

    function stopBubble(e) {
      //如果提供了事件对象,则这是一个非IE浏览器
      if (e && e.stopPropagation)
        //因此它支持W3C的stopPropagation()方法
        e.stopPropagation();
      //否则,我们需要使用IE的方式来取消事件冒泡
      else window.event.cancelBubble = true;
    }
    
    

    当需要阻止默认行为时,可以使用

    //阻止浏览器的默认行为
    function stopDefault(e) {
      //阻止默认浏览器动作(W3C)
      if (e && e.preventDefault) e.preventDefault();
      //IE中阻止函数器默认动作的方式
      else window.event.returnValue = false;
      return false;
    }
    
    

    19.js 中 this 闭包 作用域

    this:指向调用上下文
    闭包:定义一个函数就开辟了一个局部作用域,整个 js 执行环境有一个全局作用域
    作用域:一个函数可以访问其他函数中的变量(闭包是一个受保护的变量空间)

    var f = (function fn() {
      var name = 1;
      return function () {
        name++;
        console.log(name)
      }
    })()
    
    

    20.javascript 的同源策略

    一段脚本只能读取来自于同一来源的窗口和文档的属性

    解析:
    同源策略:限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。(来自 MDN 官方的解释)
    简单来说就是:一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合
    具体解释:
    (1)源包括三个部分:协议、域名、端口(http 协议的默认端口是 80)。如果有任何一个部分不同,则源不同,那就是跨域了。
    (2)限制:这个源的文档没有权利去操作另一个源的文档。这个限制体现在:(要记住)CookieLocalStorageIndexDB 无法获取。无法获取和操作 DOM。不能发送 Ajax 请求。我们要注意,Ajax 只适合同源的通信
    同源策略带来的麻烦:ajax 在不同域名下的请求无法实现,需要进行跨域操作

    相关文章

      网友评论

          本文标题:JS知识点

          本文链接:https://www.haomeiwen.com/subject/catimhtx.html