平时不用分号,只有在特定情况下,基本上是[,(,+,-,/
开头的地方(这是在犀牛书里面看到的,实际工作中也就是那么几种情况下). 比如:
const FOO = "FOO"
;[1].forEach(item => console.log(item))
;(function() {
return console.log("bar")
}())
for (let i = 0; i < 2; i+=1) console.log(i)
#26 楼 @darkbaby123 有没有什么工作只专注于写前端接口和算法的?感觉前端的业务真的是太难写了。不仅要对接后端 API,ajax 还是 fetch,各种异步处理的标准,数据结构处理,还要写组件,之下还有事件、动效,语义化 HTML,CSS 模块,还有 UI。当然还有自动化等等。一直没玩过 emberjS,但是不知道为什么,越来越对它有好感。
const pattern = /^(?:\s*(<[\w\W]+>)[^>]|#([\w-]))$/
/^ (?: \s* ( <[\w\W]+> ) [^>] | # ( [\w-] ) )$/
//
区间为正则表达式^()$
匹配从开头至结尾所有的内容(?:)
该匹配不记结果,就是你用pattern.exec("some string")
,就算匹配成功,但不反回匹配结果\s*
匹配0
至多个空白符号(<[\w\W]+>)
匹配<whatever>
, 即:尖括号之内至少有一个[A-Za-z0-9_]
及[^A-Za-z0-9_]
字符,并且返回结果[^>]
非>
|
或#
匹配#
符号([\w-])
匹配`[A-Za-z0-9_]
及-
,并且返回结果。大致能匹配到的字符串是:
" <a >#"
" <b >-"
" <c >0"
"<d>z"
const FOO = "FOO"
const BAR = "BAR"
console.log(`${FOO}${BAR}`) // => "FOOBAR"
先收藏了。感谢。
#12 楼 @darkbaby123 #8 楼 @nightire
刚才稍微改了下我的方案,似乎也可以。假设,截获所有REQUEST|SUCCESS|FAILURE
的动作,然后根据前缀使用制定的reducer
。见上面。
这是我想到的一种方案,但不知道业务膨胀之后会否比较难控制。
import { assign } from "../utils"
import login from "./auth/login"
// ...
const initState = {
isFetching: false,
isAuthenticated: !!cookie.parse(document.cookie)["_at_"]
}
const reducerMap = {
"LOGIN": login
// ...
}
export default function app(state = initState, action) {
const type = action.type
let tmpState
// when `"LOGIN_REQUEST"`
if (/REQUEST/.test(type)) {
tmpState = assign({}, state, {
isFetching: true
})
}
// when `"LOGIN_SUCCESS"` or `"LOGIN_FAILURE"`
if (/SUCCESS|FAILURE/.test(type)) {
tmpState = assign({}, state, {
isFetching: false
})
}
for (let prop in reducerMap) {
// `"LOGIN_REQUEST".indexOf("LOGIN")`
// `"LOGIN_SUCCESS".indexOf("LOGIN")`
// `"LOGIN_FAILURE".indexOf("LOGIN")`
if (type.indexOf(prop) > -1) {
// return reducerMap["LOGIN"](tmpState, action)
return reducerMap[prop](tmpState, action)
}
}
// default
return state
}
import {
LOGIN_SUCCESS,
LOGIN_FAILURE
} from "../../constants/actionTypes"
import { assign } from "../../utils"
export default function login(state, { type, payload }) {
if (type === LOGIN_SUCCESS) {
return assign({}, state, {
isAuthenticated: true,
message: payload.message
})
}
if (type === LOGIN_FAILURE) {
return assign({}, state, {
message: payload.message
})
}
}
// LOGIN
export const LOGIN_REQUEST = "LOGIN_REQUEST"
export const LOGIN_SUCCESS = "LOGIN_SUCCESS"
export const LOGIN_FAILURE = "LOGIN_FAILURE"
#1 楼 @small_fish__ 感谢,,关于项目中的 reducer 一般分为数据相关和 UI 相关,我们的经验是数据相关以资源命名放在顶层,所以 UI 状态以 UI namespce 放在顶层 . 可以给具体一些的例子吗?最好可以看代码,谢谢。
定制的几个 pixel 艺术主题。terminal 主题。
刚上手 redux,之前写了一个多月 reflux,真想吐槽,去你妹的!
之前 angular 刚感觉熟练了,结果被迫丢掉 (算一门技能)。开始写 react,真是几乎又新学了一门技能(对于年龄大的人而言,真是要命),由于业务原因,原先的项目是 reflux 做的,我接手以后 (也是我第一次用 react),辛辛苦苦花了几天强记 reflux 的 api 文档,然后写了个把月,算是有些理解了,妈逼的又要叫我改写 redux,然后苦逼的 redux(真的想说给傻逼用的),又是看文档,搜教程 (对于年纪大的我而言真是心脏受不了,都想改行了)。学 redux 一来就是一个下马威,全部 es6(先不说一堆需要 polyfill 的特性,他妈的搞得我好郁闷啊,这个方法到底用不用啊?!!!),然后一堆 (action,actionTypes,reducers(如何 combineReducer 或不 combine, normalizr 数据,到现在我对于设计全局 store 的 state 还是一头雾水),然后 react 又是 class 写法,又是 staeless 写法(完全搞不明白为什么又是这样定义一个 react component,怎么又是那样定义一个 component),然后妈逼的蛋疼的 router 处理,先来个 react-router,结果处理跳转各种其他需求,又来了个 recat-router-redux(妈逼的)。花了好多时间终于能把 counter 这个小小的简单应用写出来了。然后又是 async 处理,redux middleware,还有 store 映射到 react component(所谓的 map(State||Dispatch)ToProps),怪哉,他妈的怎么有些情况在 dispatch 里面要访问 stateProps,还要多写个 mergeProps, 最后把 state 和 dispatch handlers 绑定到 component。你妈的,想到这里就想骂人了。跟什么 P 的风呀,怀疑 angular 的性能,臃肿 (其实一般业务哪里有那么高的需求),不行就 jquery 吧,再不行,尝试 vanilla javascript 吧,反正现在的浏览器对于兼容性都基本趋向一致了,至于模块管理,什么 browserify, webpack(code-splitting, chunk) 全都是负担,我觉得 requireJS 就很靠谱了,毕竟咱们现在还是小前端。踏踏实实能把代码写的漂漂亮亮,不要每次动不动就推到重来就行 (基本上公司换人都不能接手别人的项目,还有蛋疼的 coffeescript)。
这些是我剥离出来的核心的几百行代码。
(function(window, document, undefined) {
var
jqLite, // delay binding since jQuery could be loaded after us.
jQuery, // delay binding
/** @name angular */
angular = window.angular || (window.angular = {}),
angularModule,
uid = 0;
function noop() {}
noop.$inject = [];
function identity($) {return $;}
identity.$inject = [];
var jq = function() {
if (isDefined(jq.name_)) return jq.name_;
var el;
var i, ii = ngAttrPrefixes.length, prefix, name;
for (i = 0; i < ii; ++i) {
prefix = ngAttrPrefixes[i];
if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
name = el.getAttribute(prefix + 'jq');
break;
}
}
return (jq.name_ = name);
};
var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
function getNgAttribute(element, ngAttr) {
var attr, i, ii = ngAttrPrefixes.length;
for (i = 0; i < ii; ++i) {
attr = ngAttrPrefixes[i] + ngAttr;
if (isString(attr = element.getAttribute(attr))) {
return attr;
}
}
return null;
}
function angularInit(element, bootstrap) {
var appElement,
module,
config = {};
// The element `element` has priority over any other element
forEach(ngAttrPrefixes, function(prefix) {
var name = prefix + 'app';
if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
appElement = element;
module = element.getAttribute(name);
}
});
forEach(ngAttrPrefixes, function(prefix) {
var name = prefix + 'app';
var candidate;
if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
appElement = candidate;
module = candidate.getAttribute(name);
}
});
if (appElement) {
config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
bootstrap(appElement, module ? [module] : [], config);
}
}
function bootstrap(element, modules, config) {
if (!isObject(config)) config = {};
var defaultConfig = {
strictDi: false
};
config = extend(defaultConfig, config);
var doBootstrap = function() {
element = jqLite(element);
if (element.injector()) {
var tag = (element[0] === document) ? 'document' : startingTag(element);
//Encode angle brackets to prevent input from being sanitized to empty string #8683
throw ngMinErr(
'btstrpd',
"App Already Bootstrapped with this Element '{0}'",
tag.replace(/</,'<').replace(/>/,'>'));
}
modules = modules || [];
modules.unshift(['$provide', function($provide) {
$provide.value('$rootElement', element);
}]);
if (config.debugInfoEnabled) {
// Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
modules.push(['$compileProvider', function($compileProvider) {
$compileProvider.debugInfoEnabled(true);
}]);
}
modules.unshift('ng');
var injector = createInjector(modules, config.strictDi);
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
}]
);
return injector;
};
var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
config.debugInfoEnabled = true;
window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
}
if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
return doBootstrap();
}
window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
angular.resumeBootstrap = function(extraModules) {
forEach(extraModules, function(module) {
modules.push(module);
});
return doBootstrap();
};
if (isFunction(angular.resumeDeferredBootstrap)) {
angular.resumeDeferredBootstrap();
}
}
function bindJQuery() {
var originalCleanData;
if (bindJQueryFired) {
return;
}
// bind to jQuery if present;
var jqName = jq();
jQuery = window.jQuery; // use default jQuery.
if (isDefined(jqName)) { // `ngJq` present
jQuery = jqName === null ? undefined : window[jqName]; // if empty; use jqLite. if not empty, use jQuery specified by `ngJq`.
}
// Use jQuery if it exists with proper functionality, otherwise default to us.
// Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
// Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
// versions. It will not work for sure with jQuery <1.7, though.
if (jQuery && jQuery.fn.on) {
jqLite = jQuery;
extend(jQuery.fn, {
scope: JQLitePrototype.scope,
isolateScope: JQLitePrototype.isolateScope,
controller: JQLitePrototype.controller,
injector: JQLitePrototype.injector,
inheritedData: JQLitePrototype.inheritedData
});
// All nodes removed from the DOM via various jQuery APIs like .remove()
// are passed through jQuery.cleanData. Monkey-patch this method to fire
// the $destroy event on all removed nodes.
originalCleanData = jQuery.cleanData;
jQuery.cleanData = function(elems) {
var events;
if (!skipDestroyOnNextJQueryCleanData) {
for (var i = 0, elem; (elem = elems[i]) != null; i++) {
events = jQuery._data(elem, "events");
if (events && events.$destroy) {
jQuery(elem).triggerHandler('$destroy');
}
}
} else {
skipDestroyOnNextJQueryCleanData = false;
}
originalCleanData(elems);
};
} else {
jqLite = JQLite;
}
angular.element = jqLite;
// Prevent double-proxying.
bindJQueryFired = true;
}
function setupModuleLoader(window) {
var $injectorMinErr = minErr('$injector');
var ngMinErr = minErr('ng');
function ensure(obj, name, factory) {
return obj[name] || (obj[name] = factory());
}
var angular = ensure(window, 'angular', Object);
// We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
angular.$$minErr = angular.$$minErr || minErr;
return ensure(angular, 'module', function() {
/** @type {Object.<string, angular.Module>} */
var modules = {};
return function module(name, requires, configFn) {
var assertNotHasOwnProperty = function(name, context) {
if (name === 'hasOwnProperty') {
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
}
};
assertNotHasOwnProperty(name, 'module');
if (requires && modules.hasOwnProperty(name)) {
modules[name] = null;
}
return ensure(modules, name, function() {
if (!requires) {
throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
"the module name or forgot to load it. If registering a module ensure that you " +
"specify the dependencies as the second argument.", name);
}
/** @type {!Array.<Array.<*>>} */
var invokeQueue = [];
/** @type {!Array.<Function>} */
var configBlocks = [];
/** @type {!Array.<Function>} */
var runBlocks = [];
var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
/** @type {angular.Module} */
var moduleInstance = {
// Private state
_invokeQueue: invokeQueue,
_configBlocks: configBlocks,
_runBlocks: runBlocks,
requires: requires,
name: name,
provider: invokeLaterAndSetModuleName('$provide', 'provider'),
factory: invokeLaterAndSetModuleName('$provide', 'factory'),
service: invokeLaterAndSetModuleName('$provide', 'service'),
value: invokeLater('$provide', 'value'),
constant: invokeLater('$provide', 'constant', 'unshift'),
decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
config: config,
run: function(block) {
runBlocks.push(block);
return this;
}
};
if (configFn) {
config(configFn);
}
return moduleInstance;
function invokeLater(provider, method, insertMethod, queue) {
if (!queue) queue = invokeQueue;
return function() {
queue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
};
}
function invokeLaterAndSetModuleName(provider, method) {
return function(recipeName, factoryFunction) {
if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
invokeQueue.push([provider, method, arguments]);
return moduleInstance;
};
}
});
};
});
}
function publishExternalAPI(angular) {
angularModule = setupModuleLoader(window);
angularModule('ng', ['ngLocale'], ['$provide',
function ngModule($provide) {
$provide.provider({
$$sanitizeUri: $$SanitizeUriProvider
});
$provide.provider('$compile', $CompileProvider).
directive({
a: htmlAnchorDirective,
// all other directives ....
}).
directive({
ngInclude: ngIncludeFillContentDirective
}).
directive(ngAttributeAliasDirectives).
directive(ngEventDirectives);
$provide.provider({
$browser: $BrowserProvider,
$cacheFactory: $CacheFactoryProvider,
$controller: $ControllerProvider,
$document: $DocumentProvider,
$filter: $FilterProvider,
$interpolate: $InterpolateProvider,
$interval: $IntervalProvider,
$http: $HttpProvider,
$location: $LocationProvider,
$log: $LogProvider,
$parse: $ParseProvider,
$rootScope: $RootScopeProvider,
$q: $QProvider,
$$q: $$QProvider,
$templateCache: $TemplateCacheProvider,
$timeout: $TimeoutProvider,
$window: $WindowProvider,
$$jqLite: $$jqLiteProvider,
// and other providers
});
}
]);
}
function createInjector(modulesToLoad, strictDi) {
strictDi = (strictDi === true);
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new HashMap([], true),
providerCache = {
$provide: {
provider: supportObject(provider),
factory: supportObject(factory),
service: supportObject(service),
value: supportObject(value),
constant: supportObject(constant),
decorator: decorator
}
},
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function(serviceName, caller) {
if (angular.isString(caller)) {
path.push(caller);
}
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(serviceName, caller) {
var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
}));
forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
return instanceInjector;
////////////////////////////////////
// $provider
////////////////////////////////////
function supportObject(delegate) {
return function(key, value) {
if (isObject(key)) {
forEach(key, reverseParams(delegate));
} else {
return delegate(key, value);
}
};
}
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
}
function enforceReturnValue(name, factory) {
return function enforcedReturnValue() {
var result = instanceInjector.invoke(factory, this);
if (isUndefined(result)) {
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
}
return result;
};
}
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
function value(name, val) { return factory(name, valueFn(val), false); }
function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');
providerCache[name] = value;
instanceCache[name] = value;
}
function decorator(serviceName, decorFn) {
var origProvider = providerInjector.get(serviceName + providerSuffix),
orig$get = origProvider.$get;
origProvider.$get = function() {
var origInstance = instanceInjector.invoke(orig$get, origProvider);
return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
};
}
////////////////////////////////////
// Module Loading
////////////////////////////////////
function loadModules(modulesToLoad) {
assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
var runBlocks = [], moduleFn;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
loadedModules.put(module, true);
function runInvokeQueue(queue) {
var i, ii;
for (i = 0, ii = queue.length; i < ii; i++) {
var invokeArgs = queue[i],
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
}
}
try {
if (isString(module)) {
moduleFn = angularModule(module);
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
runInvokeQueue(moduleFn._invokeQueue);
runInvokeQueue(moduleFn._configBlocks);
} else if (isFunction(module)) {
runBlocks.push(providerInjector.invoke(module));
} else if (isArray(module)) {
runBlocks.push(providerInjector.invoke(module));
} else {
assertArgFn(module, 'module');
}
} catch (e) {
if (isArray(module)) {
module = module[module.length - 1];
}
if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
// Safari & FF's stack traces don't contain error.message content
// unlike those of Chrome and IE
// So if stack doesn't contain message, we create a new string that contains both.
// Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
/* jshint -W022 */
e = e.message + '\n' + e.stack;
}
throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
module, e.stack || e.message || e);
}
});
return runBlocks;
}
////////////////////////////////////
// internal Injector
////////////////////////////////////
function createInternalInjector(cache, factory) {
function getService(serviceName, caller) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
serviceName + ' <- ' + path.join(' <- '));
}
return cache[serviceName];
} else {
try {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName, caller);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
}
throw err;
} finally {
path.shift();
}
}
}
function invoke(fn, self, locals, serviceName) {
if (typeof locals === 'string') {
serviceName = locals;
locals = null;
}
var args = [],
$inject = createInjector.$$annotate(fn, strictDi, serviceName),
length, i,
key;
for (i = 0, length = $inject.length; i < length; i++) {
key = $inject[i];
if (typeof key !== 'string') {
throw $injectorMinErr('itkn',
'Incorrect injection token! Expected service name as string, got {0}', key);
}
args.push(
locals && locals.hasOwnProperty(key)
? locals[key]
: getService(key, serviceName)
);
}
if (isArray(fn)) {
fn = fn[length];
}
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
}
function instantiate(Type, locals, serviceName) {
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
// Object creation: http://jsperf.com/create-constructor/2
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
var returnedValue = invoke(Type, instance, locals, serviceName);
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
return {
invoke: invoke,
instantiate: instantiate,
get: getService,
annotate: createInjector.$$annotate,
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
};
}
}
createInjector.$$annotate = annotate;
if (window.angular.bootstrap) {
console.log('WARNING: Tried to load angular more than once.');
return;
}
//try to bind to jquery now so that one can write jqLite(document).ready()
//but we will rebind on bootstrap again.
bindJQuery();
publishExternalAPI(angular);
jqLite(document).ready(function() {
angularInit(document, bootstrap);
});
})(window, document);
!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
#31 楼 @stevenlii 那是以前找的一个colorscheme
,现在我也不知道是哪个了,都几年前的帖子了哦。
#32 楼 @maloneguo 是这样的,即是你把 terminal 的 window size 设置成最大也没有办法,但 iterm2 似乎可以把你的 window 固定在顶部。不过我一般control
+command
+f
全屏模式,然后用screen
来当作多屏的。