前端面试题第一章

1.js的基础数据类型

  • undefined
  • boolean
  • null
  • number
  • string
  • array
  • object

2.css选择器

  • 基本选择器

    • 元素选择器
    • 类选择器
    • ID选择器
    • 属性选择器
    • 通配选择器
  • 组合选择器

    • 相邻兄弟选择器
    • 普通兄弟选择器
    • 子选择器
    • 后代选择器
  • 伪元素

  • 标准伪类

(1)元素选择器

<div></div>
<div></div>
div{
}

(2)类选择器
<div class="info"></div>

.info{
}

(3)ID选择器

<div id="info"></div>
#info{
}

(4)属性选择器
[attr]
表示带有以 attr 命名的属性的元素。

[attr=value]
表示带有以 attr 命名的,且值为”value”的属性的元素。

[attr~=value]
表示带有以 attr 命名的属性的元素,并且该属性是一个以空格作为分隔的值列表,其中至少一个值为”value”。

[attr|=value]
表示带有以 attr 命名的属性的元素,属性值为“value”或是以“value-”为前缀(”-“为连字符,Unicode编码为U+002D)开头。典型的应用场景是用来来匹配语言简写代码(如zh-CN,zh-TW可以用zh作为value)。

[attr^=value]
表示带有以 attr 命名的,且值是以”value”开头的属性的元素。

[attr$=value]
表示带有以 attr 命名的,且值是以”value”结尾的属性的元素。

[attr*=value]

表示带有以 attr 命名的,且值包含有”value”的属性的元素。

作者:若即
来源:CSDN
原文:https://blog.csdn.net/qq_17004327/article/details/78010823
版权声明:本文为博主原创文章,转载请附上博文链接!

<div id="info" style="color:red;" title='flowerssss' lang='en'></div>
[color]{
}
[color=red]{
}
[title~=flower]{
}
[lang|en]{
}

(5)通配选择器

*{
}

(6)相邻兄弟选择器

<!--兄弟选择器测试-->
<div id="b1">brother 1</div>
<div id="b2">brother 2</div>
<div id="b3">brother 3</div>
<div id="b4">brother 4</div>
/*相邻兄弟选择器测试*/
#b1 + #b2{
    color:red;
}

#b1 + #b4{
    color:red;
}
/*普通兄弟选择器*/
#b1 ~ #b2{
    color:red;
}
#b1 ~ #b4{
    color:red;
}

(7)子代/后代选择器

<!--子代/后代选择器测试-->
<ul id="parent">
    <li>
        <ul>
            <li>grandson - 1</li>
            <li>grandson - 2</li>
        </ul>
    </li>
    <li>son -1</li>
    <li>son -2</li>
</ul>
--------------------- 
作者:若即 
来源:CSDN 
原文:https://blog.csdn.net/qq_17004327/article/details/78010823 
版权声明:本文为博主原创文章,转载请附上博文链接!
/*子代选择器测试  选择父元素为parent的li*/
ul{
    color: black;
}

#parent > li{
    color: red;
}
/*后代选择器测试 选择parent内所有的li元素*/
ul{
    color: black;
}

#parent  li{
    color: red;
}
/*紧接在div之后的所有p元素*/
div+pi{
    color: red;
}

(7)伪元素(伪对象):用于向某些选择器设置特殊效果
伪元素的语法:

selector:pseudo-element {property:value;}

CSS 类也可以与伪元素配合使用

selector.class:pseudo-element {property:value;}

:first-line 伪元素
“first-line” 伪元素用于向文本的首行设置特殊样式。
在下面的例子中,浏览器会根据 “first-line” 伪元素中的样式对 p 元素的第一行文本进行格式化:

 p:first-line {
  color:#ff0000;
  font-variant:small-caps;
  }

注释:“first-line” 伪元素只能用于块级元素。

注释:下面的属性可应用于 “first-line” 伪元素:

font
color
background
word-spacing
letter-spacing
text-decoration
vertical-align
text-transform
line-height
clear

:first-letter 伪元素
“first-letter” 伪元素用于向文本的首字母设置特殊样式:

p:first-letter
  {
  color:#ff0000;
  font-size:xx-large;
  }

注释:“first-letter” 伪元素只能用于块级元素。

注释:下面的属性可应用于 “first-letter” 伪元素:

font
color
background
margin
padding
border
text-decoration
vertical-align (仅当 float 为 none 时)
text-transform
line-height
float
clear

使所有 class 为 article 的段落的首字母变为红色。

p.article:first-letter
  {
  color: #FF0000;
  }

<p class="article">This is a paragraph in an article。</p>

多重伪元素
可以结合多个伪元素来使用。

在下面的例子中,段落的第一个字母将显示为红色,其字体大小为 xx-large。第一行中的其余文本将为蓝色,并以小型大写字母显示。段落中的其余文本将以默认字体大小和颜色来显示:

//第一行的第一个字母
p:first-letter
  {
  color:#ff0000;
  font-size:xx-large;
  }
//第一行
p:first-line
  {
  color:#0000ff;
  font-variant:small-caps;
  }

“:before” 伪元素可以在元素的内容前面插入新内容。

下面的例子在每个<h1> 元素前面插入一幅图片:

h1:before
  {
  content:url(logo.gif);
  }

“:after” 伪元素可以在元素的内容之后插入新内容。

下面的例子在每个<h1>元素后面插入一幅图片:

h1:after
  {
  content:url(logo.gif);
  }

(8)标准伪类

伪类 用途
:link a连接标签的未被访问的样式
:hover 随想在鼠标移上时的样式
:active 对象被用户点击及被点击释放之间的样式
:visited a链接对象被访问后的样式
:focus 对象成为输入焦点时的样式
:first-child 对象的第一个子对象的样式
:first 对于页面的第一页使用的样式

(9)奇偶选择:
nth-of-type与nth-child都是伪类选择器,都能选择父元素下的直接子元素
例子:

/*选奇数行*/
ul li:nth-of-type(odd){}
p:nth-child(odd){}
/*选偶数行*/
ul li:nth-of-type(even){}
p:nth-child(even){}

区别:
nth-of-type主要根据type来选择,nth-child着重的是子元素

<p class='nthtype'>
    <h1>1</h1>
    <h1>2</h1>
    <p>3</p>
    <h1>4</h1>
    <h1>5</h1>
</p>
<p class='nthchild'>
    <h1>1</h1>
    <h1>2</h1>
    <p>3</p>
    <h1>4</h1>
    <h1>5</h1>
</p>
p h1:nth-of-type(n){}
p h1:nth-child(n){}
n=1,2时,两种分别取的1和2
n=3时,nthtype取的是4,nthchild取的是3

由上个例子可知,nth-of-type根据类型选择子元素,nth-child没有类型限制,只是根据参数取子元素

3.position

positon有关的问题主要是问的是有哪几种定位方式一级各种定位方式的参考。position一共有五种定位方式分别是static,relative,absolute,fixed,sticky其中sticky是实验方式

static
该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。
relative
相对定位的元素是在文档中的正常位置偏移给定的值,但是不影响其他元素的偏移。
absolute
相对定位的元素并未脱离文档流,而绝对定位的元素则脱离了文档流。在布置文档流中其它元素时,绝对定位元素不占据空间。绝对定位元素相对于最近的非 static 祖先元素定位。当这样的祖先元素不存在时,则相对于根级容器定位。
fixed
固定定位与绝对定位相似,但元素的包含块为 viewport 视口。该定位方式常用于创建在滚动屏幕时仍固定在相同位置的元素。

4.css水平垂直居中

1.知道高宽

   div{
            width: 200px;
            height: 200px;
            background: green;
            position:absolute;
            left:0;
            top: 0;
            bottom: 0;
            right: 0;
            margin: auto;
        }
    div{
            width:200px;
            height: 200px;
            background:green;
            position: absolute;
            left:50%;
            top:50%;
            margin-left:-100px;
            margin-top:-100px;
        } 
    div{
            width: 200px;
            height: 200px;
            background: green;
            position:absolute;
            left:50%;    /* 定位父级的50% */
            top:50%;
            transform: translate(-50%,-50%); /*自己的50% */
        } 

