js学习(二)

web存储

通过监听onstorage事件监听web存储事件

本地存储

  • 全局属性localStorage访问,返回storage对象,用键值对形式存储数据
  • 通过清除浏览器数据清除本地存储中的数据,即存储时间为永久

会话存储

  • 全局属性sessionStorage访问,返回storage对象,用键值对形式存储数据
  • 生命周期为窗口的存活周期

获取地理位置

  • 第一个参数是获取地理位置成功的回调函数(唯一一个参数为坐标和更新时间对象)
  • 第二个参数是获取地理位置失败的回调函数(唯一一个参数是返回的错误码和错误原因的对象)
  • 第三个参数为请求地理位置的参数
  • 返回监视器的id,通过调用navigator.geolocation.clearWatch清除监视器
  • 第一个参数是获取地理位置成功的回调函数(唯一一个参数为坐标和更新时间对象)
  • 第二个参数是获取地理位置失败的回调函数(唯一一个参数是返回的错误码和错误原因的对象)
  • 第三个参数为请求地理位置的参数

参考文档:使用地理位置定位

react16新生命周期

新生命周期

创建组件时的生命周期

新版react生命周期

创建过程

  • parent constructor
  • parent getDerivedStateFromProps
  • parent render
  • Child constructor
  • Child getDerivedStateFromProps
  • Child render
  • Child componentDidMount
  • parent componentDidMount

说明

  • getDerivedStateFromProps的参数为nextProps, prevState
  • 这个方法将会在组件实例化和接收到新的props的时候被调用. 而componentWillReceiveProps只会在接收到新的props的时候才会调用
  • 当组件实例化的时候,这个方法替代了componentWillMount(),而当接收到新的props时,该方法替代了componentWillReceiveProps()componentWillUpdate()
  • 这个方法是个static的方法,因此使用this在这个方法中并不指代本实例组件,如果打印出来会发现这个this在这个方法中是null. 而且这个方法会返回值. 当需要更新状态时,需要返回一个object,如果不需要任何更新,则返回null即可
  • 如果由于父组件的原因导致该组件重新渲染,这个方法也会被调用,如果只想要处理更新的话,最好加上判断条件if (nextProp !== prevProp).另外,虽然this.setState()也会导致组件重新渲染,但并不会导致这个方法的重新调用.

正式版的context API

  • 使用context

    1
    2
    3
    4
    5
    6
    import React, { createContext } from 'react';

    const ctx = createContext({
    msg: 'hello world!',
    });
    const { Provider, Consumer } = ctx;
  • Provider组件用于将context数据传给该组件树下的所有组件value属性是context的内容

  • 要使用context的数据,我们需要使用Consumer组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
      // 数据提供者
    class App extends React.Component {
    render() {
    return (
    <div>
    <Provider value={{ msg: 'hello react!' }}>
    <ChildComponent1 />
    <ChildComponent2 />
    </Provider>
    <ChildComponent3 />
    </div>
    );
    }
    }
    // 数据消费者
    // 函数式
    const ChildComponent1 = () => (
    <Consumer>
    {context => <p>{context.msg}</p>}
    </Consumer>
    );
    // 类
    class ChildComponent2 extends React.Component {
    render() {
    return (
    <Consumer>
    {context => <p>{context.msg}</p>}
    </Consumer>
    );
    }
    }
    // 类
    class ChildComponent3 extends React.Component {
    render() {
    return (
    <Consumer>
    {context => <p>{context.msg}</p>}
    </Consumer>
    );
    }
    }
    /*
    Consumer下不能写其它的东西,比如<Consumer>Message:{context => <p>{context.msg}</p>}</Consumer> 只能是一个函数 返回需要渲染的组件
    */
  • 既然context的内容是写在Provider的value中,如果没有将Consumer作为Provider的子组件, 如上面的ChildComponent3,那么Consumer将使用创建context时的参数作为context

  • Provider 和 Consumer 必须来自同一次 React.createContext 调用。也就是说 NameContext.Provider 和 AgeContext.Consumer 是无法搭配使用的。

  • React.createContext 方法接收一个默认值作为参数。当 Consumer 外层没有对应的 Provider 时就会使用该默认值。

  • Provider 组件的 value prop 值发生变更时,其内部组件树中对应的 Consumer 组件会接收到新值并重新执行 children 函数。此过程不受 shouldComponentUpdete 方法的影响。

  • Provider 组件利用 Object.is 检测 value prop 的值是否有更新。注意 Object.is 和 === 的行为不完全相同。

  • Consumer 组件接收一个函数作为 children prop 并利用该函数的返回值生成组件树的模式被称为 Render Props 模式。

参考:React生命周期简单分析

js和react学习(一)

import和link的区别

  • link属于XHTML标签,而@import完全是CSS提供的一种方式。link标签除了可以加载CSS外,还可以做很多其它的事情,比如定义RSS,定义rel连接属性等,@import就只能加载CSS了。此处注意浏览器的link的src为空时候时会导致页面加载次数增多。
  • 当一个页面被加载的时候(就是被浏览者浏览的时候),link引用的CSS会同时被加载,而@import引用的CSS 会等到页面全部被下载完再被加载。
  • 由于@import是CSS2.1提出的所以老的浏览器不支持,@import只有在IE5以上的才能识别,而link标签无此问题。
  • 当使用javascript控制dom去改变样式的时候,只能使用link标签,因为@import不是dom可以控制的。

内存泄漏

再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。

  • 意外的全局变量,使用一个未定义的变量隐式把其设置为了全局变量
  • 被遗忘的计时器或回调函数,在定时器或者回调函数中使用条件语句由于条件变化导致的语句不可达,进而造成数据使用的内存无法释放
  • 脱离 DOM 的引用,对dom树节点的变量引用导致移出dom节点后仍然有变量引用节点造成无法回收占用的内存
  • 闭包,匿名函数可以访问父级作用域的变量导致父级作用域的变量无法释放造成内存泄漏

函数柯里化

只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。

1
2
3
4
5
6
7
8
9
10
11
12
const addpp = (...argsa) => {
let sum = 0;
argsa.forEach(item => sum += item);
const temp = (...args) => {
args.forEach(item => sum += item);
return temp;
}
temp.toString = temp.valueOf = () => {
return sum;
}
return temp;
}

webpack核心

  • 入口(entry):指示 webpack应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
  • 输出(output):告诉 webpack 在哪里输出它所创建的bundles,以及如何命名这些文件,默认值为 ./dist。
  • loader:让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
  • 插件(plugins):打包优化和压缩,一直到重新定义环境中的变量。

MVC模式

  • M:核心的”数据层”(Model),也就是程序需要操作的数据或信息。
  • V:直接面向最终用户的”视图层”(View)。它是提供给用户的操作界面,是程序的外壳。
  • C:”控制层”(Controller),它负责根据用户从”视图层”输入的指令,选取”数据层”中的数据,然后对其进行相应的操作,产生最终结果。

Flux

Flux将一个应用分成四个部分
  • View: 视图层
  • Action(动作):视图层发出的消息(比如mouseClick)
  • Dispatcher(派发器):用来接收Actions、执行回调函数
  • Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面
Flux数据的”单向流动”
  • 用户访问 View
  • View 发出用户的 Action
  • Dispatcher 收到 Action,要求 Store 进行相应的更新
  • Store 更新后,发出一个”change”事件
  • View 收到”change”事件后,更新页面

堆栈的区别

  • 栈:后进先出,元素大小固定,保存js中的基本数据类型,Undefined、Null、Boolean、Number、String
  • 堆:内存中的一块区域,随机分配,保存大小不固定的数据类型,array、Object,但是在栈中保存存储地址

new操作符做的事情

  • 创建空对象
  • 设置原型链
  • 让function的this指向obj,并执行fn的函数体
  • 判断fn的返回值类型,如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象。

react中配置eslint和flow

react 中配置 eslint 和 flow

react 中配置 flow

  • npm install -g flow-bin flow-scripts全局安装flow
  • npm install babel-preset-flow flow-bin flow-scripts安装babel-preset-flow flow-bin flow-scripts相关包
  • 在根目录下的.babelrc文件中做flow相关的配置,配置文件如下:
1
2
3
4
5
"presets": [
"react",
"es2015",
"flow"
]
  • 在工程根目录下运行flow init初始化flow,产生一个.flowconfig文件,加入相关配置后的文件具体内容如下:
1
2
3
4
5
6
7
8
9
10
11
[ignore]
.*/node_modules/.*
[include]
./src/**/*.js
[libs]
./node_modules/.*
[lints]

[options]

[strict]
  • 在需要引入flow检查的文件的头部加入//@flow或者/*@flow*/对文件进行flow检查
  • 具体用法参考flow

react 中配置 eslint

  • npm install -g eslint命令全局安装eslint
  • npm install babel-eslint eslint-plugin-jsx-a11y eslint-plugin-react安装eslintreact插件
  • eslint --init初始化工程项目,按照提示给出答案,在项目根目录下产生.eslintrc.js文件
  • 在根目录下新建.eslintignore文件,在文件中添加需要忽略的文件和文件夹

js中的概念

闭包

1
2
3
4
5
function test(arg) {
return function() {
return arg;
}
}

类似于上述情况,函数虽然已经返回,但是仍然能够访问变量创建时的上下文的情况称为闭包

js继承

js中的prototype是一个指针

基础的父类

1
2
3
4
5
6
function Parent(name) {
this.name = name; // 会被实例共享但不会被修改
}
Parent.prototype = function () {
console.log('name ', this.name);
}

构造函数继承

1
2
3
4
5
6
7
function Child(name, sex) {
Parent.call(this, name);
this.sex = sex;
}
Child.prototype.say = function () {
console.log('My name is ', this.name);
}

通过构造函数相当于重写了整个对象,但是在继承的过程中对于父类中的方法却不需要重写

原型链继承

1
2
3
4
5
6
7
function Child(name, sex) {
this.sex = sex;
}
Child.prototype = new Parent();
Child.prototype.say = function () {
console.log('My name is ', this.name);
}

通过原型链继承的方法共享了整个父类中的方法和属性,不同的实例会共享相同的属性和方法,但是实例对属性的修改是在子类中动态的创建了新属性,其它实例仍然能够访问原型中的属性和方法,并且原型链无法复用父类的构造函数

组合继承(构造函数和原型链继承混合使用)

1
2
3
4
5
6
7
8
function Child(name, sex) {
Parent.call(this, name);
this.sex = sex;
}
Child.prototype = new Parent();
Child.prototype.say = function () {
console.log('My name is ', this.name);
}

通过构造函数复用父类的构造函数,通过原型链的形式继承父类的方法

deploy与github帐户关联

设置git的usernameemail

  • git config --global user.name "username"设置用户名
  • git config --global user.email "email"设置邮箱

生成公钥和密钥

  • ssh-keygen -t rsa -C "email"生成公钥和密钥,一路回车即可
  • 检查C:\Users\Administrator\.ssh\是否存在id_rsaid_rsa.pub两个文件

添加公钥和KEYssh-agent

  • eval "$(ssh-agent -s)"添加密钥到ssh-agent
  • ssh-add ~/.ssh/id_rsa添加生成的SSH keyssh-agent

把公钥添加到github

测试是否成功

  • ssh -T git@github.com测试是否成功,成功后会在返回的Hi后返回你的用户名

npm和webpack搭建react开发环境

npm环境搭建

  • nodejs安装参考Nnodejs官网
  • 安装完毕后用npm --version查看nodejs是否安装成功

工程初始化

  • npm init初始化工程,在根目录产生一个package.json文件

webpack安装

  • npm install webpack webpack-cli webpack-dev-server webpack-merge安装webpack和其相关的包,安装完毕后会在package.json文件的dependencies选项中看到刚刚安装的包

react安装

  • npm install react react-dom安装react和其相关的包,安装完毕后会在package.json文件的dependencies选项中看到刚刚安装的包
  • 由于react使用ES6语法大多数无法支持,所以还需用npm install babel babel-core babel-loader babel-preset-env babel-preset-es2015 babel-preset-react安装babel和其相关的包把ES6语法转化,安装完毕后会在package.json文件的dependencies选项中看到刚刚安装的包
  • 由于react使用ES6语法大多数无法在class中支持箭头,所以还需用npm install babel-preset-stage-0 babel-plugin-transform-class-properties安装相关的包把语法转化,安装完毕后会在package.json文件的dependencies选项中看到刚刚安装的包

hello word的实现

  • npm install uglifyjs-webpack-plugin html-webpack-plugin clean-webpack-plugin安装其它依赖包
  • 在根目录下新建webpack.config.js文件作为webpack的基础通用配置,配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');

module.exports = {
entry: './src/index.js',
plugins: [
new CleanWebpackPlugin(['dist']), // 清理数据
new HtmlWebpackPlugin({ // 自动打包数据
title: '测试',
template: './src/index.html', // html文件模板
}),
],
output: {
filename: '[name].[hash].bundle.js', // 输出文件名称
path: path.resolve(__dirname, 'dist') // 输出文件路径
},
module: {
rules: [
{
test: /\.(js|jsx)$/, //配置要处理的文件格式,一般使用正则表达式匹配
use: ['babel-loader'], //使用的加载器名称
exclude: /node_modules/
}
],
}
};
  • 在根目录下新建webpack.dev.js文件作为webpack的开发者模式配置,配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const merge = require('webpack-merge');
const webpack = require('webpack');
const config = require('./webpack.config.js');

module.exports = merge(config, {
devtool: 'inline-source-map', // 开发工具
plugins: [
new webpack.HotModuleReplacementPlugin(), // 热替换
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development') // 定义开发者模式
})
],
devServer: { // 开发模式下服务器配置
contentBase: './dist', // 编译后文件路径
hot: true, // 是否开启热替换
host: 'localhost' // 主机
}
});
  • 在根目录下新建webpack.prod.js文件作为webpack的生产环境配置,配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');// 精简输出
const config = require('./webpack.config.js');

module.exports = merge(config, {
plugins: [
new UglifyJSPlugin({
sourceMap: true // 调试
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production') // 定义生产模式
})
]
});
  • 在根目录下新建.babelrc文件作为react的开发环境下babel的配置,配置文件如下:
1
2
3
4
5
6
7
8
{
"presets": [
"react",
"stage-0",
"es2015"
],
"plugins": ["transform-class-properties"]
}
  • 在根目录下的packge.json中加入命令,配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
"name": "react-exercise",
"version": "0.0.0",
"description": "react exercise",
"main": "index.js",
"scripts": {
"test": "echo \"Project completed\"",
"build": "webpack --config webpack.prod.js",
"start": "webpack-dev-server --open --config webpack.dev.js"
},
"keywords": [
"react-exercise"
],
"author": "xxx",
"license": "ISC",
"dependencies": {
"babel": "^6.23.0",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-env": "^1.6.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"clean-webpack-plugin": "^0.1.19",
"html-webpack-plugin": "^3.0.6",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"uglifyjs-webpack-plugin": "^1.2.3",
"webpack": "^4.1.1",
"webpack-cli": "^2.0.12",
"webpack-dev-server": "^3.1.1",
"webpack-merge": "^4.1.2"
}
}
  • 在根目录下新建src文件夹,并在文件夹下新建index.jsindex.htmlcomponentTest.js文件

    • index.jswebpack的入口文件,文件内容如下:
      1
      2
      3
      4
      5
      6
      7
      import React, { Component } from 'react';
      import ReactDOM from 'react-dom';
      import ComponentTest from './componentTest';
      ReactDOM.render(
      <ComponentTest />,
      document.getElementById('root')
      );
    • index.htmlwebpack的打包模板文件,文件内容如下:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      <!doctype html>
      <html>
      <head>
      <title>Getting Started</title>
      </head>
      <body>
      <div id="root"></div>
      </body>
      </html>
    • componentTest.jsreact的一个组件,文件内容如下:
      1
      2
      3
      4
      5
      import React from 'react';
      const componentTest = () => (
      <h1>hello react</h1>
      );
      export default componentTest;
  • 在命令行中输入npm start即可运行项目,在打开的http://localhost:8080/网页中看到输出的hello react

总结

  • 文件目录结构
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    |---src
    | |---index.html(html模板文件)
    | |---index.js(webpack入口文件)
    | |---componentTest.js(React测试组件文件)
    |---.babelrc(babel配置文件)
    |---package-lock.json(自动生成的文件)
    |---package.json(依赖包文件)
    |---webpack.config.js(webpack公共配置文件)
    |---webpack.dev.js(开发环境下的webpack配置文件)
    |---webpack.prod.js(生产环境下的webpack配置文件)