react native 两周学习笔记

长孙正卿
2023-12-01

搭建demo环境

预期时间:1天
参照https://reactnative.cn/搭建编译环境,在真机上跑demo

2018-09-05
电脑有现成的android编译环境,已经安装node 8,已配置npm镜像,已 安装react-native模块。

ide使用webstorm,同时安装react native console插件

使用react-native init AwesomeProject生成项目
使用react-native run-android编译项目

从终端输出可以看出执行android命令主要是做如下几件事情

1.启动js server用于live reload
如果我们在手机端reload时报错,应用会提示我们直接在项目目录执行npm start 启动js server,从项目的package.json中scripts的配置可以看到,最后执行的命令为:

node node_modules/react-native/local-cli/cli.js start

2.编译android apk

Building and installing the app on the device (cd android && ./gradlew installDebug).

3.将js server的监听端口映射到手机的8081端口,此处失败,暂不处理,后面手动连接

Running adb -s 005f16d80f8e4ec6 reverse tcp:8081 tcp:8081
Could not run adb reverse: spawnSync adb ENOENT

4.启动默认启动页

Starting the app on 005f16d80f8e4ec6 (adb -s 005f16d80f8e4ec6 shell am start -n com.awesomeproject/com.awesomeproject.MainActivity)...

简单熟悉js和node

预期时间:1天
参考地址https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000

js基础
2018-09-06
1.变量使用var a = 10;的模式来定义,其中var可以省略,则定义的变量会成为全局变量,容易导致问题。 可以在js代码的第一行写上’use strict’;来启用严格模式,变量定义时未采用var会报错

2.语句块,数字运算符(除0比较特殊),布尔运算与java基本一致

3.数字为number类型,除常见数字类型外还有NaN和Infinity(除0结果为无限大)

4.比较运算符始终使用===,在数据类型不一致时返回false,特例为NaN只能通过isNaN(NaN)来比较,另外浮点数的比较要比较两者差值是否小于一定阈值

5.null和undefined: 空和未定义,基本一致。 通常我们使用null,仅在判断函数的参数是否有传递的情况下使用undefined

6.数组与java类似,其成员可以为任意类型。数组提供了一系列的方法,如sort, slice, indexOf ,reverse, join。 需要注意的是如果索引超出范围,则返回undefined,同时数组会自动扩容

7.对象为大括号包括的键值对,其中key为字符串,引号可以省略(如果key不符合变量命名则不可以省略),value为任意类型,如
var person = {
name: ‘bob’,
age: 20,
hasCar: fasle,
other: NaN,
another: undefined
}
访问变量有两种方式 person.name或者person[‘name’]。
可以通过赋值任意添加属性,如person.sex=man; 也可以通过delete关键字删除属性如delete person.age;
判断对象是否有某属性(包括继承的属性),‘age’ in person;
判断对象是否有某非继承的属性,person.hasOwnProperty(‘age’);

8.字符串:语法包括转义与java类似,其中可以使用\x开头标识ascll码,也可以用\u开头标识unicode码。 另外es6新增特性多行字符串,可以不用加换行,``, 另外还有模板字符串,即多行字符串中可以使用${variable}
字符串有一个只读number类型属性s.length;

9.条件判断if else与java一致,需要注意的是js中null, 0, undefined, ‘’,NaN均为false,其余一律为true

10.循环与java基本一致 for, for…in, while, do-while

11.es6引入Map和Set,以及iterable类型,其中Array,Map和Set均为iterable,可以通过for-of来遍历

12.普通函数的定义
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
上面abs(x)为一个函数对象,abs为指向该函数的变量。
函数的另外一种定义方式为
var abs = function (x) {…};
此处变量abs指向一个匿名函数。

13.函数的调用
函数调用允许传入任意数量的参数,不影响函数调用。必要时可以通过如下代码来检查参数类型

if (typeof x != 'number') {
    throw 'not a number!';
}

在函数内部可以使用关键字arguments来获取所有入参,类似于Array,使用arguments[0]来获取首个入参,其余类似。即使函数定义时没有入参,调用时一样可以通过arguments获取到。
当定义函数时设计某个参数为可选参数时,可以通过arguments.length来判断入参数量,然后判断是否要对入参进行移位。

14.rest参数
es6中引入rest参数,可以理解为其余参数,只能用在末尾

function abs(a, b, ...rest) {
    console.log(rest); // 打印Array,可能为空数组,不会是undefined
}

15.函数变量作用域
var声明的函数变量作用域为函数内部,由于函数可以嵌套,内部函数可以使用外部函数的变量,内部函数会覆盖外部函数的同名变量。

16.变量提升
函数中所有var定义的变量会优化为在顶部声明的变量,因此在实际编码时,最好遵循原则:在函数顶部声明所有会用到的内部变量。

17.全局作用域
不在任何函数中定义的变量拥有全局作用域,实际上它会绑定为window对象的一个属性。我们平时使用到的alert函数也是window中定义的函数。

18.命名空间
由于全局变量会绑定到window中,容易引起冲突,所以实际操作中通常使用如下方式将全局变量放入唯一的命名空间,JQuery underscore都是这么做的。

var MYAPP={}; // 定义一个对象
MYAPP.name = 'myapp';
MYAPP.foo = function (x) {
    return x +1;
};

19.let和const
var的作用域实际上为函数内部,即使在for语句内部定义的语句,在for语句外一样可以引用。
es6引入块作用域,let修饰的变量仅作用于块,比如for语句内部。同时es6引入const关键字,用于声明一个常量,同样为块作用域。

20.解构赋值
es6中可以通过解构赋值同时对一组变量进行赋值,比如

var [x, y, z] = ['Hello', 'JavaScript', 'Nice'];

也可以使用解构赋值,直接获取对象的指定属性,比如

let {name, age, passport} = person;

必要时可能需要用小括号括起来避免js引擎将{}当作了块处理导致报错。

如果使用的变量名和属性名不一致,可以使用如下的语法获取,同时针对未获取到的属性可以设置默认值,不再是undefined

let {name, password:id=1} = person; // password为person的属性

注意上面的语句中password不是变量,引用会报错

21.方法
在一个对象中绑定函数,称该函数为这个对象的方法,比如

var xiaoming = {
    name: 'xiaoming',
    age: function () {
       var y = new Date().getFullYear();
       return y - this.birth;
    }
}

上述定义中age即为对象的方法,调用方式为xiaoming.age()
方法中的this代表当前对象,在对象中或者方法内定义的内部函数中的this指向window或者undefined

22.函数的apply和call方法
函数本身提供了apply和call方法用来指定this指向哪个对象,区别是传参方式不同而已,示例如下

Math.max.apply(null, [3, 5, 4]); // 传入this和参数列表
Math.max.call(null, 3, 5, 4); //传入this和各个参数

23.装饰器
利用函数的apply方法,我们可以动态改变函数行为,比如可以先用一个变量保存原函数,然后修改原函数,必要时可以在其中调用原函数,比如修改window的parseInt方法

var count = 0;
var oldParseInt = parseInt;
window.parseInt = function () {
    count++;
    return oldParseInt.apply(null, arguments); //调用原方法
}

24.高阶函数Higher-order function
高阶函数就是接收函数作为参数的函数。常见的比如Array的map和reduce,它们都可以接收一个函数作为参数。
在调用map等函数时一定需要注意函数的定义,比如map函数的定义是传入3个参数到入参函数中,结果可能会与预期不符。

25.闭包
函数的返回值为函数,而且返回的内部函数能够访问外部函数的参数和变量,这种程序结构成为闭包Closure。
示例代码

function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce(function (x,y) {
            return x + y;
        }
    }
    return var;
}

在上述代码中传入数组后lazy_sum返回的是一个函数,而且该返回的函数保存了我们传入的数组参数,调用返回的函数才会得到计算结果。
返回闭包时需要牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量,会产生无法预期的结果。

如果一定要引用循环变量,可以创建一个匿名函数并立刻执行,同时返回一个闭包,这样可以实现返回的函数引用的循环变量不再受影响。

function count() {
    var arr = [];
    for (var i = 1; i <= 3; i++) {
        arr.push((function (n) {
            return function () {
                return n * n;
            }
        })(i))
    }
    return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
console.log(f3()); // 9

在上面的例子中

(function (n) {
            return function () {
                return n * n;
            }
        })(i)

代表一个立即执行的匿名函数,该函数返回一个闭包,引用了入参n,不再受循环变量的影响。

26.箭头函数
es6新增函数,箭头函数,与匿名函数基本一致,语法形式如下:

(x, y) => x + y
// 或者带大括号
(x, y) => {return x + y;}

等价于

function (x, y) {
    return x + y;
}

在箭头函数与匿名函数的区别在于this的指向,箭头函数中this总是指向外层调用者,同时在用call或者apply调用箭头函数时,无法对this进行绑定,也就是第一个参数会被忽略。

27.generator
generator是es6引入新的数据类型,类似函数,但是可以返回多次。
示例如下

function* foo(x) {
   yield x + 1;
   yield x + 2;
   return x + 3;
}

调用方式如下

// 生成一个generator
var f = foo(1);

// 第一种遍历方式
for (var a of f) {
    console.log(a);
}

// 第二种遍历方式,返回对象
f.next(); // {value: 2, done: false}

28.对象
JavaScript中一切都是对象,使用typeof可以获取对象的类型,常见对象的类型有number,string,boolean,function,undefined,object,注意null,Array和通常意义上的对象的类型都是object。

typeof 123; // 'number'
typeof [1,2,3]; // 'object'

判断是否为Array要通过Array.isArray(arr);

29.json序列化与反序列化

var xiaoming = {name: 'xiaoming'};
var s = JSON.stringify(xiaoming); // 序列化
var o = JSON.parse(s); // 反序列化

也可以对xiaoming添加toJSON()方法,直接返回序列化后的数据

30.原型继承
JavaScript中每个创建的对象都会设置一个原型,指向它的原型对象。
当我们用obj.xxx访问一个对象的属性时,js引擎会先在当前对象上查找该属性,找不到的时候就到原型对象上查找,还找不到的话会继续上溯一直到Object.prototype对象中查找,最后还没找到就返回undefined。

函数也是一个对象,它的原型链如下

foo --> Function.prototype --> Object.prototype --> null

可以使用如下的构造函数来创建对象,约定函数名大写开头

function Student (props) {
    this.name = props.name || '匿名';
    this.grade = props.grade || 1;
}
// 为所有Student对象添加hello方法,方法设置在原型对象上
Student.prototype.hello = function () {
    alert('Hello " + this.name  + "!");
}

在构造函数的基础上实现原型继承的方式如下

  • 定义新的构造函数,并在内部用call()调用希望继承的构造函数,并绑定this
  • 借助中间函数F实现原型链继承
  • 在新构造函数的原型上添加新方法

node基础
node项目通过package.json配置, 使用npm或者yarn下载依赖,其中package.json中可以配置script然后通过npm run 'command’来执行对应的脚本,如果command为start则直接执行npm start即可。

CommonJs规范
在node项目中,每个js文件当做一个模块,模块名即为文件名,它们内部使用的全局变量和函数名都互不冲突,可以通过module.exports指定导出内容

function greet(name) {
    console.log(s + ', ' + name + '!');
}
module.exports = greet;

可以采用require函数导入其它模块

var greet = require('./hello');  // greet即为hello.js中定义的greet函数

CommonJs的实现原理是用一个立即执行的匿名函数包装一个模块,这样原有的全局变量作用域就变成函数内部的局部变量。

简单熟悉es6

预期时间:1天
参考地址http://es6.ruanyifeng.com

1.let和const命令
顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。
es6中规定,var命令和function命令声明的全局变量,依旧是顶层对象的属性,let,const声明的全局变量不属于顶层对象的属性。

2.解构赋值
es6允许按照一定模式,从数组和对象中提取值,对一组变量进行赋值。 可以从数组,对象,字符串,数值和布尔值中提取值。对于等号右边不是对象的会先转化为对象。

函数参数传值也可以采用解构赋值,如

function add(x, y) {
    return x + y;
}

add([1,2]);

解构赋值典型用途,对象返回多个值,提取json对象中数据,函数的默认参数

3.字符串扩展
字符串可以使用for…of遍历,传统的for循环无法识别大于0xffff的码点

let text = String.fromCodePoint(0x20BB7);

for(let i of text) {
    console.log(i); // "?"
}

字符串补全,padStart和padEnd,分别用于头部补全和尾部补全。
padStart常用于补全指定位数,比如

'1'.padStart(10, '0');  不足10位头部补0

另一种用途就是提示字符串格式

'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"

模板字符串,用反引号``标识,常用于定义多行字符串,在其中可以嵌入变量${}。 大括号内部可以是变量,表达式,对象属性,函数调用等,最后都会被转化为字符串。

标签模板,函数名后接模板字符串``作为参数

4.函数的扩展
函数参数支持设置默认参数,如

function add(x, y = 10) {
    return x + y;
}

函数参数的默认值可以配合函数参数的解构赋值使用,如下面的代码中,函数参数为一个对象,在函数体中可以直接使用解构的变量及其默认值,注意考虑到函数调用时没有入参时x,y不会生成导致报错,所以入参设置了默认参数空对象

function foo({x, y = 5} = {}) {
    console.log(x, y);
}
foo();

箭头函数,注意this始终指向调用方。

双冒号运算符,即函数绑定运算符,作用与call,apply,bind类似。左边是一个对象,右边是一个函数,该运算符会自动将左边的this对象绑定到右边的函数上面。

foo::bar;
// 等同于
bar.bind(foo);

// 如果双冒号左边为空,右边为一个对象的方法,则等于将该方法绑定到该对象上面
let log = ::console.log;
// 等同于
let log = console.log.bind(console);

5.数组的扩展
扩展运算符,类似rest参数的逆运算,将一个数组(可以是表达式返回的数组)转为用逗号分隔的参数序列,主要用于函数调用。

const numbers = [1,2];
add(...numbers);

在涉及到一个字符占用4个字节的情况下,建议使用扩展运算符确保结果无误,比如

[...str].reverse().join(' ');
[...str].length;

任何实现了Iterator接口的对象都可以使用扩展运算符转为真正的数组,比如map、generator。

Array.from可以将一个Array-like对象或者iterable对象转化为数组,其本质是支持length属性的对象。

Array.of用于将一组值转换为数组,Array的默认构造方法中由于存在长度参数,行为难以理解。

6.对象的扩展
属性的简洁表示法:es6允许直接写入变量和函数作为对象的属性和方法。如

const foo = 'bar';
const baz = {foo};
// 等同于
const baz = {foo: 'bar'};

对象方法类似

函数的返回值也可以使用属性的简洁表示法,可以用于CommonJs模块输出一组变量。

module.exports = {x, y, z};

属性名表达式:用表达式作为属性名,需要将表达式放在方括号中,如

obj['a' + 'bc'] = 123;

需要注意的是属性表达式中属性名始终会转化为字符串。

Object.is(a,b),判断两个对象是否相等,类似于===,其中+0与-0不相等,NaN等于自身。

Object.assign(target, source1, source2),复制source到target,浅拷贝,后面的source会覆盖前面source的同名属性,其中数组也会被视为对象。

属性的可枚举性:对象属性有一个描述对象Desciptor,用于控制该属性的行为,Descriptor有一个属性enumerable,false表示某些操作会忽略当前属性。比如
for…in Object.keys() JSON.stringify() Object.assign()

原型链设置

Object.setPrototypeOf(obj, prototype); // 设置obj的prototype对象
Object.getPrototypeOf(obj); // 返回obj的prototype对象

super关键字:用在对象方法中,指向原型对象,类似Object.getPrototypeOf(this)…

7.Symbol
Symbol是一种类似于字符串的新数据类型,它可以作为属性名。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不与其它属性名产生冲突。
Symbol函数可以接收字符串或者对象作为参数,便于在控制台输出时进行区分。

let s = Symbol('a');

8.Set和Map
Set:不包含重复元素的集合
Map:键值对的集合

9.Promise
一个容器,包含某个未来才会结束的事件的结果。与其它语言中Promise类似。
用法参考

let promise = new Promise(function(resolve, reject) {
    console.log('Promise');
    resolve();
});

promise.then(function() {
    console.log('resolved.');
});

console.log('Hi!');

react框架

预期时间:2天
参照 https://reactjs.org/tutorial/tutorial.html

react native

1.项目结构

.
├── __tests__
├── android
├── app.json
├── appConfig.json
├── babel.config.js
├── bundle
├── index.android.js
├── index.js
├── ios
├── js
├── metro.config.js
├── node_modules
├── package-lock.json
└── package.json

我们重点关注package.json中的配置,其中scripts表示我们可以执行的脚本,如react-native bundle_android,dependencies表示我们项目中使用到的依赖。
2.调试方式
调试主要设置两个地方,原生端和rn端
3.常用第三方库
需要注意原生端的引用方式

 类似资料: