面试2

HTTP

客户端/服务器模型

  • 客户端主动发送要求。
  • 被动地等待来自用户端的要求,处理请求并传回响应
  • 客户端等待,而后处理响应。

性能优化

雪碧图 http缓存 虚拟dom webpackjavascript

三次握手

为何要三次握手? 三次握手: A:我能连你了吗? B: 能够连我,你连吧 A:那我连你了 开始发送数据css

缘由:由于要保证A/B 均可以收发信息 ,数据才能在AB之间传输html

A:我能连你了吗? B: 能够 说明A能够发信息,B能够接受信息html5

B: 能够连我,你连吧 A:那我连你了 说明B能够发送信息,A能够接受信息java

HTML5

html5中新增长的标签,技术(api)(包括promise,localStorage,canvas等),统称为html5.webpack

CSS

CSS选择器

  1. .类选择器,#id选择器,input[type=text] [data-x] [target=_blank] 属性选择器web

  2. 直接子代选择器> 后代选择器空格 表明两个都选面试

  3. 伪类选择器 input:focus 选择得到焦点的 input 元素。 a:hover p:first-child p:last-child p:nth-child(1) p:nth-child(even) p:nth-child(odd) p:before p:afterajax

input:enabled 选择每一个启用 元素。 input:disabled 选择每一个禁用 元素 input:checked 选择每一个被选中的 元素。canvas

CSS2:高度与宽度

  • inline的高度是行高,而不是font-size
  • 全部inline和inline-block元素之间,无论有多少回车和空格或者tab,都只显示一个空格,解决方法:1float:left,而后clearfix清除浮动,2display:flex
  • 超出一行文本省略:
    div{
          border:1px solid red;
          /*如下三行*/
          white-space:nowrap;
          overflow:hidden;
          text-overflow:ellipsis;
        }
    复制代码
  • 阻止父子上下margin合并的方法:1.父亲padding0.1或者儿子border0.1挡住,能够防止合并。2父亲overflow:hidden;
  • 文档流:1.内联元素从左到右依次排列,若是空间不够,就换一行从左到右依次排列2.块级元素另起一行,从上到下占满整行。
  • 脱离文档流的状况 父元素div高度变小 float position:absolute position:fixed 注意: position:relative没有脱离文档流,只是相对于以前的位置定位,原来的地方还占据位置。
  • 宽高固定居中套路: position:absolute;top:0;bottom:0;left:0;right:0;margin:auto;
  • 内联元素的padding 和margin只会影响宽度,可是不会影响高度,内联元素的高度只受line-height影响。

CSS4 icon:SVG

SVG:SVG实际上是一段代码,浏览器能够解析这段代码,将它变成图形 优势:能够渐变,不会失真,能够动

flex布局(css6)

我理解flex从两个方面去理解:

  1. 元素布局 主轴和交叉轴,弹性元素永远沿主轴排列
    /*容器上:*/
    flex-direction/* 弹性元素按主轴排列的方向*/
    flex-wrap/*nowrap | wrap | wrap-reverse,主轴排列不下,是否换行 。默认是nowrap不折行。不会溢出。元素的弹性伸缩*/
    flex-flow/*上面两个的缩写*/
    
    justify-content/* 主轴对齐方式,五个属性*/
    align-items/* 单行交叉轴的元素对齐方式。默认stretch(元素未在交叉轴上设置尺寸,将把交叉轴自动填满,有flex-start,end,center,baseline几个属性)*/
    align-content/*多行交叉轴的对齐方式。flex-wrap: wrap的时候。stretch(这几行在垂直方向上占满) | flex-start(这几行挤在上面) | flex-end(挤在下面) | center(挤在中间) | space-between | space-around */
    /*元素上:*/
    order/* 元素排列次序*/
    align-self/* 单个元素的align-items*/
    复制代码
  2. 元素伸缩 当容器为flex-wrap: nowrap;时,元素会伸缩。 在元素上写:
  • flex-shrink默认为1,按比例缩小,占满一行
  • flex-grow: 放大比例。默认为0,不放大。若是两个子元素flex-grow:3,flex-grow:2,那么意思就是剩下的空间按3:2分配。
  • flex-basis默认为为auto。若是有width,就由width决定,若是没有width,就由内容的宽度决定。
    • flex-basis有数值。忽略width,由flex-basis决定
    • flex-basis:0由内容宽度决定。由于他的优先级比width
  • flex是上面三个的缩写。
    • flex: 1 = flex: 1 1 0%之内容的大小(无论width是多少) 按比例放大或缩小,占满一行 -flex: auto = flex: 1 1 auto;考虑width, 按比例放大或缩小,占满一行
    • flex: none = flex: 0 0 auto; 不放大也不缩小,width是多少,就是多少经常使用于固定尺寸 不伸缩

calc()

width: calc(50% - 10px);

宽度100%会把父盒子撑破, 解决方法:

  1. box-sizing:border-box;
  2. width: calc(100% - 10px);

布局CSS7

segmentfault.com/a/119000001…

圣杯布局和双飞翼布局 是老的布局方式,2012年之前流行,如今已不流行,可是面试可能会考察到. why it?

  • 是三列布局,两边固定宽度,中间自适应
  • 中间内容元素在 dom 元素次序中优先位置

原理:实际上都用了浮动和负边距的特性。 双飞翼实现方法: 1先所有fl 2main width100% 3 左边的一块 margin-left: -100%; /4/ 右边的一块 margin-left: -150px; /5/ 4.main.wrap{ margin-left: 100px; /6/ margin-right: 150px; /6/ background: blue; /7/ height: 350px; /7/ } 双飞翼:js.jirengu.com/fevifumike/…

CSS8:到底什么是BFC?

内部元素彻底包起来(float等),外部元素界限分明,不重叠。

面试官问的时候就说:

  1. 首先一个BFC能够包住浮动元素,不让他超过边界(但这不是清除浮动,清除浮动用clearfix),即便是子元素的margin也能够包住,不冲出父元素。好比举一个代码的例子,儿子是浮动元素,那么只要在爸爸上写overflow:hidden;或者overflow:auto;或者diaplay:flow-root;那么爸爸就会包住儿子,且margin也会在爸爸里面)
  2. 让两个相邻的BFC界限分明。 举个例子: 两个div是是兄弟关系,若是哥哥浮动了,那么哥哥会叠在弟弟上面,会遮盖弟弟。这时候若是把弟弟也变成BFC,那么哥哥和弟弟之间就会界限分明,谁都不会遮挡谁。

移动端开发

响应式两点:(CSS5)

  1. 媒体查询:
    @media (max-width: 768px){/*0-768*/
                body{
                    background-color: blue;
                }
            }
    
            @media (max-width: 425px){/*0-425*/
                body{
                    background-color: red;
                }
            }
    复制代码
    2.加上meta viewport历史缘由:最开始手机浏览器(苹果三)会在本身的三四百像素的手机上模拟980像素的显示效果,而后让用户本身去缩放,查看网页. 那么就告诉浏览器不要缩放网页,手机屏幕是多少像素,就显示多少像素的网页.使用下面的代码
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    复制代码

手机端什么CSS属性均可以用,不用考虑兼容的问题

CSS9动态 REM

动态 REM是手机专用,是如何适配全部手机的方案。 em:一个m的宽度.若是面试官问,就说是一个汉字的宽度.这个单位是相对于font-size的 rem:root em,根元素的font-size.即 <html>font-size .rem是相对于html的font-size的.

在这里插入图片描述
vh:视口高度,总共100vh vw:视口宽度,总共100cw

pc端只须要选一个布局(flex或者float),而后定宽就能够了。可是手机端不行,由于屏幕太多了 解决方法:

  1. 使用百分比布局。(缺点:高度没法使用百分比)
  2. 使用vw,vh。(缺点是兼容性很差)
  3. 使用动态 REM总体缩放

动态rem: 由于rem这个单位跟<html>标签的font-size挂钩。那么用js<html>标签的font-size页面宽度挂钩(pagewidth),那么rem这个单位就间接地与页面宽度挂钩了。

<head>
  <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <title>动态REM</title> <script> var pageWidth = window.innerWidth document.write('<style>html{font-size:'+pageWidth/10+'px;}</style>') </script> </head> 复制代码

而后布局等大单位就用rem,可是border,font-size等小单位,还用px便可,由于这些单位就算统一,在任何手机上的表现都没有多少影响。

这样写以后,10rem就是页面宽度。这样就能够总体按比例缩放了。

JS

&&和||

&&,他的返回值就是遇到的第一个falsy值,后面的不看了 1&&2&&3&&0&&2&&3 返回0,后面的不运行。 ||,他返回的就是第一个遇到的true值,后面的不看 0||0||0||false||1||2||0返回1,后面的不运行。

七个数据类型

七种数据类型分为六个基本类型和对象。 六个基本类型分别是nullundefinedstringnumberbooleansymbol 对象又分为objectfunctionarray

null和undefined的区别

相同点:if里都是都是false值

不一样点:

  1. null转换为数字的时候是0undefined表示未定义转换为数字的时候是NaN

  2. 调用函数时,某个参数未设置任何值,这时就能够传入null,表示该参数为空。而传入undefined就表明undefined

typeof

yuchengkai.cn/docs/zh/fro… typeof只须要记住两点

  • typeof 对于基本类型,除了 null 显示为 object,其他均可以显示正确的类型
  • typeof 对于对象,除了函数为function都会显示object
  • typeof运算符只能显示数组的类型是Object,而Array.isArray(arr)方法能够识别数组

六个false值

除了下面六个值被转为false,其余值都视为true

undefined
null
false
0
NaN
""''(空字符串)
复制代码

NaN

NaN === NaN;        // false
typeof NaN//number
复制代码

for in 和forEach

for in 遍历对象

for in循环注意点

for(var key in person){
    console.log(person.key)
}
复制代码

注意:person.key 等于 person['key'] 要用 这里遍历要用person[key]

for... in可能会随机遍历,不按照声明顺序

forEach遍历数组

var arr=[1,2,3]
arr.forEach(function(e){
	console.log(e)
})
//1 2 3

复制代码

阿斯蒂

其余类型转换为String

  • nullundefined没有tostring()方法。只能null+''undefined+''
  • 其余的用.toString()方法。或直接+''。或者window.String()方法

其余类型转换为Number(主要是String)

五个方法

在这里插入图片描述

  • 简便方法'1234'-0(经常使用)
  • .parseInt()//默认十进制
  • 简便方法二+'1'取正

其余类型转换为Boolean(五个false值)

记住5个false值 null undefined NaN 0 ''

记住下面易错点:

[]//ture
{}//ture
' '//ture 里面有空格
复制代码

转换方法两个:

  • window.Boolean(xxx)
  • 前面加上!!xxx

内存

  • 数据区(存的变量的数据)分为 Stack(栈内存) 和 Heap(堆内存)
  • 简单类型的数据直接存在 Stack 里
  • 复杂类型的数据是把 Heap 地址存在 Stack 里(对象包括:狭义对象(object),函数(function),数组(array))

关于内存的面试题

引用: 一个广义对象(object,array,function) 例如 var a= {xxx:'xxx'} a存的是{xxx:'xxx'}这个广义对象的地址,假如是10000。那么a(或a存的地址10000)就是这个对象({xxx:'xxx'})的引用

var a = 1 var b = a b = 2 请问 a 显示是几? 2 1 (深拷贝)

var a = {name: 'a'}
var b = a
b = {name: 'b'}
复制代码

请问如今 a.name 是多少? 'a'

在这里插入图片描述

var a = {name: 'a'}
var b = a
b.name = 'b'
复制代码

请问如今 a.name 是多少? 'b'

在这里插入图片描述

var a = {name: 'a'}
var b = a
b = null
复制代码

请问如今 a 是什么? {name: 'a'}

****

GC垃圾回收

若是一个对象没有被引用,他就是垃圾,就会被回收(没有引用找不到他,因此要回收)

在这里插入图片描述
{name:'a'}就是垃圾,就要被 回收释放内存
在这里插入图片描述
在这里插入图片描述
不会回收,由于 document.body.onclick这个 引用在栈内存中存了fu这个函数的 地址

内存泄漏:在ie6的时候,若是关闭页面,一些垃圾是没有被清除,内存被永久的占用了

深拷贝

  • 首先:值的存储方法:两种。基础类型六个存入stack****栈内存,复合类型对象存入heap****堆内存

因此:

  • 对于六个基本数据类型来讲,直接赋值就是深拷贝,由于他们直接存在栈内存里。
  • 可是若是吧旧的对象赋值给新声明的对象,那么实际上只是把栈内存里的地址赋值给了新对象,实际上堆内存里仍然是原来的对象,若是修改新对象里面的属性,那么原来的对象也会改变,由于用的是同一块堆内存。直接给新对象赋值,没法实现拷贝。

如何实现对象的浅与深拷贝?

  1. 对象浅拷贝
  • 浅拷贝 首先能够经过Object.assign 来解决这个问题。
    let a = {
        age: 1
    }
    let b = Object.assign({}, a)
    a.age = 2
    console.log(b.age) // 1
    复制代码
    Object.assign()只拷贝第一层,若是属性存的是一个引用,那么他也只拷贝到引用。因此是浅拷贝
  • 深拷贝 深拷贝 这个问题一般能够经过JSON.parse(JSON.stringify(object))来解决。
let a = {
    age: 1,
    jobs: {
        first: 'FE'
    }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
复制代码

可是该方法也是有局限性的:

  • 会忽略 undefined
  • 不能序列化函数
  • 不能解决循环引用的对象 可是能够解决大部分问题。

做用域

JavaScript有函数级做用域,仅仅函数能建立新做用域。

变量的做用域表示这个变量存在的上下文

setTimeout中的函数所处在于全局做用域中,因此函数中使用this关键字时,这个this关键字指向的是全局对象window

变量提高

两个题目

var foo = 1;
function bar() {
    if (!foo) {
        var foo = 10;
    }
    alert(foo);
}
bar();
复制代码

答案是10

第二个例子

var a = 1;
function b() {
    a = 10;
    return;
    function a() {}
}
b();
alert(a);
复制代码

alert输出了1

变量提高后的顺序 提高时代码表现上的排序为:

1 var a;
2 function f (){}
3 形参
4 thisarguments
复制代码

总结: var 声明变量,只会提高var a=undefined(自动赋值为undefined)。 function声明函数,function f (){},全部的都会提高。

let与const暂时死区

{ console.log(x) // Uncaught ReferenceError: x is not defined let x = 1 } let x = 1以前到花括号{,就是x的暂时死区,不用使用变量x,const同样

instanceof

instanceof运算符用来验证,一个对象是否为指定的构造函数实例obj instanceof Object返回true,就表示obj对象是Object的实例。

标准库

api太多

new

  1. 使用new命令时,它后面的函数依次执行下面的步骤。

    1. 建立一个空对象,做为将要返回的对象实例。
    2. 将这个空对象的原型,指向构造函数的prototype属性。
    3. 将这个空对象赋值给函数内部的this关键字。
    4. 开始执行构造函数内部的代码。

既:

  1. 新生成了一个对象(新生成一个临时对象)
  2. 连接到原型(新生成的对象 新对象.__proto__=构造函数.prototype
  3. 绑定 this ( this = 新对象)
  4. 返回新对象 new应用举例:

第一步写私有属性,第二步写共有属性.

P4gxL4.png

能够看到这个对象的

在这里插入图片描述
1自有属性 2__proto__指向的原型对象含有共有属性. 3 共共有属性(原型的属性)constructor指向的构造函数

ES5的Object.create()

现有的对象做为模板,生成实例对象,这时就可使用Object.create()方法。

var person1 = {
  name: '张三',
  age: 38,
  greeting: function() {
    console.log('Hi! I\'m ' + this.name + '.');
  }
};

var person2 = Object.create(person1);

person2.name // 张三
person2.greeting() // Hi! I'm 张三.
复制代码

this

this的实质:

  • 引擎会将函数单独保存在内存中,而后再将函数的地址赋值给变量。
  • 因为函数是一个单独的值,因此它能够在不一样的**环境(上下文)**执行。
  • JavaScript 容许在函数体内部,引用当前环境的其余变量。
  • 如今问题就来了,因为函数能够在不一样的运行环境执行,因此须要有一种机制,可以在函数体内部得到当前的运行环境(context)。因此,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境

总结一句话:this就是指函数所在的当前环境(既所在的对象)

this:

  • 在构造函数里,this 表明新生成的实例对象
  • 其余状况下,this就是属性方法当前”所在的对象。它老是返回一个对象

面试回答:;

  1. fn() 里面的 this 就是 window(fn在最顶层)
  2. fn()strict modethis 就是 undefined(fn在最顶层,严格模式下是undefined)
  3. a.b.c.fn() 里面的 this 就是 a.b.c(属性或方法当前所在的对象。)
  4. new F() 里面的 this 就是新生成的实例
  5. () => console.log(this) 里面 this 跟外面的 this 的值如出一辙(ES6新增语法)(箭头函数里,this就上一层的this的值) 面试答上面的几个↑

面试回答call() apply() bind(): 1 call()方法,能够指定函数内部this指向(即函数执行时所在的做用域),而后在所指定的做用域中调用该函数。 (这个所指定的做用域意思就是所指定的对象)

var obj = {};

var f = function () {
  return this;
};

f() === window // true
f.call(obj) === obj // true
复制代码

call后面的参数则是函数调用时所需的参数

2 apply()call()惟一的区别就是,它接收一个数组做为函数执行时的参数。

x.call(obj,1,2,3)
    x.apply(obj,[1,2,3])
复制代码

3 bind方法用于将函数体内的this绑定到某个对象,而后返回一个新函数callapply都是绑定新this直接执行函数,而bind没有执行,而是返回新函数,这个在一函数做为参数的一些方法里就用bind

this面试题 带call的面试题遵循如下两个规则

  1. 若是call传了参数,this就是传的参数。

    在这里插入图片描述
    在这里插入图片描述

  2. 若是call没传参数或者为undefined,那么this是window(飞严格模式),或者undefined(严格模式)

    在这里插入图片描述

    在这里插入图片描述

带call的面试题仍然遵循规则 3.

在这里插入图片描述
4.
在这里插入图片描述

记住了,当call()的第一个参数是undefined的时候, thiswindow.

this面试题 this题目

在这里插入图片描述

答案: 调用B处的console.log().结果是options window(console.log()中console是全局window对象里的一个方法)

第二题:

PhftrF.md.png

答案:D Object

第三题:

PhfLZQ.md.png

答案:Object

JS 原型是什么?

举例

  1. var a = [1,2,3]
  2. 只有0、一、二、length 4 个key
  3. 为何能够a.push(4)push 是哪来的?
  4. a.__proto__ === Array.prototype(a是实例数组对象,Array是构造函数)
  5. push函数 就是沿着 a.__proto__ 找到的,也就是 Array.prototype.push
  6. Array.prototype 还有不少方法,如joinpopslicespliceconcat
  7. Array.prototype 就是 a 的原型(proto)

聚完例子后用new对象举例,说给面试官听: 比若说

  1. 咱们新建立一个构造函数

    function Person() {}
    复制代码
  2. 而后根据构造函数构造一个新对象

    var person1 = new Person();
     ``` 复制代码
  3. 每一个函数都有一个 prototype 属性,这个构造函数prototype 属性指向了一个对象,这个对象调用该构造函数而建立的实例原型

  4. 当咱们给Personprototypename属性赋值为'Kevin'

    Person.prototype.name = 'Kevin';
    var person1 = new Person();
    var person2 = new Person();
    console.log(person1.name) // Kevin
    console.log(person2.name) // Kevin
    复制代码

    每个新的实例对象对象都会从原型"继承"属性,实例对象拥有该原型的全部属性。

  5. 说白了,原型就是 构造函数 用来 构造 新实例 的 模板对象。

  6. 这就是原型。 开始解释原型链 那么咱们该怎么表示实例实例原型,也就是 person1 和 Person.prototype 之间的关系呢,这时候咱们就要讲到第二个属性__proto__

什么是原型链?

先回答什么是原型。在上面,而后继续从__proto__开始往下说。

说:

  1. JavaScript对象除了 null 都具备的一个属性,叫__proto__,这个属性会指向该对象的原型对象。

  2. 当读取实例的属性时,若是找不到,就会经过__proto__查找原型中的属性,若是还查不到,就去找原型原型

  3. 例如Person.prototype这个原型的原型就是Object这个构造函数的prototype,既Object.prototype这个原型对象。而后,Person.prototype.__proto__就指向Object.prototype这个原型。而后Object.prototype原型是null

  4. 这些原型对象经过__proto__像链子同样连起来,就叫作原型链。 而后给面试官画:

链子上都画上__proto__ person1----->Person.prototype----->Object.prototype----->null

Array.prototype----->Object.prototype----->null

在这里插入图片描述

实例的.__proto__ 指向构造函数. prototype(原型对象) 面试题:

Number.prototype.__proto__ === Object.prototype
//true
String.prototype.__proto__ === Object.prototype
//true
Boolean.prototype.__proto__ === Object.prototype
//true
Array.prototype.__proto__ === Object.prototype
复制代码
//同理
Function.prototype.__proto__=== Object.prototype//true
复制代码

关于 Function只需记住下面: 构造函数的原型:

String.__proto__===Function.prototype//true
Number.__proto__===Function.prototype//true
Boolean.__proto__===Function.prototype//true

Object.__proto__ === Function.prototype//true
复制代码

特殊的:

Function.__proto__===Function.Prototype//true
复制代码

constructor

每个构造函数的prototype属性都指向原型对象。 每个原型对象的constructor属性都指向构造函数。 原型对象

在这里插入图片描述

console.log(Person === Person.prototype.constructor); // true
复制代码

Array注意点、伪数组

  • 大BUG:var a = Array(3) 一个参数,且参数为数字,那么久声明数组长度为3的空数组

    在这里插入图片描述

    var a = Array(3,3) 两个参数以上的时候,里面的参数都是数组内部的值。 因此声明数组不要用new Array()的方法。

  • 数组本质上是一个对象。

  • 数组能够用for i和for in循环

  • 伪数组:

    • 伪数组实际是一个对象,他的__proto__指向Object.prototype,没有pop push等方法
    • 它里面的属性都是数字(内容是函数所传进来的参数)和一个length
    • JS里面只有一个伪数组arguments,表明函数里面所传入的全部的参数。
    • 在这里插入图片描述
  • forEach

    [1,2,3].forEach(function(value,index){
    			 		   console.log(value)
    			  		   console.log(index)
    	 			})
    复制代码
  • sort&join&concat&map&filter&reduce segmentfault.com/a/119000001…

DOM

  • 什么是DOM?

    • DOM 是 JavaScript 操做网页的接口,全称为“文档对象模型”。
    • 它的做用是将网页转为一个 JavaScript 对象,从而能够用JS进行各类操做(好比增删内容)。
  • 什么是DOM树?

    • 浏览器会根据 DOM 模型,将文档解析成节点。此后HTML中的每一个标签元素属性文本都能看作是一个DOM的节点
    • 再由这些节点组成一个树状结构(DOM Tree)。
    • 最后提供操做这个树的各类方法
  • Javascript操做DOM经常使用API总结http://luopq.com/2015/11/30/javascript-dom/

在这里插入图片描述
www.cnblogs.com/Ry-yuan/p/6…

在这里插入图片描述
5Document.querySelector()

6Document.querySelectorAll()

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

函数题目

函数声明的五种方式

在这里插入图片描述

注意其中一种方式:

在这里插入图片描述

  • 函数的name
1具名函数
 function f(x,y){
     return x+y
 }
 f.name // 'f'
 
2匿名函数
 var f
 f = function(x,y){
     return x+y
 }
 f.name // 'f'
 
3具名函数赋值
 var f
 f = function f2(x,y){ return x+y }
 f.name // 'f2'
 console.log(f2) // undefined
 
4window.Function
 var f = new Function('x','y','return x+y')
 f.name // "anonymous"
 
5箭头函数
 var f = (x,y) => {
     return x+y
 }

f.name//"f"
复制代码

只要记住三、4两种特殊的状况就好。

  • this
    • 特例:当call()的第一个参数是undefined的时候, this 是 window.
    • 当启用严格模式的时候,call 里的第一个参数是什么,this 就是什么
  • 函数的调用栈:执行的时候函数进入栈return的时候函数弹出栈
  • Stack Overflow堆栈溢出,超出call stack 函数调用栈。

当即执行函数

做用:建立一个独立的做用域,避免变量污染

(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
//下面的都是执行这个表达式,而无论返回值是什么
!function(){alert('我是匿名函数')}() 
复制代码

另外一种建立独立做用域的方法是使用let

做用域链

题目:

var a = 1
function f1(){
  var a = 2
  console.log(a)
  f4()
  
}
function f4(){
  console.log(a)
}

f1()
复制代码

答案,2,1 这个f4里面的a只能是他本身自己的做用域他的父做用域,跟f1里面的a没有关系 先看面试题 题目1

var a = 1
function fn1(){
  function fn2(){
    console.log(a)
  }
  function fn3(){
    var a = 4
    fn2()
  }
  var a = 2
  return fn3
}
var fn = fn1()
fn() //2
复制代码

题目2

var a = 1
function fn1(){
  function fn3(){
    var a = 4
    fn2()
  }
  var a = 2
  return fn3
}
function fn2(){
  console.log(a)
}
var fn = fn1()
fn() //1
复制代码

题目3

var a = 1
function fn1(){

  function fn3(){
    function fn2(){
      console.log(a)
    }
    var a

    fn2()
    a = 4
  }
  var a = 2
  return fn3
}
var fn = fn1()
fn() //undefined
复制代码

解密

  1. 函数在执行的过程当中,先从本身内部找变量
  2. 若是找不到,再从建立当前函数所在的做用域去找, 以此往上
  3. 注意找的是变量的当前的状态

异步函数的经典题

在这里插入图片描述
下面代码打印出的是6 由于setTimeout是 异步函数,主线程的同步任务执行完毕,异步任务才从任务队列里拿出来执行。 即便时间是0,他也是异步的。也要等到全部代码解析完。等代码解析完毕,i已是6了。

在这里插入图片描述
上面这个同理,当我点击按钮的时候,点击事件才触发(异步),至关因而js早就解析完了代码,i已经变成6了,才执行事件绑定, 事件绑定与触发都是 异步的

闭包经典面试题

经典面试题,循环中使用闭包解决 var 定义函数的问题

for ( var i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, i*1000 );
}
首先由于 setTimeout 是个异步函数,全部会先把循环所有执行完毕,这时候 i 就是 6 了,因此会输出一堆 6。

解决办法两种,第一种使用闭包(建立的这个当即执行函数就是一个新块级做用域,并使用了外部的变量i,解析完以后,也不随着i的最终改变而改变)+当即执行函数

for (var i = 1; i <= 5; i++) {
  (function(j) {
    setTimeout(function timer() {
      console.log(j);
    }, j * 1000);
  })(i);
}


第三种就是使用 let 定义 i 了

for ( let i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, i*1000 );
}
由于对于 let 来讲,他会建立一个块级做用域,至关于刚才的闭包建立的块级做用域。
复制代码

===

=== 而不用==。只须要注意两点

  1. NaN ===NaN//false
  2. 全部即便是内容同样的对象=== 也都是false 。由于地址不同。

轮播

  • 高级轮播 // 第一步,循环给按钮添加点击事件 //第二步:添加定时器,定时出发,循环轮播,而且进入时暂停轮播 jsbin.com/funumujoqe/…

  • 无缝轮播 说思路就好了,而后说我在工做的时候都不手写录播,主要是为了理解他的原理,而后用别人写好的轮播库swiper,这样工做中的BUG会少一点。

回调函数

callback 是一种特殊的函数,这个函数被做为参数传给另外一个函数去调用。这样的函数就是回调函数。 举一个Callback(回调函数)的例子 ,例如:

$button.on('click', function(){})
div.addEventListener('click', function(){})
复制代码

click 后面的 function 是一个回调,由于「我」没有调用过这个函数,是浏览器在用户点击 button 时调用的。

再举一个使用回调函数的例子

function setClock(callBack){
  console.log('1定一个闹钟,三秒钟以后响');
  setTimeout(()=>{
    console.log('2三秒到了,闹钟响了!');
    callBack();
  },3000)
}

function getUp(){
  console.log('3闹钟已经响了,该起床了')
}

setClock(getUp);
复制代码

回调函数通常只和**异步操做(setTimeOut)**在一块儿才使用!!!

什么是异步

1单线程模式

JavaScript 只在一个线程上运行,JavaScript 同时只能执行一个任务其余任务都必须在后面排队等待

2同步任务(synchronous)和异步任务(asynchronous)

同步任务主线程上排队执行的任务。只有前一个任务执行完毕,才能执行后一个任务。

异步任务不进入主线程、而进入任务队列的任务。只有引擎认为某个异步任务能够执行了(好比 Ajax 操做从服务器获得告终果,或者setTimeOut到时间了(事件循环)),该任务(采用回调函数的形式)才会进入主线程执行

3任务队列和事件循环

JavaScript 运行时,除了一个正在运行的主线程,引擎还提供一个任务队列(task queue),里面是各类须要当前程序处理的异步任务。

首先,主线程会去执行全部的同步任务。等到同步任务所有执行完,就会去看任务队列里面的异步任务。若是知足条件,那么异步任务就从新进入主线程开始执行,这时它就变成同步任务了。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。

异步任务的写法一般是回调函数。一旦异步任务从新进入主线程,就会执行对应的回调函数。若是一个异步任务没有回调函数,就不会进入任务队列,也就是说,不会从新进入主线程,由于没有用回调函数指定下一步的操做。

JavaScript 引擎怎么知道异步任务有没有结果,能不能进入主线程呢?答案就是引擎在不停地检查,一遍又一遍,只要同步任务执行完了,引擎就会去检查那些挂起来的异步任务,是否是能够进入主线程了。这种循环检查的机制,就叫作事件循环(Event Loop)。

问关于异步、主线程、事件循环(Event Loop)的时候:按照下面回答: 面试官问问题:js是单线程模式的,那么他是怎么实现异步操做的? 答:

  1. js里面的任务分为同步任务异步任务
  2. 同步任务进入主线程一个一个得执行。异步任务进入任务队列,等同步任务执行完了以后,只有触发了某个条件,才把任务队列里面的任务放到主线程执行(好比ajax获得返回的数据,就开始执行回调函数,setTimeOut的时间到了,就执行回调函数)
  3. 异步任务的写法一般是回调函数。一旦异步任务从新进入主线程,就会执行对应的回调函数。
  4. 同步任务执行完以后引擎就一遍一遍得检查。JavaScript 引擎怎么知道异步任务有没有结果,能不能进入主线程呢?答案就是引擎在不停地检查,一遍又一遍,只要同步任务执行完了,引擎就会去检查那些挂起来的异步任务,是否是能够进入主线程了。这种循环检查的机制,就叫作事件循环(Event Loop)。事件循环机制一遍一遍得检查,符合条件,就把异步任务放到主线程里面去执行(好比ajax返回的数据到了,setTimeOut里面的时间到了)

异步操做的方法: 1.回调函数 2.事件监听(触发条件,执行回调函数) 3.ES6:Promise

定时器

它们向任务队列添加定时任务。时间到就添加,而后事件循环就会扫到,扫到了就执行里面的回调函数

Promise

什么是Promise? 举例: $.ajax().then(成功函数,失败函数)

做用:避免回调嵌套,使回调变的可控

ES6划入标准标准。Promise如今是js的内置对象。Promise 对象是 JavaScript 的异步操做的解决方案。Promise 可让异步操做写起来,就像在写同步操做的流程,(链式使用,then以后能够继续then)而没必要一层层地嵌套回调函数

写一个Promise异步操做解决方案

function dosomething(){
    // Promise 接受函数做为参数两个参数,
    // resolve: 异步事件成功时调用
    // reject: 异步事件失败时调用
    return new Promise((resolve, reject) => {
        let result = 异步操做()
	// 下面给出承诺,面对不一样的结果,我会 执行 不一样的解决方案
	if (result === 'success') 
	    resolve('成功数据')
	else 
	    reject('失败数据')
	})
}

// 异步操做,模拟几率事件
function 异步操做() {
    return Math.random() > 0.5 ? 'success' : 'fail'
}

// 你在dosomething

dosomething()
    // 异步操做成功了,那么咱们打印成功的数据
    .then(res => console.log(res))
    // 异步操做失败了,那么咱们打印失败的数据
    .catch(res => console.log(res))
复制代码

Sync:同步的意思 Async:异步的意思

MVC与模块化

传统模块化方法:

  1. 使用window
    //module1.js
    !function(){
        var person = window.person = {
            name:"frank",
        }
        //局部变量person和全局变量person用的是同一个地址
    }.call()
    复制代码
    虽然不一样变量,可是是一样的地址
    //module2.js
    !function(){
        var person = person;//即var person = window.person;
        console.log(person);
    }.call();
    复制代码
  2. 使用闭包
//module1.js
!function(){
    var person = {
        name:"mataotao",
        age:18,
    };
    window.mataotaoGrowUp = function(){
        person.age+=1;
        return person.age;
    };
}.call();
复制代码
//module2.js
!function(){
    var newAge = window.mataotaoGrowUp();
    console.log(newAge);//19
}.call();
复制代码

用闭包的好处:

  • 用来 隐藏数据细节 (不告诉你多少岁可是你可让他涨一岁,隐藏了age 的细节和name)
  • 能够用来 作访问控制 (只能访问到age,没法访问到name)
相关文章
相关标签/搜索