2021-02-02

2021-02-02  本文已影响0人  刘巴哥

<meta name="source" content="lake">

比较typeof与instanceof?

相同点:JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的。

typeof的定义和用法:返回值是一个字符串,用来说明变量的数据类型。

细节:

(1)、typeof 一般只能返回如下几个结果:number,boolean,string,function,object,undefined。

(2)、typeof 来获取一个变量是否存在,如 if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错。

(3)、对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。

Instanceof定义和用法:instanceof 用于判断一个变量是否属于某个对象的实例。

实例演示:

a instanceof b?alert("true"):alert("false"); //a是b的实例?真:假

var a = new Array();
alert(a instanceof Array); // true
alert(a instanceof Object) // true

如上,会返回 true,同时 alert(a instanceof Object) 也会返回 true;这是因为 Array 是 object 的子类。

function test(){};
var a = new test();
alert(a instanceof test) // true

细节:

(1)、如下,得到的结果为‘N’,这里的 instanceof 测试的 object 是指 js 语法中的 object,不是指 dom 模型对象。

if (window instanceof Object){ alert('Y')} else { alert('N');} // 'N'

如何理解闭包?

1、定义和用法:当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。

2、表现形式:使函数外部能够调用函数内部定义的变量。

3、实例如下:

(1)、根据作用域链的规则,底层作用域没有声明的变量,会向上一级找,找到就返回,没找到就一直找,直到window的变量,没有就返回undefined。这里明显count 是函数内部的flag2 的那个count 。

<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"> var count=10; //全局作用域 标记为flag1 function add(){ var count=0; //函数全局作用域 标记为flag2 return function(){ count+=1; //函数的内部作用域 alert(count); } } var s = add() s();//输出1 s();//输出2</pre>

变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域分类:全局变量和局部变量。

特点:

1、函数内部可以读取函数外部的全局变量;在函数外部无法读取函数内的局部变量。

2、函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

5、使用闭包的注意点

1)滥用闭包,会造成内存泄漏:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)会改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

什么是跨域?跨域请求资源的方法有哪些?

1、什么是跨域?

由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。存在跨域的情况:

2、跨域请求资源的方法:

(1)、porxy代理

定义和用法:proxy代理用于将请求发送给后台服务器,通过服务器来发送请求,然后将请求的结果传递给前端。

实现方法:通过nginx代理;

注意点:1、如果你代理的是https协议的请求,那么你的proxy首先需要信任该证书(尤其是自定义证书)或者忽略证书检查,否则你的请求无法成功。

(2)、CORS 【Cross-Origin Resource Sharing】

定义和用法:是现代浏览器支持跨域资源请求的一种最常用的方式。

使用方法:一般需要后端人员在处理请求数据的时候,添加允许跨域的相关操作。如下:

<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"> res.writeHead(200, { "Content-Type": "text/html; charset=UTF-8", "Access-Control-Allow-Origin":'http://localhost', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'X-Requested-With, Content-Type' });</pre>

(3)、jsonp

定义和用法:通过动态插入一个script标签。浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下)。

特点:通过情况下,通过动态创建script来读取他域的动态资源,获取的数据一般为json格式。

实例如下:

<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"> <script> function testjsonp(data) { console.log(data.name); // 获取返回的结果 } </script> <script> var _script = document.createElement('script'); _script.type = "text/javascript"; _script.src = "http://localhost:8888/jsonp?callback=testjsonp"; document.head.appendChild(_script); </script></pre>

缺点:

1、这种方式无法发送post请求(这里)

2、另外要确定jsonp的请求是否失败并不容易,大多数框架的实现都是结合超时时间来判定。

谈谈垃圾回收机制方式及内存管理

回收机制方式

1、定义和用法:垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。

2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。

3、实例如下:

<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"> function fn1() { var obj = {name: 'hanzichi', age: 10}; } function fn2() { var obj = {name:'hanzichi', age: 10}; return obj; } var a = fn1(); var b = fn2();</pre>

fn1中定义的obj为局部变量,而当调用结束后,出了fn1的环境,那么该块内存会被js引擎中的垃圾回收器自动释放;在fn2被调用的过程中,返回的对象被全局变量b所指向,所以该块内存并不会被释放。

请说出三种减低页面加载时间的方法

web前端开发,如何提高页面性能优化?

内容方面:

1.减少 HTTP 请求 (Make Fewer HTTP Requests)

2.减少 DOM 元素数量 (Reduce the Number of DOM Elements)

3.使得 Ajax 可缓存 (Make Ajax Cacheable)

针对CSS:

1.把 CSS 放到代码页上端 (Put Stylesheets at the Top)

2.从页面中剥离 JavaScript 与 CSS (Make JavaScript and CSS External)

3.精简 JavaScript 与 CSS (Minify JavaScript and CSS)

4.避免 CSS 表达式 (Avoid CSS Expressions)

针对JavaScript :

\1. 脚本放到 HTML 代码页底部 (Put Scripts at the Bottom)

\2. 从页面中剥离 JavaScript 与 CSS (Make JavaScript and CSS External)

\3. 精简 JavaScript 与 CSS (Minify JavaScript and CSS)

\4. 移除重复脚本 (Remove Duplicate Scripts)

面向图片(Image):

1.优化图片

2 不要在 HTML 中使用缩放图片

3 使用恰当的图片格式

4 使用 CSS Sprites 技巧对图片优化

浏览器是如何渲染页面的?

渲染的流程如下:

1.解析HTML文件,创建DOM树。

自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。

2.解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式<HTML中的style样式;

3.将CSS与DOM合并,构建渲染树(Render Tree)

4.布局和绘制,重绘(repaint)和重排(reflow)

Controlled Component 与 Uncontrolled Component 之间的区别是什么?

React 的核心组成之一就是能够维持内部状态的自治组件,不过当我们引入原生的HTML表单元素时(input,select,textarea 等),我们是否应该将所有的数据托管到 React 组件中还是将其仍然保留在 DOM 元素中呢?这个问题的答案就是受控组件与非受控组件的定义分割。受控组件(Controlled Component)代指那些交由 React 控制并且所有的表单数据统一存放的组件。譬如下面这段代码中username变量值并没有存放到DOM元素中,而是存放在组件状态数据中。任何时候我们需要改变username变量值时,我们应当调用setState函数进行修改。

JavaScript

<colgroup><col width="375"><col width="375"></colgroup>
|

12345678910111213141516171819202122

|

class ControlledForm extends Component { state = { username: '' } updateUsername = (e) => { this.setState({ username: e.target.value, }) } handleSubmit = () => {} render () { return ( <form onSubmit={this.handleSubmit}> <input type='text' value={this.state.username} onChange={this.updateUsername} /> <button type='submit'>Submit</button> </form> ) }}

|
| | |

而非受控组件(Uncontrolled Component)则是由DOM存放表单数据,并非存放在 React 组件中。我们可以使用 refs 来操控DOM元素:

JavaScript

<colgroup><col width="375"><col width="375"></colgroup>
|

123456789101112131415

|

class UnControlledForm extends Component { handleSubmit = () => { console.log("Input Value: ", this.input.value) } render () { return ( <form onSubmit={this.handleSubmit}> <input type='text' ref={(input) => this.input = input} /> <button type='submit'>Submit</button> </form> ) }}

|
| | |

竟然非受控组件看上去更好实现,我们可以直接从 DOM 中抓取数据,而不需要添加额外的代码。不过实际开发中我们并不提倡使用非受控组件,因为实际情况下我们需要更多的考虑表单验证、选择性的开启或者关闭按钮点击、强制输入格式等功能支持,而此时我们将数据托管到 React 中有助于我们更好地以声明式的方式完成这些功能。引入 React 或者其他 MVVM 框架最初的原因就是为了将我们从繁重的直接操作 DOM 中解放出来。

什么是 React 的 refs ,为什么它们很重要?

refs就像是一个逃生舱口,允许您直接访问DOM元素或组件实例。为了使用它们,您可以向组件添加一个 ref 属性,该属性的值是一个回调函数,它将接收底层的 DOM 元素或组件的已挂接实例,作为其第一个参数。

<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"> class UnControlledForm extends Component { handleSubmit = () => { console.log("Input Value: ", this.input.value) } render () { return ( <form onSubmit={this.handleSubmit}> <input type='text' ref={(input) => this.input = input} /> <button type='submit'>Submit</button> </form> ) } }</pre>

以上注意到我们的输入字段有一个 ref 属性,其值是一个函数。该函数接收我们然后放在实例上的实际的 DOM 元素,以便在 handleSubmit 函数内部访问它。经常误解的是,您需要使用类组件才能使用 ref ,但 ref 也可以通过利用 JavaScript 中的 闭包 与 功能组件( functional components )一起使用。

<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"> function CustomForm ({handleSubmit}) { let inputElement return ( <form onSubmit={() => handleSubmit(inputElement.value)}> <input type='text' ref={(input) => inputElement = input} /> <button type='submit'>Submit</button> </form> ) }</pre>

React 中的keys是什么,为什么它们很重要?

keys是什么帮助 React 跟踪哪些项目已更改、添加或从列表中删除。

<pre class="cm-s-default" style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"> return ( <ul> {this.state.todoItems.map(({task, uid}) => { return <li key={uid}>{task}</li> })} </ul> ) }</pre>

每个 keys 在兄弟元素之间是独一无二的。我们已经谈过几次关于和解(reconciliation)的过程,而且这个和解过程(reconciliation)中的一部分正在执行一个新的元素树与最前一个的差异。keys 使处理列表时更加高效,因为 React 可以使用子元素上的 keys 快速知道元素是新的还是在比较树时才被移动。

而且 keys 不仅使这个过程更有效率,而且没有 keys ,React 不知道哪个本地状态对应于移动中的哪个项目。所以当你 map 的时候,不要忽略了 keys 。

在哪个生命周期事件中你会发出 AJAX 请求,为什么?

AJAX 请求应该在 componentDidMount 生命周期事件中。 有几个原因:

-您不能保证在组件挂载之前,AJAX请求将无法 resolve。如果这样做,那意味着你会尝试在一个未挂载的组件上设置 StState,这不仅不会起作用,反而会对你大喊大叫。 在 componentDidMount 中执行 AJAX 将保证至少有一个要更新的组件。

上一篇下一篇

猜你喜欢

热点阅读