记4_23面试知识整理

1.函数组件和类组件

  函数组件类似

 1   function Person = (props) => {
 2    const say = () =>{
 3      alert(`Hi my name is ${props.name}`)
 4    }
 5    return (
 6      <div>Hello, {props.name}</div>
 7      <button onClick = {say}>say</button>
 8    )
 9  }

  类组件;

 1   import React from 'react'
 2   class Person extends React.component {
 3      constructor(props){
 4      super(props)    
 5    }
 6    say(){
 7     alert(`Hi, ${this.props.name}`)
 8    }
 9      render(){
10        return (
11       <div>Hello,{this.props.name}</div>
12       <button onClick={this.say.bind(this)}>say</button>
13     )
14      }
15    }

  

  1. 函数组件看似只是一个返回值是DOM结构的函数,其实它的背后是无状态组件(Stateless Components)的思想。函数组件中,你无法使用State,也无法使用组件的生命周期方法,这就决定了函数组件都是展示性组件(Presentational Components),接收Props,渲染DOM,而不关注其他逻辑。

  2. 函数组件中没有this。所以你再也不需要考虑this带来的烦恼。而在类组件中,你依然要记得绑定this这个琐碎的事情。如示例中的sayHi。

  3. 函数组件更容易理解。当你看到一个函数组件时,你就知道它的功能只是接收属性,渲染页面,它不执行与UI无关的逻辑处理,它只是一个纯函数。而不用在意它返回的DOM结构有多复杂。

  4. 性能。目前React还是会把函数组件在内部转换成类组件,所以使用函数组件和使用类组件在性能上并无大的差异。但是,React官方已承诺,未来将会优化函数组件的性能,因为函数组件不需要考虑组件状态和组件生命周期方法中的各种比较校验,所以有很大的性能提升空间。

  5. 函数组件迫使你思考最佳实践。这是最重要的一点。组件的主要职责是UI渲染,理想情况下,所有的组件都是展示性组件,每个页面都是由这些展示性组件组合而成。如果一个组件是函数组件,那么它当然满足这个要求。所以牢记函数组件的概念,可以让你在写组件时,先思考这个组件应不应该是展示性组件。更多的展示性组件意味着更多的组件有更简洁的结构,更多的组件能被更好的复用。

2.component和purecomponent的区别;

React.createClass:   不使用ES6语法,只能使用 React.createClass 来创建组件;React对属性中的所有函数都进行了this绑定
Component:      使用ES6语法创建组件;React并没有对内部的函数,进行this绑定
PureComponent:      houldComponentUpdate通过判断props和state是否发生变化来决定需不需要重新渲染组件,当然有时候这种简单的判断,显得有些多余和样板化,于是React就提供了PureComponent来自动帮我们做这件事,这样就不需要手动来写shouldComponentUpdate了。注意:PureComponent 自动为我们添加的shouldComponentUpate函数,只是对props和state进行浅比较;最简单避免上述情况的方式,就是避免使用可变对象作为props和state,取而代之的是每次返回一个全新的对象;也可以考虑使用Immutable.js来创建不可变对象,通过它来简化对象比较,提高性能。
无状态组件:        无state,只有props。
3.this的理解
  1.this和构造器

 1 this总是挂属性/字段,方法都应在原型上
 2 function Tab(nav, content) {
 3   this.nav = nav
 4   this.content = content
 5 }
 6 Tab.prototype.getNav = function() {
 7   return this.nav;
 8 };
 9 Tab.prototype.setNav = function(nav) {
10   this.nav = nav;
11 };
12 Tab.prototype.add = function() {
13 };

  2.this和对象

 1 js中的对象不用类也可以创建,因为是面向对象编程而不是面向类编程
 2 var tab = {
 3   nav: '',
 4   content: '',
 5   getNav: function() {
 6     return this.nav;
 7   },
 8   setNav: function(n) {
 9     this.nav = n;
10   }
11 }

  3.this和函数

 1 this和独立的函数放在一起没有意义,一般尽量不要在纯函数中使用this,如果有时候需要使用,调用方式使用cal/apply
 2 
 3 function showMsg() {
 4   alert(this.message)
 5 }
 6 
 7 var m1 = {
 8   message: '输入的电话号码不正确'
 9 }
10 var m2 = {
11   message: '输入的身份证号不正确'
12 }
13 
14 showMsg.call(m1) // '输入的电话号码不正确'
15 showMsg.call(m2) // '输入的身份证号不正确'

  4.箭头函数中this指向;
4.setState执行机制

  1. setState基本特点

    1. setState是同步执行的

      setState是同步执行的,但是state并不一定会同步更新

    2. setState在React生命周期和合成事件中批量覆盖执行

      在React的生命周期钩子和合成事件中,多次执行setState,会批量执行

      具体表现为,多次同步执行的setState,会进行合并,类似于Object.assign,相同的key,后面的会覆盖前面的

     当遇到多个setState调用时候,会提取单次传递setState的对象,把他们合并在一起形成一个新的
     单一对象,并用这个单一的对象去做setState的事情,就像Object.assign的对象合并,后一个
     key值会覆盖前面的key值

    3. setState在原生事件,setTimeout,setInterval,Promise等异步操作中,state会同步更新

      异步操作中setState,即使在React的钩子或合成事件中,state都不会批量更新,而是会同步更新,
     多次连续操作setState,每次都会re-render,state会同步更新

  3. setState的基本过程

    setState的调用会引起React的更新生命周期的4个函数执行。

   shouldComponentUpdate
   componentWillUpdate
   render
   componentDidUpdate

    当shouldComponentUpdate执行时,返回true,进行下一步,this.state没有被更新
   返回false,停止,更新this.state

    当componentWillUpdate被调用时,this.state也没有被更新

   直到render被调用时候,this.state才被更新。

    总之,直到下一次render函数调用(或者下一次shouldComponentUpdate返回false时)才能得到更新后的this.state
   因此获取更新后的状态可以有3种方法:

  5. setState的缺点

   1. setState有可能循环调用

    调用setState之后,shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate 等生命周期函数会依次被调用(如果shouldComponentUpdate没有返回 false的话),

   如果我们在render、componentWillUpdate或componentDidUpdate中调用了setState方法,那么可能会造成循环调用,最终导致浏览器内存占满后崩溃

   2、setState可能会引发不必要的渲染

    可能造成不必要渲染的因素如下: 
   (1)新 state 和之前的一样。这种情况可以通过 shouldComponentUpdate 解决。 
   (2)state 中的某些属性和视图没有关系(譬如事件、timer ID等),这些属性改变不影响视图的显示。

   3、setState并不总能有效地管理组件中的所有状态

    因为组件中的某些属性是和视图没有关系的,当组件变得复杂的时候可能会出现各种各样的状态需要管理,这时候用setState管理所有状态是不可取的。

   state中本应该只保存与渲染有关的状态,而与渲染无关的状态尽量不放在state中管理,可以直接保存为组件实例的属性,这样在属性改变的时候,不会触发渲染,避免浪费

   6. setState和replaceState的区别

    setState是修改其中的部分状态,相当于Object.assign,只是覆盖,不会减少原来的状态
   replaceState是完全替换原来的状态,相当于赋值,将原来的state替换为另一个对象,如果新状态属性减少,那么state中就没有这个状态了
