一、ES6常用语法 & 新特性
二、Flex布局 & 样式
三、一般组件的使用
ES6常用语法 & 新特性
-
ECMAScript6(简称ES6)是 JavaScript 语言的下一代标准。在2015年6月正式发布,所以又称ES2015。(Babel:ES6->ES5转码器)
let, const, class, extends, super, arrow functions, template string, destructuring assignment, default, rest arguments, promise, generators, proxy, export, import
-
let、const、var
function test() {
if (bool) {
var test = 'hello'
} else {
console.log(test) //undefined
}
//undefined
}
相当于:
function test() {
var test //变量提升
if (bool) {
test = 'hello'
} else {
console.log(test) //undefined
}
//undefined
}
变量提升带来了较大的迷惑性,ES6提供了块作用域let、const
- 问题:父块中已有有一个同名变量,但是函数内部也需要用同名变量?
var name = 'Red'
while (true) {
let name = 'Blue'
console.log(name) //Blue
}
console.log(name) //Red
块级作用域指在一个函数内部、或一个代码块内部,即{}大括号内的代码块即为let和const的作用域
console.log(num); //num is not defined
let num = 3;
在某个作用域中,在let声明之前调用了let声明的变量,导致的问题就是由于Temporal Dead Zone(TDZ)的存在
变量会在我们进入块作用域时就会创建,TDZ也是在这时候创建的,它保证该变量不许被访问,只有在代码运行到let声明所在位置时,这时候TDZ才会消失,访问限制才会取消,变量才可以被访问
const
1.const声明的变量在声明时必须赋值,否则会报错:SyntaxError, missing initializer
2.const声明的变量不能再被赋予别的值。在严格模式下,试图改变const声明的变量会直接报错;在非严格模式下,改变被静默忽略
3.通过const声明的变量值并非不可改变。使用const只是意味着,变量将始终指向相同的对象或初始的值(引用是不可变的,但是值并非不可变)
下面的例子说明,虽然people的指向不可变,但是数组本身是可以被修改的。
const people = ['China', 'USA']
people.push('England')
console.log(people) //['China', 'USA', 'England']
class、extends、super
JS本身就是面向对象的,ES6中提供的类实际上只是JS原型模式的包装。引入了class(类)的概念。新的class写法让对象原型的写法更加清晰、更像面向对象编程的语法,也更加通俗易懂
class Human {
constructor(name) { //构造方法,this关键字则代表实例对象
this.name = name;
//constructor内定义的方法和属性是实例对象自己的
//而constructor外定义的方法和属性则是所有实例对象可以共享的
}
sleep() {
console.log(this.name + " is sleeping");
}
}
let man = new Human("James");
man.sleep(); //James is sleeping
class Boy extends Human {
//通过extends关键字实现继承,继承了Human类的所有属性和方法
constructor(name, age) {
//super关键字,指代父类的实例(即父类的this对象)
super()
this.name = name;
this.age = age;
}
info() {
console.log(this.name + 'is ' + this.age + 'years old');
}
}
let boy = new Boy('Love', '18');
boy.sleep(); //Love is sleeping
boy.info(); //Love is 18 years old
子类必须在constructor方法中调用super方法,否则新建实例时会报错
这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
ES6的继承机制,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。
arrow functions
JS中声明的普通函数,一般有函数名,一系列参数和函数体,如下:
function name(parameters) {
// function body
}
普通匿名函数则没有函数名,匿名函数通常会被赋值给一个变量/属性,有时候还会被直接调用:
var example = function (parameters) {
// function body
}
ES6提供了一种写匿名函数的新方法,即箭头函数。箭头函数不需要使用function关键字,其参数和函数体之间以=>相连接:
var example = (parameters) => {
// function body
}
箭头函数与匿名函数的区别:
1.箭头函数不能被直接命名,不过允许它们赋值给一个变量;
2.箭头函数不能用做构造函数,你不能对箭头函数使用new关键字;
3.箭头函数也没有prototype属性;
4.箭头函数绑定了词法作用域,不会修改this的指向
class Human {
constructor(name) {
this.name = name;
}
sleep() {
setTimeout(function () {
console.log(this.name + " is sleeping");
}, 1000)
}
}
let man = new Human("James");
man.sleep(); // is sleeping
//将this传给self,再用self来指代this
sleep() {
var self = this;
setTimeout(function () {
console.log(self.name + " is sleeping");
}, 1000)
}
//或bind(this)
sleep() {
setTimeout(function () {
console.log(self.name + " is sleeping")
}.bind(this), 1000)
}
使用箭头函数
词法作用域:箭头函数的函数体内使用的this,arguments,super等都指向包含箭头函数的上下文,箭头函数本身不产生新的上下文。原因是箭头函数根本没有自己的this,它的this是继承外面的,因此内部的this就是外层代码块的this。
var example = (parameters) => {
// function body
}
当只有一个参数时,我们可以省略箭头函数参数两侧的括号:
var double = value => {
return value * 2
}
对只有单行表达式且,该表达式的值为返回值的箭头函数来说,表征函数体的{},可以省略,return关键字可以省略,会静默返回该单一表达式的值
var double = (value) => value * 2
合并使用
var double = value => value * 2
注意!
箭头函数返回值为一个对象时,你需要用小括号括起你想返回的对象。否则,浏览器会把对象的{}解析为箭头函数函数体的开始和结束标记。正确的使用形式
var objectFactory = () => ({ modular: 'es6' })
template string
模板字符串:ES6中允许使用反引号`来创建字符串,此种方法创建的字符串里面可以包含由{vraible}
let num = Math.random();
console.log(` num is ${num}`); //num is xx
模板字符串中所有的空格、新行、缩进,都会原样输出在生成的字符串中
destructuring assignment
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
1.交换变量的值,不再需要中间变量
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); //2 1
2.提取JSON数据
let jsonData = {
id: 1,
title: "OK",
data: [5, 6]
};
let {id, title, data:number} = jsonData;
console.log(id, title, number); //1, "OK", [5, 6]
3.函数参数的定义
//参数是一组有次序的值
function f([x, y, z]) {
...
}
f([1, 2, 3]);
//参数是一组无次序的值
function f({x, y, z}) {
...
}
f({z: 3, y: 2, x: 1});
default默认值
default默认值可以在定义函数的时候指定参数的默认值,而不用像以前那样通过逻辑或操作符来达到目的了。
//传统指定默认参数
function say1(name) {
var name = name || 'James';
console.log( 'Hello ' + name );
}
//ES6默认参数
function say2(name='Love') {
console.log(`Hello ${name}`);
}
say1(); //Hello James
say1('JR'); //Hello JR
say2(); //Hello Love
say2('TT'); //Hello TT
rest参数
1.rest参数只包括那些没有给出名称的参数;
2.rest参数是Array的实例,可以直接应用sort, map, forEach, pop等方法;
3.rest参数之后不能再有其它参数(即,只能是最后一个参数);
4.函数的length属性,不包括rest参数;
function fn(x, y, ...rest){
console.log(rest)
}
fn(1, "cat", "dog", 2); //["dog", 2]
console.log(fn.length); //2
promise
在promise之前代码过多的回调或者嵌套,可读性差、耦合度高、扩展性低。通过Promise机制,扁平化的代码机构,大大提高了代码可读性;用同步编程的方式来编写异步代码,保存线性的代码逻辑,极大的降低了代码耦合性而提高了程序的可扩展性。
即用同步的方式去写异步代码。Promise/A+规范, 规定Promise对象是一个有限状态机。它三个状态:
pending(执行中)
Resolved(已完成)
Rejected(已失败)
其中pending为初始状态,Resolved和rejected为结束状态(表示promise的生命周期已结束)
let val = 1;
//假设step1, step2, step3都是数据库的异步操作
//每个步骤都有对应的失败和成功处理回调
//step1、step2、step3必须按顺序执行
function step1(resolve, reject) {
console.log('步骤一:执行');
if (val >= 1) {
resolve('Hello I am No.1');
} else if (val === 0) {
reject(val);
}
}
function step2(resolve, reject) {
console.log('步骤二:执行');
if (val === 1) {
resolve('Hello I am No.2');
} else if (val === 0) {
reject(val);
}
}
function step3(resolve, reject) {
console.log('步骤三:执行');
if (val === 1) {
resolve('Hello I am No.3');
} else if (val === 0) {
reject(val);
}
}
new Promise(step1).then(function(val){
console.info(val);
return new Promise(step2);
}).then(function(val){
console.info(val);
return new Promise(step3);
}).then(function(val){
console.info(val);
return val;
}).then(function(val){
console.info(val);
return val;
});
// 执行之后将会打印
步骤一:执行
Hello I am No.1
步骤二:执行
Hello I am No.2
步骤三:执行
Hello I am No.3
Hello I am No.3
关键点:
在Promise定义时,函数已经执行了;Promise构造函数只接受一个参数,即带有异步逻辑的函数。这个函数在new Promise 时已经执行了。只不过在没有调用then之前不会resolve或reject。
在then方法中通常传递两个参数,一个resolve函数,一个reject函数。reject就是出错的时候运行的函数。resolve 函数必须返回一个值才能把链式调用进行下去。
1.resolve返回一个新Promise:返回一个新Promise之后再调用的then就是新Promise中的逻辑了。
2.resolve 返回一个值:返回一个值会传递到下一个then的resolve方法参数中
generators
generator函数跟普通函数的写法有非常大的区别:
1.function关键字与函数名之间有一个*
2.函数体内部使用yield语句,定义不同的内部状态
function* f() {
yield 'a';
yield 'b';
yield 'c';
return 'ending';
}
let fn = f();
console.log(fn.next()); // { value: 'a', done: false }
console.log(fn.next()); // { value: 'b', done: false }
console.log(fn.next()); // { value: 'c', done: false }
console.log(fn.next()); // { value: 'ending', done: true }
异步操作的同步化写法
generator函数的暂停执行的效果,意味着可以把异步操作写在yield语句里面,等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操作可以放在yield语句下面,反正要等到调用next方法时再执行。所以,generator函数的一个重要实际意义就是用来处理异步操作,改写回调函数
proxy代理
proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。让我们对一个对象有了很强的追踪能力,同时在数据绑定方面也很有用处。
//定义被监听的目标对象
let man = { name: 'James', age: 18 };
//定义处理程序
let handle = {
set(receiver, property, value) {
console.log(property, 'is changed to', value);
receiver[property] = value;
}
};
//创建代理以进行侦听
man = new Proxy(man, handle);
//做一些改动来触发代理
man.age = 22; //age is change to 22
man.name = "Love"; //name is change to Love
export、import
export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口;
import用于在一个模块中加载另一个含有export接口的模块。
导出一组对象。导出模块文件app.js:
class Human{
constructor(name) {
this.name = name;
}
sleep() {
console.log(this.name + " is sleeping");
}
}
function walk() {
console.log('i am walking');
}
function play() {
console.log('i am playing');
}
export { Human, walk }
模块导出了两个对象:Human类和walk函数,能被其他文件使用。而play函数没有导出,为此模块私有,不能被其他文件使用。
main.js导入app.js模块
import { Human, walk } from 'app.js';
Default导出
使用关键字default,可将对象标注为default对象导出。default关键字在每一个模块中只能使用一次。
... //类,函数等
export default App;
main.js导入app.js模块
import App from 'app.js';
Flex布局
Flex是Flexible Box的缩写,意为"弹性盒布局",用来为盒状模型提供最大的灵活性。采用Flex布局的元素,称为Flex container,它的所有子元素自动成为容器成员,称为Flex item。
image.png
1.容器默认存在两根轴:主轴(main axis)和交叉轴(cross axis);
2.主轴的开始位置叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end;
3.单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size;
4.项目默认沿主轴排列。
container属性
flexDirection enum('row','column')
flexDirection决定主轴的方向,如果取值为row,那么Main Axis为横轴;若取值为column,Main Axis则为竖轴。
flexWrap enum('wrap','nowrap')
justifyContent
image.pngalignItems
image.pngitem属性
flex enum(number)
定义剩余空间的比例。flex=0的项目占用空间仅为内容所需空间,flex=1的项目会占据其余所有空间。
alignSelf enum('auto','flex-start','flex-end','center','stretch')
alignSelf定义Item自己在Container中的对齐方式。
layout的其它属性
/node_modules/react-native/Libraries/StyleSheet/LayoutPropTypes.js
image.png
react的默认位置方式是relative,item是一个接一个排列下去的;absolute为绝对布局,一般会与left和top属性一起使用(有时候我们需要实现某些项目重叠起来,absolute属性就能发挥作用了)
布局尺寸说明
React Native的宽高是不需要带单位的,width,height,padding,margin的赋值都直接是数字的,当设定width:10,在iOS的话就是设置了10pt宽度,而在Android上面是10dp
样式说明
React Native没有实现css来渲染样式,而是使用JavaScript声明样式
1.它属性的名称和css上的不一样;
2.它支持的属性比较少;
3.它支持的属性取值也比较少
声明:
var styles = StyleSheet.create({
container: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
alignItems: 'center',
flex: 1,
backgroundColor: '#ffffff',
},
item: {
width: 75,
height: 75,
color: '#ffffff',
backgroundColor: '#666666',
margin: 10,
}
});
使用:
<View style={styles.container}>
<Text style={styles.item}>
1
</Text>
<Text style={styles.item}>
2
</Text>
</View>
网友评论