BccSafe's Blog Fight for a future

react+redux+es6上线问题小记

最近在折腾react全家桶,项目用react+redux+es6开发,写了几个页面后准备上线,发现在chrome和iphone6上工作正常,但是到了安卓机上只给一个白屏,网页的标题倒是出来了

一度崩溃后开始找工具调试,用DebugGap发现并没有报错,页面上只有一个给react插入的DOM节点,显然ReactDOM.render这个方法没有生效

google…

发现是babel只是将es6转换成es5,而部分安卓上浏览器对es5的支持还不够,比如promise

解决办法:import 'babel-polyfill'

Babel includes a polyfill that includes a custom regenerator runtime and core.js.

This will emulate a full ES6 environment. This polyfill is automatically loaded when using babel-node and babel/register.

BccBrowser V3.0

DcefBrowser的CEF3版本近期更新到了3.2623.1401,算是个比较大的更新,顺手把BccBrowser也更新了

这个版本解决了多个之前的遗留问题,比如输入法框显示不正确,滚轮速度太快

以后DcefBrowser的内核可能不会再更新了,因为2623将是最后一个支持xp的版本,在中国这个问题可能短时间内还解决不了

下载地址: https://pan.baidu.com/s/1pLTdegN

AngularJs1-ES6-Webpack 项目搭建

这份代码存在多个问题,Angular 1.x和webpack结合存在很多问题,暂时放弃...

关键字:AngularJs1, ES6, SASS, gulp, Webpack, livereload

一. 项目目录

├── gulpfile.js 存放gulp相关的配置

├── index.html 入口html

├── package.son 存放npm相关的配置

├── webpack.config.js 存放webpack相关的配置

├── css 存放scss代码

├── dist 存放打包了的js,css文件

├── js 存放es6代码

│   ├── index.js 入口文件

│   ├── compontent 组件

│       ├── module 模块组件

│       ├── CommonDirective.js 通用组件

│       └── index.js 入口文件

│   ├── config app配置

│       └── routing.js 路由

│   ├── module 模块

│       ├── test 测试模块

│       	├── index.js 入口文件

│       	├── routing.js 路由

│       	└── TestController.js 控制器

│   └── index.js 入口文件

├── view 存放html代码

│   ├── module 模块

│       ├── test 测试模块

│       	└── test.html 模版

└────

二. package.json

{
  "name": "AngularJs1-ES6-Webpack",
  "version": "0.0.1",
  "description": "A simple Demo using ES6, AngularJs1 and webpack",
  "devDependencies": {
    "angular": "~1.3.0",
    "angular-ui-router": "^0.2.14",
    "babel-core": "^6.10.4",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.9.0",
    "css-loader": "^0.23.1",
    "extract-text-webpack-plugin": "^1.0.1",
    "gulp": "^3.9.0",
    "gulp-util": "^3.0.7",
    "ng-annotate-loader": "~0.0.4",
    "node-sass": "^3.8.0",
    "raw-loader": "^0.5.1",
    "sass-loader": "^4.0.0",
    "style-loader": "^0.13.1",
    "webpack": "^1.13.1",
    "webpack-dev-server": "^1.12.1"
  },
  "author": "BccSafe",
  "license": "MIT"
}

三. AngularJs ES6写法

1) 路由

//routing.js
import TestController from './TestController.js';

export default function routing($stateProvider) {
	'ngInject';
	
    $stateProvider.state('test', {
        url: '/test',
        templateUrl: "view/module/test/test.html",
        controller: TestController
    });
}

//index.js
import 'angular';
import angularUIRouter from 'angular-ui-router';
import routing from './config/routing.js';

let myApp = angular.module("myApp", [angularUIRouter]);

myApp.config(routing);

2) Controller(Service, Factory同理)

//TestController.js
class TestController {

    constructor($rootScope, $scope, $stateParams){
        'ngInject';

        $scope.testValue = "this value from the Class TestController"; 
    }

}

export default TestController;

//index.js
import 'angular';
import angularUIRouter from 'angular-ui-router';
let testModule = angular.module('testModule', [angularUIRouter]);

export default testModule = testModule.name;

3) Directive

//CommonDirective
class CommonDirective {

    constructor(){
        'ngInject';

        this.template = '<div>I\'m a directive!</div>';
        this.restrict = "E";
    }

}

export default CommonDirective;

//index.js
import 'angular';
import CommonDirective from './CommonDirective.js';

let CommonCptModule = angular.module('CommonCptModule', []);

CommonCptModule.directive('commonDirective', () => new CommonDirective);

export default CommonCptModule = CommonCptModule.name;

四. gulp+webpack 实现打包调试

1) 判断process.env.NODE_ENV的值来区分是开发还是发布

gulp.task('set-dev-node-env', () => {
	return process.env.NODE_ENV = 'development';
});

gulp.task('set-prod-node-env', () => {
    return process.env.NODE_ENV = 'production';
});

if (process.env.NODE_ENV === 'production') {
		myConfig.plugins.push(new ExtractTextPlugin("style.css", {allChunks: true}));
}

2) Webpack模块加载器(Loaders)

loaders 用于转换应用程序的资源文件,他们是运行在nodejs下的函数 使用参数来获取一个资源的来源并且返回一个新的来源(资源的位置),例如:你可以使用loader来告诉webpack去加载一个coffeescript或者jsx

用到了babel-loader, css-loader, style-loader, sass-loader, raw-loader来完成html, es6, sass的加载, ng-annotate-loader用于添加 AngularJS依赖注入

3) Webpack开发服务器 webpack-dev-server

Webpack提供了一个基于Node.js Express框架的开发服务器,它是一个静态资源Web服务器,对于简单静态页面或者仅依赖于独立服务的前端页面,都可以直接使用这个开发服务器进行开发。在开发过程中,开发服务器会监听每一个文件的变化,进行实时打包,并且可以推送通知前端页面代码发生了变化,从而可以实现页面的自动刷新。

对HTML, Es6, SCSS文件的更改将可以不需要刷新自动更新,这点很爽

gulp.task('server', ['set-dev-node-env', 'webpack', 'myWatch'], (callback) => {
	var myConfig = Object.create(webpackConfig);
	myConfig.devtool = 'eval';
	myConfig.debug = true;
	myConfig.entry.unshift("webpack-dev-server/client?http://localhost:8080/", "webpack/hot/dev-server");

	new WebpackDevServer(webpack(myConfig), {
		publicPath: '/',
		stats: {
			colors: true
		},
		hot: true
	}).listen(8080, 'localhost', (err) => {
		if(err) throw new gutil.PluginError('webpack-dev-server', err);
		gutil.log('[webpack-dev-server]', 'http://localhost:8080/webpack-dev-server/index.html');
	});
});

查看完整代码

React Native IOS开发试水

忙了一段时间,没更新Blog,上来分享个React Native开发的天气APP,是我这学期IOS课的期末作业,没用OC的原因是想尝试下RN,之前接触的太少

上图,分别是主界面,城市列表,搜索界面,仿了苹果自带的天气APP

weatherMainView


weatherCityList


weatherSearch

初次上手RN,界面布局用了FlexBox,js方面用了最新的ES6,RN支持最新的写法,import/export处理各模块的依赖关系很爽,html则是JSX,第一次使不太习惯吧。

大概花了三天时间,整个过程还是比较有趣的,js开发原生IOS应用很棒!

AngularJS控制器继承自另一控制器

AngularJS里控制器继承,常用的就是作用域嵌套作用域。默认情况下,当前作用域中无法找到某个属性时,就会在父级作用域中进行查找,若找不到直至查找到$rootScope。

但有些情况下,rootScope下就是我们的controller,不可能将大量的公用属性方法写到rootScope里去。

比如说有多个类似的页面,都有面包屑,搜索栏,工具栏,表格等元素,面包屑表格这种元素考虑做成directive,那么必然会有许多类似的配置需要从controller传到组件里去,也会产生很多工具类方法用于处理数据等,这时候在每个页面的controller里重复写相同的代码显然很难看,就需要用到继承。

在StackOverflow上找到了解决方案,原来AngularJS已经考虑到这种情况了,提供了$controller

var app = angular.module('angularjs-starter', []); 
app.controller('ParentCtrl ', function($scope) {
  // I'm the sibling, but want to act as parent
});
app.controller('ChildCtrl', function($scope, $controller) {
  $controller('ParentCtrl', {$scope: $scope}); //This works
});

StackOverflow链接

ECMAScript继承对象的若干方法

以下内容均整理自《JavaScript高级程序设计》第六章 面向对象的程序设计

  • 原型链
function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
};
function SubType(){
    this.subproperty = false;
}
//继承了 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
    return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue());//true
function SuperType(){
    this.colors = ["red", "blue", "green"];
}
function SubType(){
//继承了 SuperType
    SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors);    //"red,blue,green"
  • 借用构造函数
function SuperType(){
    this.colors = ["red", "blue", "green"];
}
function SubType(){
//继承了 SuperType
    SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors);    //"red,blue,green"
function SuperType(name){
    this.name = name;
}
function SubType(){
//继承了 SuperType,同时还传递了参数 SuperType.call(this, "Nicholas");
//实例属性
    this.age = 29;
}
var instance = new SubType();
alert(instance.name);    //"Nicholas";
alert(instance.age);     //29
  • 组合继承
function SuperType(name){
	this.name = name;
	this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name, age){
//继承属性 SuperType.call(this, name);
    this.age = age;
}
//继承方法
SubType.prototype = new SuperType(); 
SubType.prototype.constructor = SubType; 
SubType.prototype.sayAge = function(){
    alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors);//"red,blue,green,black"
instance1.sayName();//"Nicholas";
instance1.sayAge();//29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors);//"red,blue,green"
instance2.sayName();//"Greg";
instance2.sayAge();//27
  • 原型式继承
function object(o){
	function F(){} 
	F.prototype = o;
	return new F();
}
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
  • 寄生式继承
function createAnother(original){ 
	var clone = object(original); //通过调用函数创建一个新对象
	clone.sayHi = function(){ //以某种方式来增强这个对象
		alert("hi");
	};
	return clone; //返回这个对象
}
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"
  • 寄生组合式继承
function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
    alert(this.age);
};
function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}
function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
    alert(this.age);
}

总结

原型式继承可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制。而复制得到的副本还可以得到进一步改造。

组合继承是JavaScript中最常用的继承模式,instanceof 和 isPrototypeOf()都能够用于识别基于组合继承创建的对象。

寄生式继承与原型式继承非常相似,也是基于某个对象或某些信息创建一个对象,然后增强对象,最后返回对象。为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问题,可以将这个模式与组合继承一起使用。

寄生组合式继承集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。

ECMAScript创建对象的若干方法

以下内容均整理自《JavaScript高级程序设计》第六章 面向对象的程序设计

PS 读完这一章真的熟悉颇多,之前自己编写工具类的时候就很疑惑,只是简单的百度了解下,这次的则较为系统。

  • 工厂模式
function createPerson(name, age, job){
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function(){
            alert(this.name);
        };
		  return o;
 }
    var person1 = createPerson("Nicholas", 29, "Software Engineer");
    var person2 = createPerson("Greg", 27, "Doctor");
  • 构造函数模式
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
}
function sayName(){
    alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
  • 原型模式
function Person(){
}
Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    friends : ["Shelby", "Court"],
    sayName : function () {
        alert(this.name);
	  }
 };
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends);    //"Shelby,Court,Van"
alert(person2.friends);    //"Shelby,Court,Van"
alert(person1.friends === person2.friends);  //true
  • 组合使用构造函数模式和原型模式
function Person(name, age, job){
	this.name = name;
	this.age = age;
	this.friends = ["Shelby", "Court"];
}
Person.prototype = {
	constructor: Person,
	sayName: function() {
		alert(this.name);
	}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends);    //"Shelby,Count,Van"
alert(person2.friends);    //"Shelby,Count"
alert(person1.friends === person2.friends);//false
alert(person1.sayName === person2.sayName);//true
  • 动态原型模式
function Person(name, age, job){ 		
	this.name = name;
	this.age = age;
	this.job = job;
	if (typeof this.sayName != "function"){
		Person.prototype.sayName = function(){
			alert(this.name);
		}; 
	}
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();
  • 寄生构造函数模式
function Person(name, age, job){
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function(){
            alert(this.name);
        };
		  return o;
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();  //"Nicholas"
  • 稳妥构造函数模式
function Person(name, age, job){
        //创建要返回的对象
        var o = new Object();
        //可以在这里定义私有变量和函数
		  //...
        //添加方法
        o.sayName = function(){
            alert(this.name);
        };
		  return o;
}
var friend = Person("Nicholas", 29, "Software Engineer");
friend.sayName();  //"Nicholas"

优缺点

/ 对象识别(instanceof) 多个实例共享同一个function function不在全局作用域,具有封装性 构造函数能传递初始化参数 多个实例有各自的属性,不共享
工厂模式 No No Yes Yes Yes
构造函数模式 Yes Yes No Yes Yes
原型模式 Yes
(需要设置constructor值)
Yes Yes No No
组合使用构造函数模式和原型模式 Yes Yes Yes Yes Yes
动态原型模式 Yes Yes Yes Yes Yes

总结

上表可以看出组合使用构造函数模式和原型模式动态原型模式是较为完美的方案,前者更常用,而寄生构造函数模式稳妥构造函数模式则是为了解决特殊的问题而提出的,不在讨论范围内,前者为了在已有对象上添加一个额外方法,并创建构造函数;后者则是安全方面的考虑。

JavaScript高级程序设计 阅读笔记

转前端5个月,意识到基础过于薄弱,买了《JavaScript高级程序设计》恶补,并把一些学到的纪录下来

  • JavaScript变量
P68

按照ECMA-262的定义,JavaScript的变量与其他语言的变量有很大区别

ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。基本类型值有Undefined、Null、Boolean、Number、String

  • 检测变量类型
P72

typeof 操作符是确定一个变量是字符串、数值、布尔值,还是 undefined 的最佳工具

var s = "Nicholas";
var b = true;
var i = 22;
var u;
var n = null;
var o = new Object();
alert(typeof s); //string
alert(typeof i); //number
alert(typeof b); //boolean
alert(typeof u); //undefined
alert(typeof n); //object
alert(typeof o); //object

但在检测引用类型的值时,这个操作符的用处不大。通常,我们并不是想知道某个值是对象,而是想知道它是什么类型的对象。为此,ECMAScript提供了 instanceof 操作符

alert(person instanceof Object); // 变量 person 是 Object 吗?
alert(colors instanceof Array); // 变量 colors 是 Array 吗?
alert(pattern instanceof RegExp); // 变量 pattern 是 RegExp 吗?
  • 垃圾回收
P78

JavaScript 具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。垃圾收集方式有标记清楚引用计数,前者最常用。

性能问题与内存管理。垃圾收集器是周期性运行的,确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为 null 来释放其引用——这个做法叫做解除引用

  • Array类型
P86

除了 Object 之外,Array 类型恐怕是 ECMAScript 中最常用的类型了

  • push 接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
  • pop 从数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项
  • shift 移除数组中的第一个项并返回该项,同时将数组长度减1
  • reverse 反转数组项的顺序并返回
  • sort 按升序排列数组项并返回
  • concat 在没有给 concat()方法传递参数的情况下,它只是 复制当前数组并返回副本。如果传递给 concat()方法的是一或多个数组,则该方法会将这些数组中的 每一项都添加到结果数组中。如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾。
  • slice slice()方法可以 接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下,slice()方法返回从该 参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束位置之间的项— —但不包括结束位置的项。注意,slice()方法不会影响原始数组。可用于删除,插入,替换。
  • indexOf 接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。从数组的开头(位置 0)开始向后查找
  • lastIndexOf 接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。从数组的末尾开始向前查找。
  • every 对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true。
  • filter 对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。
  • forEach 对数组中的每一项运行给定函数。这个方法没有返回值。
  • map 对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
  • some 对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true。
var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item, index, array){
 return (item > 2);
}); 
alert(everyResult); //false
var someResult = numbers.some(function(item, index, array){
 return (item > 2);
});
alert(someResult); //true 
var filterResult = numbers.filter(function(item, index, array){
 return (item > 2);
});
alert(filterResult); //[3,4,5,4,3] 
var mapResult = numbers.map(function(item, index, array){
 return item * 2;
});
alert(mapResult); //[2,4,6,8,10,8,6,4,2] 
  • reduce 迭代数组的所有项,然后构建一个最终返回的值。从数组的第一项开始,逐个遍历 到最后。
  • reduceRight 迭代数组的所有项,然后构建一个最终返回的值。从数组的最后一项开始,向前遍历到第一项。
var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
 return prev + cur;
});
alert(sum); //15