5.git常用命令

  1 git init
  2      在本地新建一个repo,进入一个项目目录,执行git init,会初始化一个repo,并在当前文件夹下创建一个.git文件夹.
  3  
  4 git clone
  5      获取一个url对应的远程Git repo, 创建一个local copy.
  6      一般的格式是git clone [url].
  7      clone下来的repo会以url最后一个斜线后面的名称命名,创建一个文件夹,如果想要指定特定的名称,可以git clone [url] newname指定.
  8  
  9 git status
 10      查询repo的状态.
 11      git status -s: -s表示short, -s的输出标记会有两列,第一列是对staging区域而言,第二列是对working目录而言.
 12  
 13 git log
 14      show commit history of a branch.
 15      git log --oneline --number: 每条log只显示一行,显示number条.
 16      git log --oneline --graph:可以图形化地表示出分支合并历史.
 17      git log branchname可以显示特定分支的log.
 18      git log --oneline branch1 ^branch2,可以查看在分支1,却不在分支2中的提交.^表示排除这个分支(Window下可能要给^branch2加上引号).
 19      git log --decorate会显示出tag信息.
 20      git log --author=[author name] 可以指定作者的提交历史.
 21      git log --since --before --until --after 根据提交时间筛选log.
 22      --no-merges可以将merge的commits排除在外.
 23      git log --grep 根据commit信息过滤log: git log --grep=keywords
 24      默认情况下, git log --grep --author是OR的关系,即满足一条即被返回,如果你想让它们是AND的关系,可以加上--all-match的option.
 25      git log -S: filter by introduced diff.
 26      比如: git log -SmethodName (注意S和后面的词之间没有等号分隔).
 27      git log -p: show patch introduced at each commit.
 28      每一个提交都是一个快照(snapshot),Git会把每次提交的diff计算出来,作为一个patch显示给你看.
 29      另一种方法是git show [SHA].
 30      git log --stat: show diffstat of changes introduced at each commit.
 31      同样是用来看改动的相对信息的,--stat比-p的输出更简单一些.
 32     
 33 git add
 34      在提交之前,Git有一个暂存区(staging area),可以放入新添加的文件或者加入新的改动. commit时提交的改动是上一次加入到staging area中的改动,而不是我们disk上的改动.
 35      git add .
 36      会递归地添加当前工作目录中的所有文件.
 37  
 38 git diff
 39      不加参数的git diff:
 40      show diff of unstaged changes.
 41      此命令比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容.
 42  
 43      若要看已经暂存起来的文件和上次提交时的快照之间的差异,可以用:
 44      git diff --cached 命令.
 45      show diff of staged changes.
 46      (Git 1.6.1 及更高版本还允许使用 git diff --staged,效果是相同的).
 47  
 48      git diff HEAD
 49      show diff of all staged or unstated changes.
 50      也即比较woking directory和上次提交之间所有的改动.
 51  
 52      如果想看自从某个版本之后都改动了什么,可以用:
 53      git diff [version tag]
 54      跟log命令一样,diff也可以加上--stat参数来简化输出.
 55  
 56      git diff [branchA] [branchB]可以用来比较两个分支.
 57      它实际上会返回一个由A到B的patch,不是我们想要的结果.
 58      一般我们想要的结果是两个分支分开以后各自的改动都是什么,是由命令:
 59      git diff [branchA]…[branchB]给出的.
 60      实际上它是:git diff $(git merge-base [branchA] [branchB]) [branchB]的结果.
 61  
 62  
 63 git commit
 64      提交已经被add进来的改动.
 65      git commit -m “the commit message"
 66      git commit -a 会先把所有已经track的文件的改动add进来,然后提交(有点像svn的一次提交,不用先暂存). 对于没有track的文件,还是需要git add一下.
 67      git commit --amend 增补提交. 会使用与当前提交节点相同的父节点进行一次新的提交,旧的提交将会被取消.
 68  
 69 git reset
 70      undo changes and commits.
 71      这里的HEAD关键字指的是当前分支最末梢最新的一个提交.也就是版本库中该分支上的最新版本.
 72      git reset HEAD: unstage files from index and reset pointer to HEAD
 73      这个命令用来把不小心add进去的文件从staged状态取出来,可以单独针对某一个文件操作: git reset HEAD - - filename, 这个- - 也可以不加.
 74      git reset --soft
 75      move HEAD to specific commit reference, index and staging are untouched.
 76      git reset --hard
 77      unstage files AND undo any changes in the working directory since last commit.
 78      使用git reset —hard HEAD进行reset,即上次提交之后,所有staged的改动和工作目录的改动都会消失,还原到上次提交的状态.
 79      这里的HEAD可以被写成任何一次提交的SHA-1.
 80      不带soft和hard参数的git reset,实际上带的是默认参数mixed.
 81  
 82      总结:
 83      git reset --mixed id,是将git的HEAD变了(也就是提交记录变了),但文件并没有改变,(也就是working tree并没有改变). 取消了commit和add的内容.
 84      git reset --soft id. 实际上,是git reset –mixed id 后,又做了一次git add.即取消了commit的内容.
 85      git reset --hard id.是将git的HEAD变了,文件也变了.
 86      按改动范围排序如下:
 87      soft (commit) < mixed (commit + add) < hard (commit + add + local working)
 88  
 89 git revert
 90      反转撤销提交.只要把出错的提交(commit)的名字(reference)作为参数传给命令就可以了.
 91      git revert HEAD: 撤销最近的一个提交.
 92      git revert会创建一个反向的新提交,可以通过参数-n来告诉Git先不要提交.
 93     
 94 git rm
 95      git rm file: 从staging区移除文件,同时也移除出工作目录.
 96      git rm --cached: 从staging区移除文件,但留在工作目录中.
 97      git rm --cached从功能上等同于git reset HEAD,清除了缓存区,但不动工作目录树.
 98  
 99 git clean
100      git clean是从工作目录中移除没有track的文件.
101      通常的参数是git clean -df:
102      -d表示同时移除目录,-f表示force,因为在git的配置文件中, clean.requireForce=true,如果不加-f,clean将会拒绝执行.
103  
104 git mv
105      git rm - - cached orig; mv orig new; git add new
106  
107 git stash
108      把当前的改动压入一个栈.
109      git stash将会把当前目录和index中的所有改动(但不包括未track的文件)压入一个栈,然后留给你一个clean的工作状态,即处于上一次最新提交处.
110      git stash list会显示这个栈的list.
111      git stash apply:取出stash中的上一个项目(stash@{0}),并且应用于当前的工作目录.
112      也可以指定别的项目,比如git stash apply stash@{1}.
113      如果你在应用stash中项目的同时想要删除它,可以用git stash pop
114  
115      删除stash中的项目:
116      git stash drop: 删除上一个,也可指定参数删除指定的一个项目.
117      git stash clear: 删除所有项目.
118  
119 git branch
120      git branch可以用来列出分支,创建分支和删除分支.
121      git branch -v可以看见每一个分支的最后一次提交.
122      git branch: 列出本地所有分支,当前分支会被星号标示出.
123      git branch (branchname): 创建一个新的分支(当你用这种方式创建分支的时候,分支是基于你的上一次提交建立的). 
124      git branch -d (branchname): 删除一个分支.
125      删除remote的分支:
126      git push (remote-name) :(branch-name): delete a remote branch.
127      这个是因为完整的命令形式是:
128      git push remote-name local-branch:remote-branch
129      而这里local-branch的部分为空,就意味着删除了remote-branch
130  
131 git checkout
132   git checkout (branchname)
133  
134  
135 
136  切换到一个分支.
137      git checkout -b (branchname): 创建并切换到新的分支.
138      这个命令是将git branch newbranch和git checkout newbranch合在一起的结果.
139      checkout还有另一个作用:替换本地改动:
140      git checkout --<filename>
141      此命令会使用HEAD中的最新内容替换掉你的工作目录中的文件.已添加到暂存区的改动以及新文件都不会受到影响.
142      注意:git checkout filename会删除该文件中所有没有暂存和提交的改动,这个操作是不可逆的.
143  
144 git merge
145      把一个分支merge进当前的分支.
146      git merge [alias]/[branch]
147      把远程分支merge到当前分支.
148  
149      如果出现冲突,需要手动修改,可以用git mergetool.
150      解决冲突的时候可以用到git diff,解决完之后用git add添加,即表示冲突已经被resolved.
151  
152 git tag
153      tag a point in history as import.
154      会在一个提交上建立永久性的书签,通常是发布一个release版本或者ship了什么东西之后加tag.
155      比如: git tag v1.0
156      git tag -a v1.0, -a参数会允许你添加一些信息,即make an annotated tag.
157      当你运行git tag -a命令的时候,Git会打开一个编辑器让你输入tag信息.
158      
159      我们可以利用commit SHA来给一个过去的提交打tag:
160      git tag -a v0.9 XXXX
161  
162      push的时候是不包含tag的,如果想包含,可以在push时加上--tags参数.
163      fetch的时候,branch HEAD可以reach的tags是自动被fetch下来的, tags that aren’t reachable from branch heads will be skipped.如果想确保所有的tags都被包含进来,需要加上--tags选项.
164  
165 git remote
166      list, add and delete remote repository aliases.
167      因为不需要每次都用完整的url,所以Git为每一个remote repo的url都建立一个别名,然后用git remote来管理这个list.
168      git remote: 列出remote aliases.
169      如果你clone一个project,Git会自动将原来的url添加进来,别名就叫做:origin.
170      git remote -v:可以看见每一个别名对应的实际url.
171      git remote add [alias] [url]: 添加一个新的remote repo.
172      git remote rm [alias]: 删除一个存在的remote alias.
173      git remote rename [old-alias] [new-alias]: 重命名.
174      git remote set-url [alias] [url]:更新url. 可以加上—push和fetch参数,为同一个别名set不同的存取地址.
175  
176 git fetch
177      download new branches and data from a remote repository.
178      可以git fetch [alias]取某一个远程repo,也可以git fetch --all取到全部repo
179      fetch将会取到所有你本地没有的数据,所有取下来的分支可以被叫做remote branches,它们和本地分支一样(可以看diff,log等,也可以merge到其他分支),但是Git不允许你checkout到它们. 
180  
181 git pull
182      fetch from a remote repo and try to merge into the current branch.
183      pull == fetch + merge FETCH_HEAD
184      git pull会首先执行git fetch,然后执行git merge,把取来的分支的head merge到当前分支.这个merge操作会产生一个新的commit.    
185      如果使用--rebase参数,它会执行git rebase来取代原来的git merge.
186   
187  
188 git rebase
189      --rebase不会产生合并的提交,它会将本地的所有提交临时保存为补丁(patch),放在”.git/rebase”目录中,然后将当前分支更新到最新的分支尖端,最后把保存的补丁应用到分支上.
190      rebase的过程中,也许会出现冲突,Git会停止rebase并让你解决冲突,在解决完冲突之后,用git add去更新这些内容,然后无需执行commit,只需要:
191      git rebase --continue就会继续打余下的补丁.
192      git rebase --abort将会终止rebase,当前分支将会回到rebase之前的状态.
193  
194 git push
195      push your new branches and data to a remote repository.
196      git push [alias] [branch]
197      将会把当前分支merge到alias上的[branch]分支.如果分支已经存在,将会更新,如果不存在,将会添加这个分支.
198      如果有多个人向同一个remote repo push代码, Git会首先在你试图push的分支上运行git log,检查它的历史中是否能看到server上的branch现在的tip,如果本地历史中不能看到server的tip,说明本地的代码不是最新的,
     Git会拒绝你的push,让你先fetch,merge,之后再push,这样就保证了所有人的改动都会被考虑进来.