2.不定高宽

      .box{
             height:600px;
             display:flex;
             justify-content:center;
             align-items:center;
               /* 只要三句话就可以实现不定宽高水平垂直居中。 */
        }
        .box>div{
            background: green;
            width: 200px;
            height: 200px;
        }

3.将父盒子设置为table-cell元素,可以使用text-align:center和vertical-align:middle实现水平、垂直居中。比较完美的解决方案是利用三层结构模拟父子结构。

<p class="outerBox tableCell"></p>
<p class="ok">
    <p class="innerBox">tableCell</p>
</p>
 
/*
table-cell实现居中
将父盒子设置为table-cell元素,设置
text-align:center,vertical-align: middle;
子盒子设置为inline-block元素
*/
.tableCell{
  display: table;
}
.tableCell .ok{
  display: table-cell;
  text-align: center;
  vertical-align: middle;
}
.tableCell .innerBox{
  display: inline-block;
}

4.对子盒子实现绝对定位,利用calc计算位置

<p class="outerBox calc">
    <p class="innerBox">calc</p>
</p>


/*绝对定位,clac计算位置*/
.calc{
  position: relative;
}
.calc .innerBox{
  position: absolute;
  left:-webkit-calc((500px - 200px)/2);
  top:-webkit-calc((120px - 50px)/2);
  left:-moz-calc((500px - 200px)/2);
  top:-moz-calc((120px - 50px)/2);
  left:calc((500px - 200px)/2);
  top:calc((120px - 50px)/2);
}

5.数组的常用方法

1.Array.map()
此方法是将数组中的每个元素调用一个提供的函数,结果作为一个新的数组返回,并没有改变原来的数组

    let arr = [1, 2, 3, 4, 5]
    let newArr = arr.map(x => x*2)
    //arr= [1, 2, 3, 4, 5]   原数组保持不变
    //newArr = [2, 4, 6, 8, 10] 返回新数组

2.Array.forEach()
此方法是将数组中的每个元素执行传进提供的函数,没有返回值,直接改变原数组,注意和map方法区分

   let arr = [1, 2, 3, 4, 5]
   arr = arr.forEach(x => x*2)
   // arr = [2, 4, 6, 8, 10]  数组改变,注意和map区分

3.Array.filter()
此方法是将所有元素进行判断,将满足条件的元素作为一个新的数组返回

    let arr = [1, 2, 3, 4, 5]
    const isBigEnough => value => value >= 3
    let newArr = arr.filter(isBigEnough )
    //newNum = [3, 4, 5] 满足条件的元素返回为一个新的数组

4.Array.every()
此方法是将所有元素进行判断返回一个布尔值,如果所有元素都满足判断条件,则返回true,否则为false

    let arr = [1, 2, 3, 4, 5]
    const isLessThan4 => value => value < 4
    const isLessThan6 => value => value < 6
    arr.every(isLessThan4 ) //false
    arr.every(isLessThan6 ) //true

5.Array.some()
此方法是将所有元素进行判断返回一个布尔值,如果存在元素都满足判断条件,则返回true,若所有元素都不满足判断条件,则返回false

    let arr= [1, 2, 3, 4, 5]
    const isLessThan4 => value => value < 4
    const isLessThan6 => value => value > 6
    arr.some(isLessThan4 ) //true
    arr.some(isLessThan6 ) //false

6.Array.reduce()
此方法是所有元素调用返回函数,返回值为最后结果,传入的值必须是函数类型:

   let arr = [1, 2, 3, 4, 5]
   const add = (a, b) => a + b
   let sum = arr.reduce(add)
   //sum = 15  相当于累加的效果
   与之相对应的还有一个 Array.reduceRight() 方法,区别是这个是从右向左操作的

7.Array.push()
此方法是在数组的后面添加新加元素,此方法改变了数组的长度:

    let arr = [1, 2, 3, 4, 5]
    arr.push(6)
    console.log(arr) //[1, 2, 3, 4,5,6]
    console.log(arr.length) //6

8.Array.pop()
此方法在数组后面删除最后一个元素,并返回数组,此方法改变了数组的长度

    let arr = [1, 2, 3, 4, 5]
    arr.pop()
    console.log(arr) //[1, 2, 3, 4]
    console.log(arr.length) //4

9.Array.shift()
此方法在数组后面删除第一个元素,并返回数组,此方法改变了数组的长度

    let arr = [1, 2, 3, 4, 5]
    arr.shift()
    console.log(arr) //[2, 3, 4, 5]
    console.log(arr.length) //4 

10.Array.unshift()
此方法是将一个或多个元素添加到数组的开头,并返回新数组的长度

    let arr = [1, 2, 3, 4, 5]
    arr.unshift(6, 7)
    console.log(arr) //[6, 7,1, 2, 3, 4, 5]
    console.log(arr.length) //7

11.Array.isArray()
判断一个对象是不是数组,返回的是布尔值
12.Array.concat()
此方法是一个可以将多个数组拼接成一个数组

  let arr1 = [1, 2, 3]
      arr2 = [4, 5]
  let arr = arr1.concat(arr2)
  console.log(arr)//[1, 2, 3, 4, 5]

13.Array.toString()
此方法将数组转化为字符串

   let arr = [1, 2, 3, 4, 5];
   let str = arr.toString()
   console.log(str)// 1,2,3,4,5

14.Array.join()
此方法也是将数组转化为字符串,以参数作为分隔符,将所有数组成员组成一个字符串返回。如果不提供参数,默认用逗号分隔

   let arr = [1, 2, 3, 4, 5];
   let str1 = arr.toString()
   let str2 = arr.join(',')
   let str3 = arr.join('##')
   console.log(str1)// 12345
   console.log(str2)// 1,2,3,4,5
   console.log(str3)// 1##2##3##4##5

通过例子可以看出和toString的区别,可以设置元素之间的间隔~

15.Array.splice(开始位置, 删除的个数,元素)
万能方法,可以实现增删改

     let arr = [1, 2, 3, 4, 5];
     let arr1 = arr.splice(2, 0 ,'haha')
     let arr2 = arr.splice(2, 3)
     let arr1 = arr.splice(2, 1, 'haha')
     console.log(arr1) //[1, 2, 'haha', 3, 4, 5]新增一个元素
     console.log(arr2) //[1, 2] 删除三个元素
     console.log(arr3) //[1, 2, 'haha', 4, 5] 替换一个元素

16.Array.valueOf():返回数组的本身

 var arr = [1, 2, 3];
 arr.valueOf()     // [1, 2, 3]

17.Array.indexOf():返回指定元素在数组中出现的位置,如果没有出现则返回-1。

var arr = ['a', 'b', 'c'];
arr.indexOf('b') // 1
arr.indexOf('y') // -1

indexOf方法还可以接受第二个参数,表示搜索的开始位置

['a', 'b', 'c'].indexOf('a', 1)     // -1

上面代码从1号位置开始搜索字符a,结果为-1,表示没有搜索到
18.Array.reverse()
用于颠倒数组中元素的顺序,返回改变后的数组。注意,该方法将改变原数组。

  var arr = ['a', 'b', 'c'];
  arr.reverse() // ["c", "b", "a"]
  console.log(arr) // ["c", "b", "a"]

19.Array.slice()
用于截取原数组的一部分,返回一个新数组,原数组不变
slice(start,end)它的第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。

 1 var arr = ['a', 'b', 'c'];
 2 
 3 arr.slice(0)         // ["a", "b", "c"]
 4 arr.slice(1)         // ["b", "c"]
 5 arr.slice(1, 2)     // ["b"]
 6 arr.slice(2, 6)     // ["c"]
 7 arr.slice()           // ["a", "b", "c"]    无参数返回原数组
 8 
 9 arr.slice(-2)          // ["b", "c"]    参数是负数,则表示倒数计算的位置
10 arr.slice(-2, -1)     // ["b"] 

20.Array.sort():
对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变。

1 ['d', 'c', 'b', 'a'].sort()
 2 // ['a', 'b', 'c', 'd']
 3 
 4 [4, 3, 2, 1].sort()
 5 // [1, 2, 3, 4]
 6 
 7 [11, 101].sort()
 8 // [101, 11]
 9 
10 [10111, 1101, 111].sort()
11 // [10111, 1101, 111]

6.JS中常见的两种函数声明(statement)方式有这两种

// 函数表达式(function expression) 
var h = function() {
      // h
}

// 函数声明(function declaration) 
function h() {
      // h
}

先说两者的显著区别:

第一种声明方式也就是var声明方式, 函数只有在var语句声明之后才能被调用

第二种声明方式也就是function声明方式, 函数可以在function声明之前被调用

这是因为,

对第一种情况, 函数表达式是在函数运行阶段才赋值给变量h

对第二种情况, 函数表达式是在代码运行阶段之前, 也就是代码解析阶段才赋值给标识符h

深入:

JS声明函数的三种方式:

1. 函数表达式: 即上面第一种方式, 这种方法使用function操作符创建函数, 表达式可以存储在变量或者对象属性里. 函数表达式往往被称为匿名函数, 因为它没有名字. 证明这一点你可以 console.log(h.name); 可以看到打印为空 “”
2. 函数声明: 即上面第二种方式, 会声明一个具名函数, 且函数能在其所在作用域的任意位置被调用, 其创建的函数为具名函数, 证明这一
点你可以 console.log(h.name); 可以看到打印为 “h”. 可在后面的代码中将此函数通过函数名赋值给变量或者对象属性
3. Function()构造器: 不推荐这种用法, 容易出问题

7.闭包

以下闭包了解
出处:https://www.cnblogs.com/heyushuo/p/9975911.html
1.什么是闭包:
闭包是指有权访问另外一个函数作用域中的变量的函数.可以理解为(能够读取其他函数内部变量的函数)
2.闭包的作用
正常函数执行完毕后,里面声明的变量被垃圾回收处理掉,但是闭包可以让作用域里的 变量,在函数执行完之后依旧保持没有被垃圾回收处理掉
例子:

// 创建闭包最常见的方式函数作为返回值
function foo() {
  var name = "kebi";
  return function() {
    console.log(name);
  };
}
var bar = foo();
bar(); //打印kebi    --外部函数访问内部变量

常见面试题:
(1) for 循环中打印

for (var i = 0; i < 4; i++) {
  setTimeout(function() {
    console.log(i);
  }, 300);
}

上边打印出来的都是 4, 可能部分人会认为打印的是 0,1,2,3

原因:js 执行的时候首先会先执行主线程,异步相关的会存到异步队列里,当主线程执行完毕开始执行异步队列, 主线程执行完毕后,此时 i 的值为 4,说以在执行异步队列的时候,打印出来的都是 4(这里需要大家对 event loop 有所了解(js 的事件循环机制))

如何修改使其正常打印:(使用闭包使其正常打印):

//方法一:
for (var i = 0; i < 4; i++) {
  setTimeout(
    (function(i) {
      return function() {
        console.log(i);
      };
    })(i),
    300
  );
}
// 或者
for (var i = 0; i < 4; i++) {
  setTimeout(
    (function() {
      var temp = i;
      return function() {
        console.log(temp);
      };
    })(),
    300
  );
}
//这个是通过自执行函数返回一个函数,然后在调用返回的函数去获取自执行函数内部的变量,此为闭包

//方法发二:
for (var i = 0; i < 4; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i);
    }, 300);
  })(i);
}
// 大部分都认为方法一和方法二都是闭包,我认为方法一是闭包,而方法二是通过创建一个自执行函数,使变量存在这个自执行函数的作用域里

(2).真实的获取多个元素并添加点击事件

var op = document.querySelectorAll("p");
for (var j = 0; j < op.length; j++) {
  op[j].onclick = function() {
    alert(j);
  };
}
//alert出来的值是一样的
// 解决办法一:
for (var j = 0; j < op.length; j++) {
  (function(j) {
    op[j].onclick = function() {
      alert(j);
    };
  })(j);
}
// 解决办法二:
for (var j = 0; j < op.length; j++) {
  op[j].onclick = (function(j) {
    return function() {
      alert(j);
    };
  })(j);
}
//解决方法三其实和二类似
for (var j = 0; j < op.length; j++) {
  op[j].onclick = (function() {
    var temp = j;
    return function() {
      alert(j);
    };
  })();
}

//这个例子和例子一几乎是一样的大家可以参考例子一

3.闭包的缺陷:

通过上边的例子也发现, 闭包会导致内存占用过高,因为变量都没有释放内存

一个挺难的面试题:

function fun(n,o) {
  console.log(o)
  return {
    fun:function(m){
      return fun(m,n);
    }
  };
}
var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?
//问:三行a,b,c的输出分别是什么?
//答案:
//a: undefined,0,0,0
//b: undefined,0,1,2
//c: undefined,0,1,1

1.先看第一个fun函数,属于标准具名函数声明,是新创建的函数,他的返回值是一个对象字面量表达式,属于一个新的object。

这个新的对象内部包含一个也叫fun的属性,属于匿名函数表达式,即fun这个属性中存放的是一个新创建匿名函数表达式。

注意:所有声明的匿名函数都是一个新函数。

所以第一个fun函数与第二个fun函数不相同,均为新创建的函数。
2.再说第三个fun函数之前需要先说下,在函数表达式内部能不能访问存放当前函数的变量。结论是:使用var或是非对象内部的函数表达式内,可以访问到存放当前函数的变量;在对象内部的不能访问到。

原因也非常简单,因为函数作用域链的问题,采用var的是在外部创建了一个fn变量,函数内部当然可以在内部寻找不到fn后向上册作用域查找fn,而在创建对象内部时,因为没有在函数作用域内创建fn,所以无法访问。

所以综上所述,可以得知,最内层的return出去的fun函数不是第二层fun函数,是最外层的fun函数。

所以,三个fun函数的关系也理清楚了,第一个等于第三个,他们都不等于第二个

开始解疑:
(1)第一行a

var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);

可以得知,第一个fun(0)是在调用第一层fun函数。第二个fun(1)是在调用前一个fun的返回值的fun函数,所以:

第后面几个fun(1),fun(2),fun(3),函数都是在调用第二层fun函数。

遂:

在第一次调用fun(0)时,o为undefined;

第二次调用fun(1)时m为1,此时fun闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层fun函数fun(1,0);所以o为0;

第三次调用fun(2)时m为2,但依然是调用a.fun,所以还是闭包了第一次调用时的n,所以内部调用第一层的fun(2,0);所以o为0

第四次同理;

即:最终答案为undefined,0,0,0
(2)第二行b

var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?

先从fun(0)开始看,肯定是调用的第一层fun函数;而他的返回值是一个对象,所以第二个fun(1)调用的是第二层fun函数,后面几个也是调用的第二层fun函数。

遂:

在第一次调用第一层fun(0)时,o为undefined;

第二次调用 .fun(1)时m为1,此时fun闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层fun函数fun(1,0);所以o为0;

第三次调用 .fun(2)时m为2,此时当前的fun函数不是第一次执行的返回对象,而是第二次执行的返回对象。而在第二次执行第一层fun函数时时(1,0)所以n=1,o=0,返回时闭包了第二次的n,遂在第三次调用第三层fun函数时m=2,n=1,即调用第一层fun函数fun(2,1),所以o为1;

第四次调用 .fun(3)时m为3,闭包了第三次调用的n,同理,最终调用第一层fun函数为fun(3,2);所以o为2;

即最终答案:undefined,0,1,2
(3)第三行c

var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?

根据前面两个例子,可以得知:

fun(0)为执行第一层fun函数,.fun(1)执行的是fun(0)返回的第二层fun函数,这里语句结束,遂c存放的是fun(1)的返回值,而不是fun(0)的返回值,所以c中闭包的也是fun(1)第二次执行的n的值。c.fun(2)执行的是fun(1)返回的第二层fun函数,c.fun(3)执行的也是fun(1)返回的第二层fun函数。

遂:

在第一次调用第一层fun(0)时,o为undefined;

第二次调用 .fun(1)时m为1,此时fun闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层fun函数fun(1,0);所以o为0;

第三次调用 .fun(2)时m为2,此时fun闭包的是第二次调用的n=1,即m=2,n=1,并在内部调用第一层fun函数fun(2,1);所以o为1;

第四次.fun(3)时同理,但依然是调用的第二次的返回值,遂最终调用第一层fun函数fun(3,1),所以o还为1

即最终答案:undefined,0,1,1
以上面试题
作者:小小沧海
出处:http://www.cnblogs.com/xxcanghai/
本文地址:http://www.cnblogs.com/xxcanghai/

8.css画三角形

参考:https://www.cnblogs.com/blosaa/p/3823695.html

9.html的块级和行级元素

参考:https://www.cnblogs.com/yanqiu/p/8987126.html

10.json和jsonp

出处:https://kb.cnblogs.com/page/139725/
JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。我们拿最近比较火的谍战片来打个比方,JSON是地下党们用来书写和交换情报的“暗号”,而JSONP则是把用暗号书写的情报传递给自己同志时使用的接头方式。看到没?一个是描述信息的格式,一个是信息传递双方约定的方法。
JSON的优点:

1、基于纯文本,跨平台传递极其简单;

2、Javascript原生支持,后台语言几乎全部支持;

3、轻量级数据格式,占用字符数量极少,特别适合互联网传递;

4、可读性较强,虽然比不上XML那么一目了然,但在合理的依次缩进之后还是很容易识别的;

5、容易编写和解析,当然前提是你要知道数据结构;

JSON的缺点当然也有,但在作者看来实在是无关紧要的东西,所以不再单独说明。

JSON的格式或者叫规则:

JSON能够以非常简单的方式来描述数据结构,XML能做的它都能做,因此在跨平台方面两者完全不分伯仲。

1、JSON只有两种数据类型描述符,大括号{}和方括号[],其余英文冒号:是映射符,英文逗号,是分隔符,英文双引号""是定义符。

2、大括号{}用来描述一组“不同类型的无序键值对集合”(每个键值对可以理解为OOP的属性描述),方括号[]用来描述一组“相同类型的有序数据集合”(可对应OOP的数组)。

3、上述两种集合中若有多个子项,则通过英文逗号,进行分隔。

4、键值对以英文冒号:进行分隔,并且建议键名都加上英文双引号”",以便于不同语言的解析。

5、JSON内部常用数据类型无非就是字符串、数字、布尔、日期、null 这么几个,字符串必须用双引号引起来,其余的都不用,日期类型比较特殊,这里就不展开讲述了,只是建议如果客户端没有按日期排序功能需求的话,那么把日期时间直接作为字符串传递就好,可以省去很多麻烦。
json实例:

// 描述一个人 
var person = {
    "Name": "Bob",
    "Age": 32,
    "Company": "IBM",
    "Engineer": true
}
 
// 获取这个人的信息 
var personAge = person.Age;
 
// 描述几个人 
var members = [
    {
        "Name": "Bob",
        "Age": 32,
        "Company": "IBM",
        "Engineer": true
    },
    {
        "Name": "John",
        "Age": 20,
        "Company": "Oracle",
        "Engineer": false
    },
    {
        "Name": "Henry",
        "Age": 45,
        "Company": "Microsoft",
        "Engineer": false
    }
]
 
// 读取其中John的公司名称 
var johnsCompany = members[1].Company;
 
// 描述一次会议 
var conference = {
    "Conference": "Future Marketing",
    "Date": "2012-6-1",
    "Address": "Beijing",
    "Members":
    [
        {
            "Name": "Bob",
            "Age": 32,
            "Company": "IBM",
            "Engineer": true
        },
        {
            "Name": "John",
            "Age": 20,
            "Company": "Oracle",
            "Engineer": false
        },
        {
            "Name": "Henry",
            "Age": 45,
            "Company": "Microsoft",
            "Engineer": false
        }
    ]
}
 
// 读取参会者Henry是否工程师 
var henryIsAnEngineer = conference.Members[2].Engineer;

jsonp:
1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;

2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如

3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;

4、恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;

5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。

6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。

7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

json与jsonp的区别:
1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加

3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。

总而言之,jsonp不是ajax的一个特例,哪怕jquery等巨头把jsonp封装进了ajax,也不能改变这一点!

猜你喜欢

转载自blog.csdn.net/weixin_43073223/article/details/89373742
0条评论
添加一条新回复