JavaScript 进阶营让前端飞

TypeScript学习笔记(一) + ( antd-table

2018-08-19  本文已影响464人  woow_wu7

安装

cnpm install typescripy -g

使用

在命令行上,运行TypeScript编译器:
输出结果为一个a.js文件,它包含了和输入文件中相同的JavsScript代码。


tsc a.ts          ---------------- 把a.ts文件编译成a.js文件

在vscode中自动编译

  1. 运行命令:tsc --init -------> 生成tsconfig.json文件
  2. 点击 任务---->运行任务--------->tsc:监视 - tsconfig.json

在tsconfig.json文件中:
outDir: 表示js文件的生成目录
比如:生成在根目录的js文件夹中 ------------> outDir: './js'

数据类型

  1. string
  2. number
  3. boolean
  4. 数组
    有两种方法可以定义数组:

(1)第一种,可以在元素类型后面接上 [],表示由此类型元素组成的一个数组


let list: number[] = [1, 2, 3];   -------------- 由number类型元素组成的数组

(2)第二种方式是使用数组泛型,Array<元素类型>:


let list: Array<number> = [1, 2, 3];

  1. 元组Tuple
    tuple:是元组的意思
    元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
// Declare a tuple type
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK

// Initialize it incorrectly
x = [10, 'hello']; // Error  ------------------- 不能交换位置,只能按顺序

6.枚举enum
enum类型是对JavaScript标准数据类型的一个补充。 像C#等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。

enum Color {Red = 1, Green, Blue} ---- 默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值。
let c: Color = Color.Green; ---------- 结果是2
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

alert(colorName);  // 显示'Green'因为上面代码里它的值是

7.Any
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量:

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
let list: any[] = [1, true, "free"];   -------------- 成员可以是任何类型

list[1] = 100;

let a: number | undefined

a=20;     --------------- true
a=undefined    ---------- true

8.Void ------------------------------ 一般用于定义方法没有返回值
某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void:


function warnUser(): void {        ------------------------------- 正确
    alert("This is my warning message");
}


function warnUser(): undefined {        -------------------------- 错误
    alert("This is my warning message");
}

function a(): number {             ------------------------------- 正确
  return 123;
}

let unusable: void = undefined;  ----------- viod类型的变量只能赋予 undefined和null

9.Null 和 Undefined
TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。 和 void相似,它们的本身的类型用处不是很大:

10.Never -----------------------------------------包含null和undefined
never类型表示的是那些永不存在的值的类型。 例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型保护所约束时。

never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使 any也不可以赋值给never。

类型断言

有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。

通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。

类型断言有两种形式。

let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;  ---------------- someValue一定是一个字符串
let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;

接口:

关键词: interface

interface LabelledValue {      ----------------- interface声明接口
  label: string; ------------------------------- 注意这里是分号,但LabelledValue是个对象
}

function printLabel(labelledObj: LabelledValue) { --- 参数是一个对象,必须有label属性,并且是个字符串
  console.log(labelledObj.label);
}

let myObj = {size: 10, label: "Size 10 Object"};  ---- 虽然可以传入size,但是在函数中调用时还是会报错
printLabel(myObj);





注意:
参数定义在外部,只要包含接口中的属性就可以,而直接写在调用函数的内部,则只能是接口中的属性个数
如果是printLabel({size: 10, label: "Size 10 Object"}); 报错 -------- 错
如果是printLabel({ label: "Size 10 Object"});  --------------------- 对



可选属性 ?

可选属性就是在接口对象中的属性后面加上?

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
  let newSquare = {color: "white", area: 100};
  if (config.clor) {
    // Error: Property 'clor' does not exist on type 'SquareConfig'
    newSquare.color = config.clor;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

let mySquare = createSquare({color: "black"});

访问修饰符

private表示私有,私有属性和方法只能在该类中使用,在 子类和实例对象中都不能使用

派生类

关键字:extends














(一) 在Table中,编辑每一行的值,当Antd-Modal-Form-FormItem-initialValue 表单的每项获得初始值后,改变其中某个input框的值,影响其他行的table-modal-form的input值

( Modal中内嵌Form表单的initialValue值不动态更新问题 )
( 编辑第一行的input,影响第二行的input )

{
  this.state.showModal ? <Modal></Modal> : null
}


false的时候,不挂载Modal
true的时候,挂载

https://blog.csdn.net/u013558749/article/details/79105531/














(二) react-intl 国际化

cnpm install react-intl --save
(1) addLocaleData
(2) IntlProvider ----- 包裹需要国际化的根组件 ( local属性,message属性 )
index.js根组件:


import{ addLocaleData, IntlProvider  } from 'react-intl'; --- 引入 addLocaleData 和 IntlProvider  




添加多种语言对应的文本,自己新建两个js文件或者json文件
import enus from './locales/en-us';
import zhcn from './locales/zh-cn';



载入语言环境数据
import enLocaleData from 'react-intl/locale-data/en'
import zhLocaleData from 'react-intl/locale-data/zh'
// addLocaleData(enLocaleData) //注册区域设置数据
// addLocaleData(zhLocaleData) //注册区域设置数据
addLocaleData([...enLocaleData, ...zhLocaleData])  ------------ 使用addLocalData载入语言环境数据




 <Provider store={store}>
     <IntlProvider   locale={'zh'} messages={zhcn} >    ------------- interProvider组件
            <BrowserRouter>
                ...
            </BrowserRouter>
        </IntlProvider>
    </Provider>
, document.getElementById('root'));

(3) injectIntl 和 FormattedMesssage

React Intl 提供一个API,injectIntl,可以把命令式格式化的 API 注入到任意组件的props中。然后可以在那个组件中通过this.props.intl直接去调用一些API和属性,

比如this.props.intl.locale的值就是当前语言了。

<FormattedMessage id="table.edit"/>



---------------


  定义:
  formatMessage = (...args) => {
    const {intl: {formatMessage}} = this.props;
    return formatMessage(...args)
  };

  调用:
  this.formatMessage({id: "modal.saveError"})
  zh-cn.js


  const b = { 
    "home.name": "王 {type}"
  }
  export default b;


------------------------
  组件中

  import { FormattedMessage, FormattedDate, FormattedTime, injectIntl  } from 'react-intl';

   <FormattedMessage
      id = "home.name"
      values={{ type: '学生啊'}}
   />


   <FormattedDate 
      value={  new Date() }
   />










运算符优先级

结合性--------------优先级相同时的顺序

运算符优先级
https://www.cnblogs.com/liushui-sky/p/7993122.html
只有一元运算符,三元运算符,赋值运算符是右结合,其他的都是左结合



列子
const a = 2 < 1 ? 20 : 3 > 1 ? 200 : 2000    // 200

因为三元运算符是右结合,所以上面的代码相当于

const a = 2 < 1 ? 20 : ( 3 > 1 ? 200 : 2000 )   -------------------------  先算右边的    

























事件模型

事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现

EventTarget 接口

dom的事件操作,监听和触发,都定义在eventTarget接口,所有节点对象都部署了这个接口

EventTarget 接口提供三个实例方法 :

EventTarget.addEventListener()

EventTarget.addEventListener()绑定事件的监听函数,一旦该事件发生,就会触发执行绑定的监听函数,没有返回值

EventTarget.addEventListener()用于在当前节点或对象上,定义一个特定事件的监听函数。一旦这个事件发生,就会执行监听函数。

该方法没有返回值。

target.addEventListener(type, listener, useCapture);

关于 ( 参数 ) 需要注意两个地方:

  1. 第二个参数除了是监听函数以外,还可以是一个具有handleEvent 方法的对象
    handleEvent详细介绍: https://www.jianshu.com/p/13a0e7f4c335
  componentDidMount() {
    const a = document.getElementById('test');
    a.addEventListener('click', {
      handleEvent: function(e) {console.log(e)},
    },false)
  }
  1. 第三个参数除了是useCapture布尔值以外,还可以是一个属性配置对象
capture:布尔值,表示该事件是否在捕获阶段触发监听函数。


once:布尔值,表示监听函数是否只触发一次,然后就自动移除。


passive:布尔值,表示监听函数不会调用事件的preventDefault方法。
如果监听函数调用了,浏览器将忽略这个要求,并在监控台输出一行警告。
function hello() {
  console.log('Hello world');
}

document.addEventListener('click', hello, false);
document.addEventListener('click', hello, false);

执行上面代码,点击文档只会输出一行Hello world。

function print(x) {
  console.log(x);
}

var el = document.getElementById('div1');
el.addEventListener('click', function () { print('Hello'); }, false);


addEventListener(type, listener, useCapture)
class App extends Component {
  componentDidMount() {
    const a = document.getElementById('test');
    a.addEventListener('click', function(e) {console.log(this.nodeName)}, false)
  }  ------------------------------ 监听函数中的this,指向当前事件所在的对象   // span
  render() {
    return (
      <div className="App">
        <div>aaaa <span id="test">&times;</span> </div>
      </div>
    );
  }
}
  componentDidMount() {
    const a = document.getElementById('test');
    a.addEventListener('click', function(e) {console.log(this.nodeName)}, false);
    a.addEventListener(
      'click', 
      function(e) {console.log(this.nodeName + '可以为同一个对象的同一个事件绑定不同的监听函数')}, 
      false);
    a.addEventListener('click', function(){ go('重庆') }, false);
    ----- 如果要向监听函数传递参数,可以用匿名函数来包装一下监听函数



    const b = document.getElementById('test-wrapper');
    b.addEventListener('click', {
      handleEvent: function(e) {
        console.log('第二个参数可以是一个具有 handleEvent方法的对象')
      }
    }, {
      capture: false,  ------- 是否在捕获阶段触发监听函数
      once: false,   --------- 是否只触发一次监听函数,然后自动移除
      passive: true  --------- 表示监听函数不会调用事件的preventDefault方法
    });
   ----- 第二个参数可以是具有handleEvent方法的对象,
   ----- 第三个参数可以省略,默认是false,在冒泡阶段触发,第三个参数也可以是配置对象

   function go(params) {
      console.log(params)
    }

  }

EventTarget.removeEventListener()

EventTarget.removeEventListener方法用来移除addEventListener方法添加的事件监听函数。该方法没有返回值。


div.addEventListener('click', function (e) {}, false);
div.removeEventListener('click', function (e) {}, false);
上面代码中,removeEventListener方法无效,因为监听函数不是同一个匿名函数。



element.addEventListener('mousedown', handleMouseDown, true);
element.removeEventListener("mousedown", handleMouseDown, false);
上面代码中,removeEventListener方法也是无效的,因为第三个参数不一样。

EventTarget.dispatchEvent()

EventTarget.dispatchEvent方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(),则返回值为false,否则为true。


para.addEventListener('click', hello, false); ----------- 触发event事件后,会触发事件监听函数hello

var event = new Event('click');   ----------- Event构造函数,生成'click'事件实例

para.dispatchEvent(event);   ----------------- 在para节点上,触发 event 事件


总结:

1. EventTarget.dispatchEvent()触发当前节点指定的事件,参数是Event对象的实例。
2. EventTarget.dispatchEvent()返回boolean值,只要有一个监听函数调用了 preventDefault函数,就返回false
3. EventTarget.dispatchEvent()参数为空,或者不是一个有效的事件对象,就会报错

监听函数

浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。

JavaScript 有三种方法,可以为事件绑定监听函数。

HTML 的 on- 属性 ------- 只会在冒泡阶段触发监听函数

<!-- 正确 -->
<body onload="doSomething()">    -----------  值是将要执行的代码,而不是函数,即必须调用

<!-- 错误 -->
<body onload="doSomething">
<div onClick="console.log(2)">
  <button onClick="console.log(1)">点击</button>
</div>

由于on-属性的监听代码,只在冒泡阶段触发,所以点击结果是先输出1,再输出2,

即事件从子元素开始冒泡到父元素。
el.setAttribute('onclick', 'doSomething()');
// 等同于
// <Element onclick="doSomething()">

元素节点的事件属性

  1. 元素节点对象的 事件属性: ------它的值是函数名(doSomething),
  2. HTML 的on-属性: ------必须给出完整的监听代码(doSomething())。
window.onload = doSomething;

div.onclick = function (event) {   ----------------- 注意这种写法不是驼峰写法
  console.log('触发事件');
};

小结

上面三种方法,

  1. 第一种“HTML 的 on- 属性”,违反了 HTML 与 JavaScript 代码相分离的原则,将两者写在一起,不利于代码分工,因此不推荐使用。

  2. 第二种“元素节点的事件属性”的缺点在于,同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。因此,也不推荐使用。

  3. 第三种EventTarget.addEventListener是推荐的指定监听函数的方法。它有如下优点:

EventTarget.addEventListener() 优点

EventTarget.addEventListener()的优点:

1. 可以为同一个事件,指定不同的监听函数

2. 可以指定监听函数触发的阶段,默认是在useCapture捕获阶段触发。第三个参数

3. 除了dom节点,其他对象也有这个接口。     window, XMLHttpRequest等

this 的指向

事件的传播

一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。

注意,浏览器总是假定click事件的目标节点,就是点击位置嵌套最深的那个节点

也就是说,事件传播顺序,
在捕获阶段依次为window、document、html、body、div、p,
在冒泡阶段依次为p、div、body、html、document、window。

事件的代理

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。

// 事件传播到 p 元素后,就不再向下传播了
p.addEventListener('click', function (event) {
  event.stopPropagation();
}, true);


// 事件冒泡到 p 元素后,就不再向上冒泡了
p.addEventListener('click', function (event) {
  event.stopPropagation();
}, false);

Event 对象概述

事件发生以后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event对象,所有的事件都是这个对象的实例,或者说继承了Event.prototype对象。

bubbles:布尔值,可选,默认为false,表示事件对象是否冒泡。

cancelable:布尔值,可选,默认为false,表示事件是否可以被取消,
即能否用Event.preventDefault()取消这个事件。
一旦事件
- 被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为。
// HTML 代码为
// <div><p>Hello</p></div>
var div = document.querySelector('div');
var p = document.querySelector('p');

function callback(event) {
  var tag = event.currentTarget.tagName;
  console.log('Tag: ' + tag); // 没有任何输出
}

div.addEventListener('click', callback, false);

var click = new Event('click');
p.dispatchEvent(click);


上面代码中,p元素发出一个click事件,该事件默认不会冒泡。

div.addEventListener方法指定在冒泡阶段监听,因此监听函数不会触发。

如果写成div.addEventListener('click', callback, true),那么在“捕获阶段”可以监听到这个事件。

Event 对象的实例属性

Event.bubbles,Event.eventPhase

0,事件目前没有发生。
1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
2,事件到达目标节点,即Event.target属性指向的那个节点。
3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。

- 除非显式声明,Event构造函数生成的事件,默认是不冒泡的。

Event.cancelable,

Event.cancelBubble,

event.defaultPrevented

Event.cancelable属性返回一个布尔值,表示事件是否可以取消。该属性为只读属性,一般用来了解 Event 实例的特性。

大多数浏览器的原生事件是可以取消的。


Event.currentTarget,

Event.target

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  componentDidMount() {
    const a = document.getElementById("one");
    a.addEventListener('click', go, false);
    function go(e) {
      console.log(e.target, "e.target");  ----------------- 事件发出的节点,即点击的那个节点
      console.log(e.currentTarget, "e.currentTarget"); ---------------- 是监听函数绑定的元素节点
      console.log(this, 'this'); ------------ 事件触发所绑定的那个节点,即监听函数所在的节点
    }
  }
  render() {
    return <div className="App">
        <div id="one" style={{ background: "yellow", padding: "20px" }}>
          第一个节点
          <div id="two" style={{ background: "silver", padding: "20px" }}>
            第二个节点
            <div id="three" style={{ background: "red", padding: "20px" }}>
              第三个节点
            </div>
          </div>
        </div>
      </div>;
  }
}

export default App;


总结:
1. e.currentTarget指向监听函数所在的元素节点 ------ 即id=one的节点
2. e.target 指向事件发出的节点 ----- 即点击的那个节点
3. 监听函数中的this, 指向触发事件的节点 ---- 始终等于e.currentTarget

Event.timeStamp

Event.detail


Event 对象的实例方法

Event.preventDefault()

Event.stopPropagation()

Event.stopImmediatePropagation()

Event.composedPath()

CustomEvent 接口





















document.documentElement

document.documentElement 以一个 ( 元素对象 ) 返回一个文档的 ( 文档元素 )

document.documentElement   返回整个html文档元素
document.documentElement------返回文档元素,html文档返回html元素

window.location.protocol

window.location.protocol 获得当前网址的协议



类似数组的对象转成真正的数组

Array.prototype.slice.call(nodeList类似数组的对象,传入slice方法的参数)

call方法举例:



var obj = {};
var f = function () {
  return this;
};
f() === window // true
f.call(obj) === obj // true



-------------- 把f函数中this的指向obj对象,即在obj的作用域内运行f函数,第二个参数是传给f函数的参数


Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })
// ['a', 'b']


Array.prototype.slice.call(document.querySelectorAll("div"));--- 将nodeList对象转成数组
Array.prototype.slice.call(arguments);  --------------------------- 将arguments对象转成数组
等于 [].slice.call(arguments) -------------- 因为[]是Array.prototype的实例,继承了slice()方法




可以理解为:在特定的作用域中去执行slice方法

https://www.cnblogs.com/happypayne/p/7739514.html



数组去重

1.
[ ...new Set([有重复值得数组]) ]



2.
let arr = [];
for(let i of new Set([有重复值得数组])) {
    arr.push(i)
}


typeof NaN

typeof返回一个字符串,一共有6种类型:number, string, boolean,object,function,undefined

instanceof

instanceof的原理是检测右边构造函数的原型是否在 左边对象的原型链上
   componentDidMount() {

        let a = {};
        let b = {x: 1};
        Object.setPrototypeOf(a, b); // 把b对象设置成a对象的原型
        console.log( Object.getPrototypeOf(a) === b );

        // ---------------------------------------
        const C = function(){};
        const c = new C();
        const d = c instanceof C;
        console.log(d); // true

        // ---------------------------------------
        undefined instanceof Object // false
        null instanceof Object // false

    }

v instanceof Vehicle

等同于

Vehicle.prototype.isPrototypeOf(v)

Object.create()

Object.prototype.isPrototypeOf()

const a = {};
const b = Object.create(a); ------------------------- 以a对象为原型,生成实例对象b

const c = a.isPrototypeOf(b); ----------------------- a对象是不是b对象的原型
console.log(c)  ------------------------------------- true


--


var o1 = {};
var o2 = Object.create(o1);
var o3 = Object.create(o2);
o2.isPrototypeOf(o3) // true
o1.isPrototypeOf(o3) // true



--


Object.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false

上面代码中,由于Object.prototype处于原型链的最顶端,所以对各种实例都返回true,
只有直接继承自null的对象除外。

Object.getPrototypeOf() ----------- 重要!!!!!!

var F = function () {};
var f = new F();
Object.getPrototypeOf(f) === F.prototype -------- F.prototype会在生成实例时,成为实例对象的原型对象
// true



--



// 空对象的原型是 Object.prototype
Object.getPrototypeOf({}) === Object.prototype // true

// Object.prototype 的原型是 null
Object.getPrototypeOf(Object.prototype) === null // true --------------------重要重要!!

// 函数的原型是 Function.prototype
function f() {}
Object.getPrototypeOf(f) === Function.prototype // true

Object.setPrototypeOf(对象,原型对象)

var a = {};
var b = {x: 1};
Object.setPrototypeOf(a, b);

Object.getPrototypeOf(a) === b // true
a.x // 1
        const a = {};
        const b = {};
        Object.setPrototypeOf(a,b); ----------------- 把b对象设置成a对象的原型对象
        console.log( Object.getPrototypeOf(a) === b);

        const c = Object.create(b);  ---------------- 以b对象为原型对象,生成实例对象
        console.log( Object.getPrototypeOf(c) === b );
上一篇 下一篇

猜你喜欢

热点阅读