便签

265 阅读3分钟

diff的作用

就会为了减少Dom更新量,找到最小差异部分DOM,只更新差异部分DOM就好了

Diff 做法

只有两个新旧节点是相同节点的时候,才会去比较他们各自的子节点

Diff比较的逻辑

1、能不移动,尽量不移动

2、没得办法,只好移动

3、实在不行,新建或删除

1、先找到 不需要移动的相同节点,消耗最小

2、再找相同但是需要移动的节点,消耗第二小

3、最后找不到,才会去新建删除节点,保底处理

computed 和 watch 有什么区别?

computed 计算属性,是依赖其他属性的计算值,并且有缓存,只有当依赖的值变化时才会更新。

watch 是在监听的属性发生变化时,在回调中执行一些逻辑。 所以,computed 适合在模板渲染中,某个值是依赖了其他的响应式对象甚至是计算属性计算而来,而 watch 适合监听某个值的变化去完成一段复杂的业务逻辑。

computed vs methods

计算属性是基于他们的响应式依赖进行缓存的,只有在依赖发生变化时,才会计算求值,而使用 methods,每次都会执行相应的方法。

继承

原型链继承

function Parent(){
    this.name = 'fdasf';
    this.actions = ['fdas', 'fdsa' , 'fdas']
}

function Child(){
}

Child.prototype =  new Parent();
Child.prototype.constructor = Child;

const c1 = new Child();
c1.actions.push('fdsa')
const c2 = new Child();
console.warn(c2.actions); // ['fdas', 'fdsa' , 'fdas', 'fdsa]

缺点:

  1. 父类的应用类型实例被所有实例共享。
  2. 无法传参

构造函数继承 call、apply继承

function Parent(name, age){
    this.name = name;
    this.age = age;
    this.actions = ['fdas', 'fdsa' , 'fdas']
}

function Child(){
    Parent.call(this, ...arguments)
}

const c1 = new Child('fdasf', 20);
const c2 = new Child('fdasd', 30);

c1.actions.push('fdsa')
console.warn(c2.actions);
console.warn(c1);
console.warn(c2);

缺点:浪费内存,每次new一次都开辟新的存储空间,只要是直接用构造函数继承都会有浪费内存问题

组合继承 将上面两种方式组合起来

function Parent(name, age){
    this.name = name;
    this.age = age;
    this.actions = ['fdas', 'fdsa' , 'fdas']
}
Parent.prototype.getName = function(){
    return this.name;
};
function Child(){
    Parent.call(this, ...arguments)
}
Child.prototype =  new Parent();
Child.prototype.constructor = Child;
const c1 = new Child('fdasf', 20);
const c2 = new Child('fasd', 30);

c1.actions.push('fdsa')
console.warn(c2.actions);
console.warn(c1);
console.warn(c2);
console.warn(c1.getName());
console.warn(c2.getName());

缺点:调用了两次构造函数

寄生组合式继承

function prototype2(child, parent){
    function F(){};
    F.prototype = parent.prototype;
    child.prototype = new F();
    child.prototype.constructor = child;
}

function Parent(){
    this.name = 'fdsafd'
    this.age = 20
}

function Son(){
    this.name = 'fafd'

}

Parent.prototype.getName = function (){
    console.warn(this.age);
}
prototype2(Son, Parent)
const son = new Son()
console.warn(son.name);
console.warn(son.age);
console.warn(son.getName());

class 继承

class Parent {
    constructor(props) {
        this.name = 'zhang'
    }
    getName() {
        console.warn(this.name);
    }
}

class Child extends Parent {
    constructor(props) {
        super(props);
        this.age = 2;
    }
}
const child = new Child();
console.warn(child);
console.warn(child.getName());

实现一个new

function Player() {
    this.color = 'red';
    if(Player.total){
        Player.total = 0;
    }
    Player.total ++;
}

function myNew(){
    var obj = new Object();
    let Fun = Array.prototype.shift.call(arguments);
    obj.__proto__ = Fun.prototype;
    var returnObj = Fun.apply(obj, arguments);
    if(typeof returnObj === 'object'){
        return returnObj;
    }else{
        return obj
    }
}

const obj = myNew(Player);
console.warn(obj);

this

  1. 当一个函数自然执行时,指向全局,严格模式下是undefined。自然执行就是全局。
  2. 看执行时那一刻被谁点出来的。
  3. new一个实例的时候,构造函数内部的this指向即将生成的实例。
  4. bind,call,apply可以改变this指向。
  5. 箭头函数没有this,向上的作用域链去查找this,所以指向出生时的this。

设计模式

单例模式

一个类只维护一个实例

页面上点击元素创造弹窗,只能创造一次。

const Singleton = function(name){
    this.name = name;
    this.instatnce = null;
};
Singleton.prototype.getName = function(){
    console.warn(this.name);
};

Singleton.getInstance = function(name){
    if(!this.instance){
        this.instance = new Singleton(name);
    }
    return this.instance;
};

var a = Singleton.getInstance('a');

var b = Singleton.getInstance('b');

console.warn(a === b, a, b);

// 一个单利模式的方法
var proxySingle = (function(){
    var name = 'user';
    var _instance = null;
    return function(Func){
        if(!_instance) return new Func();
        return _instance;
    }
})();

function A(name){
    this.name = Math.random();
}

const a = proxySingle(A);
const b = proxySingle(A)