TypeScript学习笔记(一) + ( antd-table-modal-form-input影响其他行initialValue值 ) + ( react-intl 国际化 ) 运算符优先级...

安装

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;
}
  • 声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:

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

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

  • 默认情况下null和undefined是所有类型的子类型。 就是说你可以把 null和undefined赋值给number类型等任意类型的变量。然而,当你指定了--strictNullChecks标记,null和undefined只能赋值给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一定是一个字符串
  • 另一个为as语法:
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"});  --------------------- 对



可选属性 ?

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

  • 可选属性的好处之一是可以对可能存在的属性进行预定义,
  • 好处之二是可以捕获引用了不存在的属性时的错误。
    比如,我们故意将 createSquare里的color属性名拼错,就会得到一个错误提示:
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表示私有,私有属性和方法只能在该类中使用,在 子类和实例对象中都不能使用

  • public
  • private

派生类

关键字:extends
  • 基类,派生类
  • ( 基类 ) 通常叫做 ( 超类 )
  • ( 派生类 ) 通常叫做 ( 子类 )














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

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

  • 原因分析:当第一个打开modal时,modal被挂载,form获得initialValue值,再次打开modal时,modal并没有被重新挂载(只是被css隐藏了), 所以form中是上一次改变后input的值。
  • 解决方案: Modal窗口我们都有应用一个Visible来控制是否显示, 我们只要利用这个值得变化就可以实现Modal组件的重新挂载了。
{
  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属性 )
  • 使用<IntlProvider>组件包裹需要实现国际化的根组件
  • intlProvider --- 组件包含两个属性 : localmessage
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的值就是当前语言了。

  • FormattedMesssage组件
  • injectIntl包裹子组件后,通过this.props.intl.formatMessage({.....})来国际化
<FormattedMessage id="table.edit"/>



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


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

  调用:
  this.formatMessage({id: "modal.saveError"})
  • FormattedMessage
  • FormattedDate
  • FormattedTime
  • 使用:
  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() }
   />










运算符优先级

  • 最高优先级:
    ----------> 属性访问 . () []
  • 一元操作符是除了属性访问操作符外,具有最高的优先级
    -----------> 一元+,一元-,递增,递减,typeof,delete,void等
  • 除逗号外,最低优先级:
    ----------> 赋值运算符=

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

  • 左结合:除了一元,三元,赋值以外的,都是左结合
  • 右结合:一元运算符,三元运算符,赋值运算符 (从右往左算)

运算符优先级

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 接口提供三个实例方法 :
  • addEventListener:绑定事件的监听函数
  • removeEventListener:移除事件的监听函数
  • dispatchEvent:触发事件

EventTarget.addEventListener()

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

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

该方法没有返回值。

target.addEventListener(type, listener, useCapture);

  • type: 事件名称,大小写敏感

  • listener: 监听函数,事件发生时,触发该事件

  • useCapture: 监听函数是否在捕获阶段触发,默认是false,即只在冒泡阶段触发

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

  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方法。
如果监听函数调用了,浏览器将忽略这个要求,并在监控台输出一行警告。
  • addEventListener可以为当前对象的同一事件,添加不同的监听函数,这些函数按照添加顺序触发,即先添加先触发。
  • 如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除(不必使用removeEventListener方法手动去除)。
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)
  • 监听函数内部中的this,指向 ( 当前事件 ) 所在的那个 ( 对象 )
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方法添加的事件监听函数。该方法没有返回值。

  • removeEventListener方法的参数,与addEventListener方法完全一致。
  • 注意:
    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。

  • dispatchEvent() 在当前节点上触发指定事件-----------> 从而触发监听函数执行
  • dispatchEvent() 方法的参数是一个Event对象的实例
  • 有返回值,只有有一个监听函数设置了 preventDefault() 就返回 false

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()参数为空,或者不是一个有效的事件对象,就会报错

  • 如果dispatchEvent方法的参数为空,或者不是一个有效的事件对象,将报错。

监听函数

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

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

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

  • 元素的事件监听属性,都是on加上事件名,比如onload就是on + load,表示load事件的监听代码。
  • 注意,这些属性的值是将会执行的代码,而不是一个函数。
  • 使用这个方法指定的监听代码,只会在冒泡阶段触发。
  • 直接设置on-属性,与通过元素节点的setAttribute方法设置on-属性,效果是一样的。
<!-- 正确 -->
<body onload="doSomething()">    -----------  值是将要执行的代码,而不是函数,即必须调用

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

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

即事件从子元素开始冒泡到父元素。
  • 直接设置on-属性,与通过元素节点的setAttribute方法设置on-属性,效果是一样的。
el.setAttribute('onclick', 'doSomething()');
// 等同于
// <Element onclick="doSomething()">

元素节点的事件属性

  • 元素节点对象 的事件属性,同样可以指定监听函数。
  • 使用这个方法指定的监听函数,也是只会在冒泡阶段触发。
  • 缺点: 同一个事件只能定义一个监听函数
  • 注意,
    (元素节点对象的 事件属性 )这种方法与 HTML 的on-属性的差异是:
  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() 优点

  • 同一个事件可以添加多个监听函数。
  • 能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数。
  • 除了 DOM 节点,其他对象(比如window、XMLHttpRequest等)也有这个接口,它等于是整个 JavaScript 统一的监听函数接口。
EventTarget.addEventListener()的优点:

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

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

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

this 的指向

  • 监听函数内部的this, 指向触发事件的元素节点
  • 监听函数中的this, 指向触发事件的那个元素节点

事件的传播

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

  • 第一阶段:从window对象传导到目标节点(上层传到底层),称为“捕获阶段”(capture phase)。
  • 第二阶段:在目标节点上触发,称为“目标阶段”(target phase)。
  • 第三阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。
    事件的传播分为三个阶段
    第一阶段是从window对象传到到目标节点,是捕获阶段 capture phase
    第二阶段,在目标节点上触发,称为目标阶段,target phase
    第三阶段,从目标节点传导到window对象,称为冒泡阶段 bubbling phase
  • phase是阶段的意思
  • bubbling是冒泡的意思
  • capture是捕获的意思

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

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

事件的代理

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

  • delegation 是委托,代理的意思
  • 如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation方法。
  • 但是,stopPropagation方法只会阻止事件的传播,不会阻止该事件触发<p>节点的其他click事件的监听函数。也就是说,不是彻底取消click事件。
// 事件传播到 p 元素后,就不再向下传播了
p.addEventListener('click', function (event) {
  event.stopPropagation();
}, true);


// 事件冒泡到 p 元素后,就不再向上冒泡了
p.addEventListener('click', function (event) {
  event.stopPropagation();
}, false);
  • 如果想要彻底阻止这个事件的传播,不再触发后面所有click的监听函数,可以使用stopImmediatePropagation方法。

Event 对象概述

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

  • Event对象本身就是一个构造函数,可以用来生成新的实例。
  • event = new Event(type, options);
  • Event构造函数接受两个参数。
    第一个参数type是字符串,表示事件的名称;
    第二个参数options是一个对象,表示事件对象的配置
bubbles:布尔值,可选,默认为false,表示事件对象是否冒泡。

cancelable:布尔值,可选,默认为false,表示事件是否可以被取消,
即能否用Event.preventDefault()取消这个事件。
一旦事件
- 被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为。
  • 注意,如果不是显式指定bubbles属性为true,生成的事件就只能在“捕获阶段”触发监听函数。
// 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

  • Event.bubbles属性返回一个布尔值,表示当前事件是否会冒泡。属性为只读属性,一般用来了解 Event 实例是否可以冒泡。
  • Event.eventPhase属性返回一个整数常量,表示事件目前所处的阶段。该属性只读。
    Event.eventPhase的返回值有四种可能。
0,事件目前没有发生。
1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
2,事件到达目标节点,即Event.target属性指向的那个节点。
3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。

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

Event.cancelable,

Event.cancelBubble,

event.defaultPrevented

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

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


Event.currentTarget,

Event.target

  • Event.currentTarget属性返回事件当前所在的节点,即正在执行的监听函数所绑定的那个节点。
  • Event.target属性返回原始触发事件的那个节点,即事件最初发生的节点。
  • 事件传播过程中,不同节点的监听函数内部的Event.target与Event.currentTarget属性的值是不一样的,前者总是不变的,后者则是指向监听函数所在的那个节点对象。
    https://www.cnblogs.com/bo-haier/p/5644268.html
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.preventDefault方法取消浏览器对当前事件的默认行为。比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了;再比如,按一下空格键,页面向下滚动一段距离,使用这个方法以后也不会滚动了。该方法生效的前提是,事件对象的cancelable属性为true,如果为false,调用该方法没有任何效果。
  • 注意,该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。如果要阻止传播,可以使用stopPropagation()或stopImmediatePropagation()方法。

Event.stopPropagation()

  • stopPropagation方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数。
  • propagation:是传播的意思

Event.stopImmediatePropagation()

  • Event.stopImmediatePropagation方法阻止同一个事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。也就是说,该方法阻止事件的传播,比Event.stopPropagation()更彻底。

Event.composedPath()

  • Event.composedPath()返回一个数组,成员是事件的最底层节点和依次冒泡经过的所有上层节点。
  • compose: 组成,成员

CustomEvent 接口

  • CustomEvent 接口用于生成自定义的事件实例。那些浏览器预定义的事件,虽然可以手动生成,但是往往不能在事件上绑定数据。如果需要在触发事件的同时,传入指定的数据,就可以使用 CustomEvent 接口生成的自定义事件对象。




















document.documentElement

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

  • ( html文档 ) 返回对象为 ( html元素 )
  • 如果html元素缺失,返回null
document.documentElement   返回整个html文档元素
document.documentElement------返回文档元素,html文档返回html元素

window.location.protocol

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

  • protocol是协议的意思


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

  • Array.from()
  • Array.prototype.slice.call(类似数组的对象)

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

  • Array是实例数组的构造函数,
    Array.prototype.slice就是实例数组的slice()方法。
    实例数组的slice()方法继承自Array.prototype属性。
    slice()方法没有参数时,相当于原数组的拷贝。即从0截取到最后
  • call方法
    Function.prototype.call(this需要绑定的对象, 传入function函数的参数)。
    函数中this的指向,即this指向函数执行时所在的对象。
    Function.prototype.call的作用是,绑定this的指向为参数对象,并且执行该函数。
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(类似数组的对象,传入slice的参数,如果没有就是拷贝数组)

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

  • typeof NaN 返回的是 ‘number’
  • typeof Infinity 返回的是 ‘number’
  • typeof Date 返回的是‘function’
  • null , array , object 返回的都是‘object’
    ------- 如果要区分对象,可以使用 instanceof检测某个对象是不是另一个对象的实例
    ------- [ ] instanceof Array // true
    https://blog.csdn.net/GreyBearChao/article/details/77914261

instanceof

instanceof的原理是检测右边构造函数的原型是否在 左边对象的原型链上
  • instanceof返回一个布尔值,表示对象是否为某个构造函数的实例
  • instance左边是对象,右边是构造函数
  • 'aaa' instanceof String false
  • [ ] instanceof Array // true
  • 对于undefined和null,instanceOf运算符总是返回false
   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

    }
  • instanceof的原理是检测右边构造函数的原型是否在 左边对象的原型链上

v instanceof Vehicle

等同于

Vehicle.prototype.isPrototypeOf(v)

Object.create()

  • 以参数对象为原型生成实例对象

Object.prototype.isPrototypeOf()

  • isPrototype用来判断该该对象是否是参数对象的原型对象
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() ----------- 重要!!!!!!

  • 返回参数对象的原型对象
  • 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(对象,原型对象)

  • 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 );
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容