-
Notifications
You must be signed in to change notification settings - Fork 319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
createClass #27
Comments
第二代 import { extend, isFn, inherit, noop } from "./util";
import { Component } from "./Component";
/**
* 为了兼容0.13之前的版本
*/
var MANY = "DEFINE_MANY";
var MANY_MERGED = "MANY_MERGED";
var ReactClassInterface = {
mixins: MANY,
statics: MANY,
propTypes: MANY,
contextTypes: MANY,
childContextTypes: MANY,
getDefaultProps: MANY_MERGED,
getInitialState: MANY_MERGED,
getChildContext: MANY_MERGED,
render: "ONCE",
componentWillMount: MANY,
componentDidMount: MANY,
componentWillReceiveProps: MANY,
shouldComponentUpdate: "DEFINE_ONCE",
componentWillUpdate: MANY,
componentDidUpdate: MANY,
componentWillUnmount: MANY
};
var specHandle = {
displayName(Ctor, value, name) {
Ctor[name] = value;
},
mixins(Ctor, value) {
if (value) {
for (var i = 0; i < value.length; i++) {
mixSpecIntoComponent(Ctor, value[i]);
}
}
},
propTypes: mergeObject,
childContextTypes: mergeObject,
contextTypes: mergeObject,
getDefaultProps(Ctor, value, name) {
if (Ctor[name]) {
Ctor[name] = createMergedResultFunction(Ctor[name], value);
} else {
Ctor[name] = value;
}
},
statics(Ctor, value) {
extend(Ctor, Object(value));
},
autobind: noop
};
function mergeObject(fn, value, name) {
fn[name] = Object.assign({}, fn[name], value);
}
//防止覆盖Component内部一些重要的方法或属性
var protectedProps = {
mixin: 1,
setState: 1,
forceUpdate: 1,
__processPendingState: 1,
__pendingCallbacks: 1,
__pendingStates: 1
};
function mixSpecIntoComponent(Ctor, spec) {
if (!spec) {
return;
}
if (isFn(spec)) {
console.warn("createClass(spec)中的spec不能为函数,只能是纯对象"); // eslint-disable-line
}
var proto = Ctor.prototype;
var autoBindPairs = proto.__reactAutoBindPairs;
if (spec.hasOwnProperty("mixin")) {
specHandle.mixins(Ctor, spec.mixins);
}
for (var name in spec) {
if (!spec.hasOwnProperty(name)) {
continue;
}
if (protectedProps[name] === 1) {
continue;
}
var property = spec[name];
var isAlreadyDefined = proto.hasOwnProperty(name);
if (specHandle.hasOwnProperty(name)) {
specHandle[name](Ctor, property, name);
} else {
var isReactClassMethod = ReactClassInterface.hasOwnProperty(name);
var shouldAutoBind =
isFn(property) &&
!isReactClassMethod &&
!isAlreadyDefined &&
spec.autobind !== false;
if (shouldAutoBind) {
autoBindPairs.push(name, property);
proto[name] = property;
} else {
if (isAlreadyDefined) {
var specPolicy = ReactClassInterface[name];
//合并多个同名函数
if (specPolicy === MANY_MERGED) {
//这个是有返回值
proto[name] = createMergedResultFunction(proto[name], property);
} else if (specPolicy === MANY) {
//这个没有返回值
proto[name] = createChainedFunction(proto[name], property);
}
} else {
proto[name] = property;
}
}
}
}
}
function mergeOwnProperties(one, two) {
for (var key in two) {
if (two.hasOwnProperty(key)) {
one[key] = two[key];
}
}
return one;
}
function createMergedResultFunction(one, two) {
return function mergedResult() {
var a = one.apply(this, arguments);
var b = two.apply(this, arguments);
if (a == null) {
return b;
} else if (b == null) {
return a;
}
var c = {};
mergeOwnProperties(c, a);
mergeOwnProperties(c, b);
return c;
};
}
function createChainedFunction(one, two) {
return function chainedFunction() {
one.apply(this, arguments);
two.apply(this, arguments);
};
}
function bindAutoBindMethod(component, method) {
var boundMethod = method.bind(component);
return boundMethod;
}
function bindAutoBindMethods(component) {
var pairs = component.__reactAutoBindPairs;
for (var i = 0; i < pairs.length; i += 2) {
var autoBindKey = pairs[i];
var method = pairs[i + 1];
component[autoBindKey] = bindAutoBindMethod(component, method);
}
}
//创建一个构造器
function newCtor(className) {
var curry = Function(
"ReactComponent",
"bindAutoBindMethods",
`return function ${className}(props, context) {
ReactComponent.call(this, props, context);
this.state = this.getInitialState ? this.getInitialState() : {};
if (this.__reactAutoBindPairs.length) {
bindAutoBindMethods(this);
}
};`
);
return curry(Component, bindAutoBindMethods);
}
var warnOnce = 1;
export function createClass(spec) {
if (warnOnce) {
warnOnce = 0;
console.warn("createClass已经过时,强烈建议使用es6方式定义类"); // eslint-disable-line
}
var Constructor = newCtor(spec.displayName || "Component");
var proto = inherit(Constructor, Component);
proto.__reactAutoBindPairs = [];
delete proto.render;
mixSpecIntoComponent(Constructor, spec);
if (isFn(Constructor.getDefaultProps)) {
Constructor.defaultProps = Constructor.getDefaultProps();
}
//性能优化,为了防止在原型链进行无用的查找,直接将用户没有定义的生命周期钩子置为null
for (var methodName in ReactClassInterface) {
if (!proto[methodName]) {
proto[methodName] = null;
}
}
return Constructor;
} |
第三代 import {extend, isFn, inherit} from "./util";
import {Component} from "./Component";
/**
* 为了兼容0.13之前的版本
*/
const LiFECYCLE = {
render: 1,
shouldComponentUpdate: 1,
componentWillReceiveProps: 1,
componentWillUpdate: 1,
componentDidUpdate: 1,
componentWillMount: 1,
componentDidMount: 1,
componentWillUnmount: 1,
componentDidUnmount: 1
};
function collectMixins(mixins) {
let keyed = {};
for (let i = 0; i < mixins.length; i++) {
let mixin = mixins[i];
if (mixin.mixins) {
applyMixins(mixin, collectMixins(mixin.mixins));
}
for (let key in mixin) {
if (mixin.hasOwnProperty(key) && key !== 'mixins') {
(keyed[key] || (keyed[key] = [])).push(mixin[key]);
}
}
}
return keyed;
}
var MANY_MERGED = {
getInitialState: 1,
getDefaultProps: 1,
getChildContext: 1
}
function flattenHooks(key, hooks) {
let hookType = typeof hooks[0];
if (hookType === 'object') {
// Merge objects
hooks.unshift({});
return Object
.assign
.apply(null, hooks);
} else if (hookType === 'function') {
return function () {
let ret;
for (let i = 0; i < hooks.length; i++) {
let r = hooks[i].apply(this, arguments);
if (r && MANY_MERGED[key]) {
if (!ret)
ret = {};
Object.assign(ret, r);
}
}
return ret;
};
} else {
return hooks[0];
}
}
function applyMixins(proto, mixins) {
for (let key in mixins) {
if (mixins.hasOwnProperty(key)) {
proto[key] = flattenHooks(key, mixins[key].concat(proto[key] || []));
}
}
}
//创建一个构造器
function newCtor(className) {
var curry = Function("ReactComponent", "blacklist",
`return function ${className}(props, context) {
ReactComponent.call(this, props, context);
for (let methodName in this) {
let method = this[methodName];
if (typeof method === 'function'&& !blacklist[methodName]) {
this[methodName] = method.bind(this);
}
}
if (spec.getInitialState) {
this.state = spec.getInitialState.call(this);
}
};`);
return curry(Component, LiFECYCLE);
}
var warnOnce = 1;
export function createClass(spec) {
if (warnOnce) {
warnOnce = 0;
console.warn("createClass已经过时,强烈建议使用es6方式定义类"); // eslint-disable-line
}
var Constructor = newCtor(spec.displayName || "Component");
var proto = inherit(Constructor, Component);
//如果mixins里面非常复杂,可能mixin还包含其他mixin
if (spec.mixins) {
applyMixins(spec, collectMixins(spec.mixins));
}
extend(proto, spec);
if (spec.statics) {
extend(Constructor, spec.statics);
}
"propTypes,contextTypes,childContextTypes,displayName"
.replace(/\w+/g, function (name) {
if (spec[name]) {
Constructor[name] = spec[name];
}
})
if (isFn(spec.getDefaultProps)) {
Constructor.defaultProps = spec.getDefaultProps();
}
return Constructor;
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The text was updated successfully, but these errors were encountered: