zoukankan      html  css  js  c++  java
  • javascript部分

    //generator yield 解析
    
    function *test(){
       console.log('a');
       let data1 = yield 22;
       console.log(data1);
       return 'done'
    }
    
    var obj = test();
    
    var obj1 = obj.next()
    //此时控制台打印'a',并给obj1 => {done: false, value: 22}
    
    var obj2 = obj.next('in')
    //此时控制台打印'in',并给obj2 => {done: true, value: "done"}
    
    //es7 提供了async await 和提供同步方式编写代码
    
    //大概实现原理
    
    function runner(_gen){
      return new Promise((resolve, reject)=>{
        var gen=_gen();
    
        _next();
        function _next(_last_res){
          var res=gen.next(_last_res);
    
          if(!res.done){
            var obj=res.value;
    
            if(obj.then){
              obj.then((res)=>{
                _next(res);
              }, (err)=>{
                reject(err);
              });
            }else if(typeof obj=='function'){
              if(obj.constructor.toString().startsWith('function GeneratorFunction()')){
                runner(obj).then(res=>_next(res), reject);
              }else{
                _next(obj());
              }
            }else{
              _next(obj);
            }
          }else{
            resolve(res.value);
          }
        }
      });
    }
    
    
    //使用
    runner(function *(){
      alert('欢迎哈');
    
      let arr=yield $.ajax({url: 'data/1.txt', dataType: 'json'});
    
      alert('接收到了数组'+arr);
    
      let json=yield $.ajax({url: 'data/2.txt', dataType: 'json'});
    
      alert('json也读完了');
    
      console.log(json);
    });
    //运算优先级
    var a = {n: 1};
    var b = a;
    a.x = a = {n: 2};
    
    a.x     // undefined
    b.x   // {n:2}
    
    //js的赋值运算顺序永远都是从右往左的,不过由于“.”是优先级最高的运算符,所以这行代码先“计算”了a.x,所以对象A多了个值为undefined的x
    
    //这里对象A指{n: 1}, 对象B指{n: 2}
    
    //由于( .  运算符最先计算)一开始js已经先计算了a.x,便已经解析了这个a.x是对象A的x,所以在同一条公式的情况下再回来给a.x赋值,也不会说重新解析这个a.x为对象B的x

     this绑定的硬绑定和软绑定实现

    背景: 硬绑定可以把this强制绑定到指定的对象(`new`除外),防止函数调用应用默认绑定规则。但是会降低函数的灵活性,使用**硬绑定之后就无法使用隐式绑定或者显式绑定来修改this**。

    var a = {b:1};
    var b = {b:2}
    function func(){
      console.log(this.b)
    }
    var bind1 = func.bind(a)
    
    bind1()  //1
    
    bind1.apply(b) //1
    
    var copybind1 = bind1.bind(b)
    copybind1() //1

    软绑定实现原理:给默认绑定指定一个全局对象和undefined以外的值**,那就可以实现和硬绑定相同的效果

    // 默认绑定规则,优先级排最后
    // 如果this绑定到全局对象或者undefined,那就把指定的默认对象obj绑定到this,否则不会修改this
    if(!Function.prototype.softBind) {
        Function.prototype.softBind = function(obj) {
            var fn = this;//对应要绑定的函数
            // 捕获所有curried参数
            var curried = [].slice.call( arguments, 1 ); //柯里化,预绑定参数
            var bound = function() {
                return fn.apply(
                    (!this || this === (window || global)) ? 
                        obj : this,
                    curried.concat.apply( curried, arguments ) //
                );
            };
            bound.prototype = Object.create( fn.prototype );//继承原型,避免绑定后得到的函数原型丢失
            return bound;
        };
    }
    function foo() {
        console.log("name:" + this.name);
    }
    
    var obj = { name: "obj" },
        obj2 = { name: "obj2" },
        obj3 = { name: "obj3" };
    
    // 默认绑定,应用软绑定,软绑定把this绑定到默认对象obj
    var fooOBJ = foo.softBind( obj );
    fooOBJ(); // name: obj 
    
    // 隐式绑定规则
    obj2.foo = foo.softBind( obj );
    obj2.foo(); // name: obj2 <---- 看!!!
    
    // 显式绑定规则
    fooOBJ.call( obj3 ); // name: obj3 <---- 看!!!
    
    // 绑定丢失,应用软绑定
    setTimeout( obj2.foo, 10 ); // name: obj

     this考题举例

    var num = 1;
    var myObject = {
        num: 2,
        add: function() {
            this.num = 3; // 隐式绑定 修改 myObject.num = 3
            // 严格模式下,报错。`TypeError: Cannot read property 'num' of undefined`
            // 即使非自执行函数,this也是window;这个不属于隐式绑定,容易误区
            (function() {
                console.log(this.num); // 默认绑定 输出 1
                this.num = 4; // 默认绑定 修改 window.num = 4
            })();
            console.log(this.num); // 隐式绑定 输出 3
        },
        sub: function() {
            console.log(this.num) // 因为丢失了隐式绑定的myObject,所以使用默认绑定 输出 4
        }
    }
    myObject.add(); // 1 3
    console.log(myObject.num); // 3
    console.log(num); // 4
    var sub = myObject.sub;//  丢失了隐式绑定的myObject
    sub(); // 4
    var name = 'window'
    
    function Person (name) {
      this.name = name;
      this.show2 = () => console.log(this.name)
    }
    
    var personA = new Person('personA')
    
    personA.show2() //personA
    personA.show2.call(personB) // personA
    
    
    //另一种形式
    var name = 'window'
    
    var person1 = {
      name: 'person1',
      show2: () => console.log(this.name)
    }
    var person2 = { name: 'person2' }
    
    person1.show2() //window
    person1.show2.call(person2) //window
    
    //结论
    // 箭头函数的this无法通过bind,call,apply来**直接**修改(可以间接修改)

     实现一个深拷贝

    //没有考虑symbol和递归爆栈
    function cloneDeep(source, hash = new WeakMap()) {
        if (typeof source !== 'object') return source;
    
        let target = Array.isArray(source) ? [] : {}
        //解决循环引用和引用丢失
        if (hash.has(source)) {
            console.log('in')
            return hash.get(source)
        }
    
        hash.set(source, target)
    
        for (let item in source) {
            if (source.hasOwnProperty(item)) {
                if (typeof source[item] === 'object' && source[item] != null) {
                    target[item] = cloneDeep(source[item], hash)
                } else {
                    target[item] = source[item]
                }
            }
    
        }
        return target
    
    }
    //参考链接https://github.com/yygmind/blog/issues/29

     node与浏览器的event loop 区别

    https://juejin.im/post/5d5b4c2df265da03dd3d73e5 (浏览器的事件循环)

    https://juejin.im/post/5c337ae06fb9a049bc4cd218#heading-12 (比较)

    // node的运行环境
    console.log('start')
    setTimeout(() => {
      console.log('timer1')
      Promise.resolve().then(function() {
        console.log('promise1')
      })
    }, 0)
    setTimeout(() => {
      console.log('timer2')
      Promise.resolve().then(function() {
        console.log('promise2')
      })
    }, 0)
    Promise.resolve().then(function() {
      console.log('promise3')
    })
    console.log('end')
    //start=>end=>promise3=>timer1=>timer2=>promise1=>promise2
    
    // 浏览器的运行环境
    //start=>end=>promise3=>timer1=>promise1=>timer2=>promise2

    一开始执行栈的同步任务(这属于宏任务)执行完毕后(依次打印出start end,并将2个timer依次放入timer队列),会先去执行微任务(这点跟浏览器端的一样),所以打印出promise3

    然后进入timers阶段,执行timer1的回调函数,打印timer1,并将promise.then回调放入microtask队列,同样的步骤执行timer2,打印timer2;这点跟浏览器端相差比较大,timers阶段有几个setTimeout/setInterval都会依次执行,并不像浏览器端,每执行一个宏任务后就去执行一个微任务

    如果是node11版本一旦执行一个阶段里的一个宏任务(setTimeout,setInterval和setImmediate)就立刻执行微任务队列,这就跟浏览器端运行一致

    如果是node10及其之前版本:要看第一个定时器执行完,第二个定时器是否在完成队列中

    总结:

    Node端,microtask 在事件循环的各个阶段之间执行

    浏览器端,microtask 在事件循环的 macrotask 执行完之后执行

    对constructor的理解

    export 和 export default

    export 导出的变量实际上仍然可以受到原来模块的控制。不单单本身模块的a值会变化, 使得其他模块中引入的 a 值发生改变

    export default 导出的是值,导出的就是普通变量 a 的值,以后 a 的变化与导出的值就无关了,修改变量 a,不会使得其他模块中引入的 default 值发生改变。

  • 相关阅读:
    BUAA 2020 软件工程 个人项目作业
    BUAA 2020 软件工程 个人博客作业
    BUAA 2020 软件工程 热身作业
    面向对象设计与构造2019 第四单元总结博客作业
    面向对象设计与构造2019 第三单元总结博客作业
    Windows 安装rabbitmq
    windows 安装mongodb4.2.7
    docker安装(ubuntu20.04)
    C# 文件操作
    经纬度转换 sql 自定义函数
  • 原文地址:https://www.cnblogs.com/luguiqing/p/10392916.html
Copyright © 2011-2022 走看看