violet0sea / note

can not open gist, so write here
0 stars 0 forks source link

杂货铺 #18

Open violet0sea opened 6 years ago

violet0sea commented 6 years ago

对于构造函数,有这么一个问题: 如果一个构造函数没有使用new运算符,如何在构造函数内部改造使其实现和new一样的效果?

1.使用instanceof判断this是不是该构造函数的实例

function Person() {
    if(!(this instanceof Person)) {
        return new Person();
    }
    // init property
}

2.今天看了阮老师的ES6,发现还要一个new.target属性,该属性指向调用的构造函数,so
function Person() {
    if(!new.target) {
        return new Person();
    }
    // init property
}
violet0sea commented 5 years ago

Arrow Function(=>),为什么要引入它呢? 主要是为了解决原本this在function里的指向,首先需要了解this的指向(4种),其中有一种情况是函数只是通过正常的形式调用时,this指向Global对象(严格模式下是undefined),由于this指向带来的困扰,曾今的方式是通过绑定this或者将this指向that等等之类的方式保留this的引用。但是引入=>函数后,直接就将箭头函数里的this绑定在了当前环境的this下,这也是react通常绑定this的方式;

this binding is not dynamic, but is instead lexical => is about lexical binding of this, arguments, and super 如果声明了=>函数,外层没有父级的函数,在箭头函数里直接使用arguments会报错,只有存在父级函数时,才正确,这是因为this, arguments and super都是绑定在里surrounding environment

violet0sea commented 5 years ago

Javascript里的new操作符实现方式

  1. 首先创建一个空对象obj;
  2. 设置obj对象的内部属性[[prototype]](也就是各大浏览器实现的prototype)指向构造函数的prototype;
  3. 执行构造函数并将this指向obj,通过apply方法实现;
  4. 如果构造函数返回了一个对象,则使用该对象,否则返回obj。

代码实现:

function NewOperator(func) {
  let obj = {}, res;
  const args = [].slice.call(arguments, 1);

  // obj.__proto__ = func.prototype; 性能不好
  // Object.setPrototypeof(obj, func.prototype); 依然性能不佳
  obj = Object.create(func.prototype);
  res = func.apply(obj, args);
  // if((Object(res) === res) && res !== null) {
  //   return res;
  // }
  if(res instanceof Object) {
    return res;
  }
  return obj;
}
function Person(name) {
  this.name = name;
}
const p1 = NewOperator(Person, 'lemon');

function Student(name) {
  this.name = name;
  return {};
}
const p2 = NewOperator(Student, 'orange');
violet0sea commented 5 years ago

this binding 4 ways and arrow function key point: call-site precedence

1.default binding: standalone function invocation
function foo() {
  console.log(this) // undefined(strict mode) | global
}

foo();
2.implicit binding: have a context object, which means oject methods
let obj = {
  run: foo 
};

obj.run() // refer to obj
3. explicit binding Function has call(...) and apply(...) and bind(...)
let boundFun = fun.bind(context);

boundFun();
4.new binding

function foo(a) {
  this.a = a;
}

let bar = new foo(10);
bar.a // 10

the order of precedence

Caution binding exceptions

  1. ignore this (pass null, undefined to call, apply, bind)
  2. ES6 arrow-functions use lexical scoping for this binding, which means they adopt the this binding from its enclosing function call.

function foo() { console.log(this.a); }

var a = 2; // let and const did not give window the property foo.call(null) // maybe it is better to use Θ = Object.create(null) (DMZ object) to create an empty object, foo.call(Θ)

violet0sea commented 5 years ago

简单的SPA路由

  1. Hash 路由 当url的hash路由发生变化时可以监听hashchange事件来响应

    export class HashRouter {
    constructor() {
        this.routes = {}; // 存放不同hash对应的cb
        this.currentUrl = '';
    }
    route(path, callback = noop) {
        this.routes[path] = callback;
    }
    updateView() {
        const hashString = location.hash.slice(1) || '/';
        let options = {};
    
        if(hashString === '/') {
            this.currentUrl = hashString;
        } else {
            const hashList = hashString.split('/').filter(d => d !== '');
            this.currentUrl = '/' + hashList[0];
            options.id = hashList[1] || '';
        }
    
        const cb = this.routes[this.currentUrl];
    
        if(typeof cb === 'function') {
            cb(options);
        }
    }
    init() {
        window.addEventListener('load', this.updateView.bind(this), false);
        window.addEventListener('hashchange', this.updateView.bind(this), false);
    }
    }
  2. History api 路由 使用history.pushState | history.replaceState
    export class BrowserRouter {
    constructor() {
        this.routes = {};
        this.currentUrl = '';
    }
    route(path, callback = noop) {
        this.routes[path] = callback;
    }
    updateView(url) {
        this.currentUrl = url;
        const cb = this.routes[this.currentUrl];
        if(typeof cb === 'function') {
            cb();
        }
    }
    bindLink() {
        const allLinks = document.querySelectorAll('a[data-href]');
        for(let i =0; i < allLinks.length; i++) {
            const current = allLinks[i];
            current.addEventListener('click', e => {
                e.preventDefault();
                const url = current.getAttribute('data-href');
                history.pushState({}, null, url);
                this.uodateView(url);
            }, false);
        }
    }
    init() {
        this.bindLink();
        window.addEventListener('popstate', e => {
            this.updateView(window.location.pathname);
        });
        window.addEventListener('load', () => this.updateView('/'), false);
    }
    }
violet0sea commented 5 years ago

Promise读书笔记 在Promise出现之前,一直都是使用回调函数来处理异步操作;直到Promise出现,规范了处理规则,按照统一的接口来编写

var promise = getAsyncPromise("file.txt");
promise.then(result => {
    // TODO handle data
}).catch(err => {
    // TODO handle error
});

对比node中一些文件读取将error作为第一个参数,这种方式更加规范;

规范后的优势:可以形成基于接口的各种各样的异步处理模式(将复杂的异步处理模式化),Promise.all 和 Promise.race就是典型的处理模式

Promise的状态

使用new Promise实例化的promise对象有以下三个状态:

  1. Fulfilled - 成功
  2. Rejected - 失败
  3. Pending - 不是resolve也不是reject的状态,通常是promise对象刚被创建初始化状态

promise对象的状态从Pending转换为Fulfilled或者Rejected之后,这个对象的状态就不会再发生改变

注意: promise的状态都是内部定义的,没有公开的api进行访问

创建一个promise对象

以实现一个get请求为例

function getUrl(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onload = function() {
      if(xhr.status === 200) {
        resolve(xhr.responseText);
      } else {
        reject(new Error(xhr.statusText));
      }
    };
    xhr.onerror = function() {
      reject(new Error(xhr.statusText));
    };
    xhr.send();
  });
}

promise提供的各种方法

Promise.resolve 直接产生一个Fulfilled状态的promise对象

Promise.resolve(100).then(val => console.log(val));

Thenable概念 Promise.resolve方法另外一个作用就是将thenable对象转换为promise对象,thenable指的是一个具有.then方法的对象