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]
缺点:
- 父类的应用类型实例被所有实例共享。
- 无法传参
构造函数继承 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
- 当一个函数自然执行时,指向全局,严格模式下是undefined。自然执行就是全局。
- 看执行时那一刻被谁点出来的。
- new一个实例的时候,构造函数内部的this指向即将生成的实例。
- bind,call,apply可以改变this指向。
- 箭头函数没有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)