用了很久的react了,突然想一探究竟react源码什么样子,于是开始了我的react源码细节之路探索,我这里不讲源码,只讲我对知识点的扩展和联想,希望对大家有用。
首先,看看平时我们继承的 Component 和 PureComponent。
Component 和 PureComponent
首先我们会看到这句话:
路径:react/packages/react/src/ReactBaseClasses.js /
const emptyObject = {};
if (__DEV__) {
Object.freeze(emptyObject);
}
于是MDN 了 Object.freeze(),MDN这样解释的:Object.freeze()方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
这里冻结了一个emptyObject属性,我联想了const 也可以定义常量,引发了我的思考?
Object.freeze() 与 const name = 'lq' 区别;
const: 无法重新分配变量,但仍然可以改变对象本身(说的很简单,需要大家自己理解)。
Object.freeze(): 对象具有无法修改或删除的属性。实际上具有嵌套属性的对象并未被冻结(说的很简单,需要大家自己理解)。
那如何封装一个深度冻结对象呢?
封装一个深度冻结对象
module.exports = function deepFreeze (o) {
Object.freeze(o);
Object.getOwnPropertyNames(o).forEach(function (prop) {
if (o.hasOwnProperty(prop)
&& o[prop] !== null
&& (typeof o[prop] === "object" || typeof o[prop] === "function")
&& !Object.isFrozen(o[prop])) {
deepFreeze(o[prop]);
}
});
return o;
};
这个方法里面有三个方法引发了探索和思考:
Object.getOwnPropertyNames()
Object.prototype.hasOwnProperty()
Object.isFrozen()
Object.getOwnPropertyNames()
MDN: Object.getOwnPropertyNames(obj: 其自身的可枚举和不可枚举属性的名称被返回) 方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
如何只获取可枚举属性:
function ParentClass() {}
ParentClass.prototype.inheritedMethod = function() {};
function ChildClass() {
this.prop = 5;
this.method = function() {};
}
ChildClass.prototype = new ParentClass;
ChildClass.prototype.prototypeMethod = function() {};
console.log(
Object.getOwnPropertyNames(
new ChildClass() // ["prop", "method"]
)
);
只获取不可枚举的属性:
var target = myObject;
var enum_and_nonenum = Object.getOwnPropertyNames(target);
var enum_only = Object.keys(target);
var nonenum_only = enum_and_nonenum.filter(function(key) {
var indexInEnum = enum_only.indexOf(key);
if (indexInEnum == -1) {
// 没有发现在enum_only健集中意味着这个健是不可枚举的,
// 因此返回true 以便让它保持在过滤结果中
return true;
} else {
return false;
}
});
Object.prototype.hasOwnProperty()
MDN: hasOwnProperty(str:要检测的属性的 String 字符串形式表示的名称,或者 Symbol。) 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
Object.isFrozen()
Object.isFrozen()方法判断一个对象是否被冻结。
继续往后看
function Component(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.isReactComponent = {};
Component.prototype.setState = function(partialState, callback) {
invariant(
typeof partialState === 'object' ||
typeof partialState === 'function' ||
partialState == null,
'setState(...): takes an object of state variables to update or a ' +
'function which returns an object of state variables.',
);
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
Component.prototype.forceUpdate = function(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
// 为什么需要多一个中间函数?寄生继承
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
// 寄生虫
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// 1.这句话为什么不可以写在 PureComponent.prototype = new ComponentDummy()前面,有什么影响,因为前面PureComponent.prototype是引用类型。
// 2.性能:减少原型链查找以及扩展自身原型上面的方法。
// Avoid an extra prototype jump for these methods.
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;
export {Component, PureComponent};
这里为什么使用寄生继承?我们知道JavaScript继承方式有很多种,为什么react要这样实现继承?相比较其他的继承方式优势在哪里?希望大家下来多多思考。
网友评论