199 200 git reflog 201 git reflog是对reflog进行管理的命令,reflog是git用来记录引用变化的一种机制,比如记录分支的变化或者是HEAD引用的变化. 202 当git reflog不指定引用的时候,默认列出HEAD的reflog. 203 HEAD@{0}代表HEAD当前的值,HEAD@{3}代表HEAD在3次变化之前的值. 204 git会将变化记录到HEAD对应的reflog文件中,其路径为.git/logs/HEAD, 分支的reflog文件都放在.git/logs/refs目录下的子目录中.

6.受控组件和非受控组件

  假设我们现在有一个表单,表单中有一个input标签,input的value值必须是我们设置在constructor构造函数的state中的值,然后,通过onChange触发事件来改变state中保存的value值,这样形成一个循环的回路影响。也可以说是React负责渲染表单的组件仍然控制用户后续输入时所发生的变化。

  就像上面这样,input中的value值通过state值获取,onChange事件改变state中的value值,input中的value值又从state中获取。。。


  非受控也就意味着我可以不需要设置它的state属性,而通过ref来操作真实的DOM。

7.浏览器多个标签页之间通信

一:websocket通讯

WebSocket连接必须由浏览器发起,特点:

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

二:定时器setInterval+cookie

在页面A设置一个使用 setInterval 定时器不断刷新,检查 Cookies 的值是否发生变化,如果变化就进行刷新的操作。

由于 Cookies 是在同域可读的,所以在页面 B 审核的时候改变 Cookies 的值,页面 A 自然是可以拿到的。

这样做确实可以实现我想要的功能,但是这样的方法相当浪费资源。虽然在这个性能过盛的时代,浪费不浪费也感觉不出来,但是这种实现方案,确实不够优雅。

三:使用localstorage

localstorage是浏览器多个标签共用的存储空间,所以可以用来实现多标签之间的通信(ps:session是会话级的存储空间,每个标签页都是单独的)。

直接在window对象上添加监听即可:

window.onstorage = (e) => {console.log(e)}// 或者这样window.addEventListener('storage', (e) => console.log(e))

onstorage以及storage事件,针对都是非当前页面对localStorage进行修改时才会触发,当前页面修改localStorage不会触发监听函数。然后就是在对原有的数据的值进行修改时才会触发,比如原本已经有一个key会a值为b的localStorage,你再执行:localStorage.setItem('a', 'b')代码,同样是不会触发监听函数的。

8.宏任务和微任务
但是js异步有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入eventqueue,然后在执行微任务,将微任务放入eventqueue最骚的是,这两个queue不是一个queue。当你往外拿的时候先从微任务里拿这个回掉函数,然后再从宏任务的queue上拿宏任务的回掉函数。

而宏任务一般是:包括整体代码script,setTimeout,setInterval。

微任务:Promise,process.nextTick。

posted @ 2019-04-24 16:37  醉清风&雨  阅读(93)  评论(0)    收藏  举报