【study】押题冲鸭冲鸭!!!

284 阅读30分钟

1.元素应用box-sizing:border-box;会产生怎样的效果?简述一个应用场景。

  • (1)border-box是怪异盒子模型,使用border-box之后,padding和border的值就不会影响元素的宽高,因为他们的值都相当于计算在了content里面
  • (2)应用场景:如果我的网页内容中要给元素加上border或者padding,要是使用默认的标准盒子模型,原先不加的时候刚好占满整个屏幕,但是加上之后,就会掉下去,如果此时使用怪异盒子模型,就不会掉下去,因为border或者padding会自动计算在content里面

2.哪些css属性会创建块格式化上下文(Block Formatting Content)?

  • (1)BFC是可视化css渲染的一部分,会创建格式化上下文的有根元素;浮动float不是none;定位display为absolute或者fixed,display:inline-block转换行内块元素,display:table-cell;overflow:hidden;弹性布局:display:flex;flex:grid
  • (2)BFC本来就是为了创建块级上下文存在的,也就是所有应该要创建BFC的都会创建BFC

3.请说明,forEach(),map(),reduce()应在什么场景下使用?

  • (1)forEach()和map()最大的区别是返回值,map是有返回值的,所以map的原数组有几项,新生成的数组一定会有几项,forEach只是给for循环增加了一种原型上的方法,所以forEach的返回值是undefined,因此,只做遍历不考虑返回值的时候可以选择forEach,在原数组的基础上返回一个新的数组使用map。
  • (2)reduce是一个累加器,第二个参数是累加器的初始值,如果传了第二个参数,那么第一次的遍历就会指定初始值,如果不传反之,所以此时的场景就是做一个累加器。reduce还是一个函数,所以它也可以做些字符串的拼接或者运算,甚至可以在遍历里加逻辑判断,达到filter加map的效果

4.以下会输出什么,如果报错,会报什么错?

var data = [5,10,15,20];
for(var i in data) { 
   console.log("start:"+ i);
   setTimeout(function(){
       console.log("end:" + i)
     },i*500);
}

  • 最大的考点是作用域,setTimeout()\color{red}{最大的考点是作用域,setTimeout()}
  • 然后第二个考点是for...in\color{red}{然后第二个考点是for...in}
  • for...in是用于对象的,数组是一个对象,但是和数组的项完全没关系
  • (1)for...in循环的是对象的key,而且不仅是自身的key,所有继承的(也就是原型链上的)key都会被循环,所以如果原型链有多层的话,会一直找下去,另一个特点是,for...in只会找可枚举的key,也就是说,如果原型链上的属性是不可枚举的,就不会被遍历到
  • (2)如果了解数组,就能知道,数组实例的length属性和数组的原型上的方法都不可枚举,而继承自object的原型,因为object的原型也不可枚举,所以都不会被遍历到,所以,才能最终得出,遍历的是数组的index
  • 最后一个考点是var\color{red}{最后一个考点是var }
  • (1)ES6除了var,还增加了let和const,就是为了解决问题的,对于let和const来说,作用域在块内,即在for循环内,那么循环的单次,i都是一个新值,且是固定的,setTimeout的回调中,console.log的i即当次循环的i值,下一次记循环时i的变化不会影响上次的i,但是var不一样,它的作用域是在闭包中,这里显然是在整段函数运行期间,如果上下文是global,那么i就是定义在global作用域中的
  • 最后得出的结论\color{red}{最后得出的结论 }
  • (1)这里的for循环是同步的,但是setTimeout是异步的,根据同步先执行原则,当data循环完毕之后,i会是最后项的index,也就是3,然后才开始执行异步setTimeout部分,setTimeout的设定语句是同步的,回调函数是异步执行的,所以,回调会分别以0 x 500,1 x 500,2 x 500,3 x 500的延时去做异步回调,当执行回调时,因为此时的i已经全部变成了3,所以回调中的i总会是3,而如果使用的是let或者const,那么i就能正确表示

5.请写出下列代码的输出的JSON结构

 var data = {}
  data.name = ‘items’
  data.content = []
  for(var i = 0, i< 2 , i++){
      var item = {}
      item.id = i
      item[‘key-‘ + i]= ‘value’ + i
      data.content.push(item);
}
    Console.log(JSON.stringify(data))
)}
{"name":"items",
"content":[
   {"id":0,"key-0":"value-0"},
   {"id":1,"key-1":"value-1"}
   ]
 }
  • 最终打印的时候,用了JSON.stringfy,把对象类型转成了JSON类型

6.请定义 function get(url)函数完成异步请求,函数返回Promise对象,使用Promise封装XML HTTPRequest。

function get(url) {
       return new Promsie((resolve,reject)=>{
           let xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
                 xhr .open("GET", url, true);
                 xhr .onreadystatechange =()=> {
                        if (xhr .readyState == 4) {
                               if (xhr.status >=200 && xhr.status <=399) {
                                resolve(xhr.responseText);
                        }
                            else {
                            reject(xhr.Error);
                  }
                    xhr.send();
 })
}

7.盒子水平居中的方法

8.如何实现单行文本溢出显示省略号呢?多行文本呢?

  • 单行文本\color{red}{单行文本 }:用text-overflow:ellipsis属性,同时需要加宽度width来兼容部分浏览
 overflow:hidden;
 text-overflow:ellipsis;
 white-space:nowrap;
  • 多行文本\color{red}{多行文本 }:因为使用了webkit的css扩展属性,所以该方法适用于webkit浏览器以及移动端
 overflow:hidden
 //将对象作为弹性伸缩盒子模型显示
 display:-webkit-box;
 //设置或检索伸缩盒对象的子元素的排列方式
-webkit-box-orient:vertical;
//用来限制行数
-webkit-line-clamp:3;

9.如何判断数组和对象?

  • (1)用String或者toString
String([]) //  ""
String({})  //  "[object object]"
  • (2)ES6提供了一种静态方法,使用Array.isArray判断
Array.isArray([])   //true
Array.isArray({})   //false

10.ES中一共定义了哪几种数据类型,分别是什么?

  • The ECMAScript language types are Undefined,Null,Boolean,String,Symbol,Number,BigInt,andObject\color{red}{Undefined, Null, Boolean, String, Symbol, Number, BigInt, and Object }

11.怎么判断一个变量是undefined?

  • typeof a = "undefined"

12.怎样将一个变量设置为undefined呢?

  • (1)此时a变量是undefined,让b = a可以保证b也是undefined
var a;
b = a
  • 缺点:之前必须没有定义这个变量a,如果在父级作用域中定义了undefined为另外一个值,就不可以了,所以可以用let,let的作用域在块级中,所以可以确保这个变量是undefined,但是还不保险,因为很多编译工具会把let和const在打包时转为var
  • (2)使用关键字void,viod表示没有返回值,在js中的语法是void(表达式),所以常见,很多压缩的代码,undefined会变成void 0,void加任何都是undefined
//相当于什么都没做,然后返回值是undefined
void 0 
  • (3)利用闭包:通过闭包将变量的作用域锁定在函数内,这样也可以确保变量的值
var undefined = 1;
(function(undefined){
    console.log(undefined)
})

13.什么时候需要将变量设置为undefined呢?

  • (1)大多数情况下是不需要的,但是有些情况则是必须的,比如为了防止内存泄漏,假设你有个变量对一个对象做了长时间的引用,就会造成内存泄漏问题
  • 内存泄漏指的是长时间被占用而得不到释放的一种表现,常见的内存泄漏有不恰当的使用定时器,或者引用DOM节点等
  • (2)为了避免内存泄漏,可以释放引用的对象,比如var node = document.getElementById("id"),这时候,node变量就引用了DOM节点,如果后面做了一个闭包,比如事件监听,document.addEventListener("click",()=>{node.innerHTML=""}),因为回调时间是在不确定的时间运行的,这个回调函数会一直处于时间监听控制中得不到释放,所以函数内使用的node变量会一直被占用,从未一只会对DOM节点的引用关系存在,所以可以通过node=void 0 这种形式释放对DOM节点的引用。这样就可以释放内存了

14.typeof null的值是什么?

  • (1)标准中定义,null这个值(不是null这个关键字)表示任意对象的空值,所以typeof null是值是Object,用来描述对象的
  • (2)但是null这个关键字表示的是这个变量的值是Null类型的,而Null类型在标准中定义了它的值就是null
  • 总结:null这个关键字表示这个变量是Null类型,null的类型是objectnull的值是null\color{red}{null这个关键字表示这个变量是Null类型,null的类型是object,null的值是null}

15.undefined和null在定义变量的时候有什么区别?

  • undefined是指定义了一个变量,而没给变量赋值
  • null是指这个变量有值,值为null,所以可以认为null是有值的,只不过值为空而已

16.既然typeof null = "object",那么为什么null === null 成立呢?

  • (1)对象之间为什么不相等?
             因为对象存储的是一个hash,它不是一个单一的值,是有key和value的,所以,就算key和value相同,但它的存储空间是不同的,所以一个变量如果是一个对象,那么这个变量指的是对象本身,就像静态语言中的指针,指向的是内存地址,而非具体的值
  • (2)null在标准中定义它就是对象缺失内容时填充的值,可以认为null是在程序中预先定义好的一个常量,当这个对象中什么内容都没有时,就用null来代替,所以null永远指向的是同一个引用

17.Symbol的应用场景是什么?

  • (1)简单的理解,就是Symbol和Object一样,返回的是一个引用,其实就是指向了一个空间地址
  • (2)Symbol的应用场景:消除魔术变量,魔术变量就是一个变量,不管它的值是什么,程序都能正常运行,所以,魔术变量的值就是魔术字符串
//key是魔术变量,“foo”是魔术字符串
var key = "foo";
var obj = {};
obj[key] = 1;

function get() {
  return obj[key];
}
  • (3)Symbol有个静态方法,Symbol.for
Symbol.for("a") === Symbol.for("a") 
//true

  • (4)内部实现过程:主要是两步,因为内部有个全局的Symbol注册表,所以就是同一个,就会相等,如果没有,就会继续往下走,创建新的Symbol,并放在注册表中,所以Symbol.for("a") === Symbol.for("a") ,左边的语句会先执行,这时候是创建一个新的放入注册表中,而等号右边的则是从注册表中取出来
  • (5)Symbol的原型链和静态属性

    。。。

18.怎么判断一个变量是否是对象?

  • (1)String()和toString()都是将其他类型的变量转换为字符串类型,toString()无法转换null和undefined
//所有的类型都可以转换成方法,通过构造器String()
String(undefined) // undefined
String(null) //null
String(false) //false
String(NaN) //NaN
String({})  // object
String([]) // ""
  • (2)判断一个变量是否是对象,用的就是String或者toString的方法,因为object和array虽然都是object类型的,但是转成字符串的表现不同,typeof({})=typeof([]),他们的类型是相同的,所以要判断对象只能转成字符串来判断,所有的object类型,不管是简单的对象,还是类生成的实例,转成字符串都是[object object]
a = {};
a.toString = () => 1;
String(a);
  • (3)上面的代码可以看出,String构造器会先调用toString方法,如果有toString方法,那么将它的返回值转换成文本类型,如果没有toString,自然就直接转换成字符串
  • (4)定义toString属性,构造器是直接读对象上的toString属性的,如果读不到,会去原型链上读,如果在读不到,就直接转换成对象

19.如何将abcd转成a,b,c,d?

 var a = abcd
 Array.prototype.join.call(a)
 //本例中call和apply一样

  • (1)call和apply除了后续的传参使用不同外,性能也有差异,call总会快一点点

20.slice/substring/substr有什么区别?

  • (1)slice()方法可通过制定开始和结束位置,提取字符串的某个部分,并以新的字符串返回;
a.slice(start,end)
//start(必须):表示开始位置,可以是正数,也可是负数,负数表示从后面开始数
//end(可选):表示结束位置,不写就是从开始位置到截取到最后面,正数就是正常的截取,负数就是从后面开始数
  • (2)substring()方法用于提取字符串介于两个指定下标的字符,返回一个新的字符串,该字符串的长度为end-start
 a.substring(start,end)
 //start(必须):非负的整数
 //end(可选):非负的整数,可写可不写
 //如果startend相等,那么该方法返回的就是一个空字符串,即长度为0的字符串
 //如果startend大,那么该方法就会截取字符串之前,先交换这两个参数
 //如果startend为负数,那么将会被替换成0
  • (3)substr()方法用于返回一个从指定位置开始的指定长度的字符串
 a.substr(start,length)
 //start(必须):开始的位置,字符串的第一个字符的索引是0
 //length(可选):在返回的字符串中包括的字符个数
 //如果length为0或者是负数,将返回一个空字符串
 //如果没有指定length,那么子字符串将延续到a的最后
 //如果srart或length为负数,那么将会被替换成0

21.什么是类数组?

  • (1)标准定义中,数组有2个特性,第一个是数组有长度length,第二个是数组需要有个方法splice
  • (2)虽然没说为什么是splice,但是splice是个操作数组的全能方法,所以也不难理解为什么是splice

22.数组有几种静态方法?

  • (1)Array.isArray
  • (2)Array.from,用于把类数组转成真正的数组,原来的数组不受任何影响,所以是生成了一个新的数组

拓展:类数组对象转为数组的六种方法:
1.Array.form(arr)
2.Array.prototype.slice.call(arr)或者[].slice.call(arr)
3.[...arr]
4.Array.prototype.forEach.call(arr,callback)
5.Array.prototype.forEach.apply(arr,[callback])
6.Array.prototype.forEach.bind(arr,callback)

  • (3)Array.of,用于生成[1]这样一个数组,因为Array(1)生成的不是[1],而是[undefined]

23.如何利用css实现一个三角形?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .triangle{
            width: 0px;
            height: 0px;
            /* border:10px solid pink; */
            border-right:30px solid transparent;
            border-left:30px solid transparent;
            border-top:30px solid blue;
            border-bottom:30px solid transparent;
        }
    </style>
</head>
<body>
    <div class="triangle"></div>
</body>
</html>

24.什么是token以及怎样生成token?

25.split和join方法有什么作用?

  • (1)split是字符串原型上的方法,用来把字符串分割成数组
  • (2)join是数组原型上的方法,用来把数组合并成字符串

26.push,shift,unshift,pop的作用分别是什么?

  • (1)push方法,可以在数组的末尾添加一个或者多个元素,push可以接受不仅一个参数,它可以接受无限个,也就是说可以一次性的push多项,push的返回值也很特别,返回的是变动后数组的长度\color{red}{长度}
//利用解构,可以结合push进行很多方便地操作
arr.push(...args)
  • (2)pop方法把数组的最后一个元素删除,不接受参数,返回最后一项,同时会改变原数组
  • (3)unshift方法可以在数组的最前面添加一个或者多个元素(类别上面的push)
  • (4)shift方法把数组的第一个元素删除(类比上面的pop)
  • (5)区别:

1.push和pop操作的一定是栈(stack)类型的,而shift和unshift操作的是队列(queue)类型的

  • (6)push,pop,shift,unshift都会改变原数组\color{red}{push,pop,shift,unshift都会改变原数组}

27.数组的splice方法如何运用?

  • (1)splice会改变原数组\color{red}{splice会改变原数组}
  • (2)splice接受的参数,第一个是要开始操作的项的index,第二个参数时要从这个操作项开始删除几项,第三项开始,是可以接受无限多个参数,
  • (3)所以如果只做删除\color{red}{删除},只需要传入2个参数即可
  • (4)如果只做添加\color{red}{添加},第二个参数就传0,就是不删除
  • (5)splice的返回值是被删除的项,所以哪怕即使只删除了一项,返回的也是一个数组\color{red}{数组}

28.数组的reverse和sort方法如何使用?

  • (1)reverse,sort会改变原数组\color{red}{reverse,sort会改变原数组}
  • (2)[2, 10].sort()的结果是什么呢?
  • (3)从上述例子可以看出,直接使用sort,是没有办法做到正确排序的,sort不传参时的排序方式是这样的,首选,把所有项转成字符串,然后通过字符串比较排序,字符串的比较方式是先比较第一个字符,从字符的ASCII(或者Unicode)从小到大顺序排序,然后在比较第二个字符,所以10和2其实比较的是1和2
  • (4)sort的参数,sort接受一个函数,函数中费被接受2个参数,即要对比的2项,而函数的返回值比较重要,3种返回值\color{red}{有3种返回值},大于0,等于0,小于0
  • (5)比较12,自然是从小到大,也就是12,也就是小于0\color{red}{比较1和2,自然是从小到大,也就是1-2,也就是小于0}

29.什么是对象?

  • 除了常见的基本类型外,其他的都是对象,JS最重要的三个东西,函数,作用域,原型链\color{red}{函数,作用域,原型链},虽然这3个都是和函数有关,但对象就是函数构造出来的,对象的原型,其实就是指类上定义的实例方法,即原型上的方法都是共享的\color{red}{原型上的方法都是共享的},只有实例本身不同而已,相同类生成的实例的原型链全部都是共享的,而对象就是上面说的实例本身部分,因为我们在创建原型链的时候,常会写function.prototype = {};所以,原型链本身会是一个object\color{red}{原型链本身会是一个object},也因此,大多情况下,任何对象的原型链都可以追溯到object这个对象\color{red}{任何对象的原型链都可以追溯到object这个对象}

30.创建一个Object有什么方法?

  • (1)new操作符 + Object创建对象
  • (2)字面量创建对象
  • (3)工厂模式
  • (4)构造函数模式
  • (5)原型模式
  • (6)混合模式(构造函数模式+原型模式)
  • www.cnblogs.com/shirliey/p/…

31.如何创建一个没有原型链的对象?并举例适用于什么场景?

  • (1)大部分的对象原型链都可以追溯到Object,是因为定义其原型的时候,指定了prototype={}
  • (2)Object.create(null),我们指定了原型为null,所以创建出的对象是没有原型的,或者说原型是null
  • (3)因为这样创建出的对象没有原型,所以很多依赖原型的功能就没办法实现了,比如,在vue中,所有可观察的数据和属性,都是通过在原型上存储对应的依赖实现的,所以我们如果创建一个没有原型的对象,可以防止数据被观察

32.Object.create()里面传的是一个函数,会生成什么呢?

  • (1)Object.create(()=>{})
  • (2)这样是创建了一个类型为Function的对象,过程如下,var prototype = () =>{} ;Object.create(prototype);而prototype是生成对象的原型,也就是函数的静态方法
  • (3)Object.create这个方法接受2个参数,第一个参数是指定要生成的对象的原型。第二个参数则是指定函数熟悉的描述器

juejin.cn/post/687933…

33.Vue2的核心原理是什么?

  • Vue2的核心就是将对象的属性通过get和set做了劫持,从而能获知属性的变动(set),并且可以在属性被使用时(get)记录依赖关系

34.Object.seal的作用是什么?

  • (1)Object.seal是将configurable(设置false就不能对对象重新定义属性)设置为false的快捷方法,所以不能再修改这个对象上已经存在的属性描述了,同时,也没法再给这个对象增加额外的属性了,也不能在删除对象上的属性
  • (2)注意:对象的属性描述不能增加和删除,但是并没有禁止已有属性的修改\color{red}{对象的属性描述不能增加和删除,但是并没有禁止已有属性的修改}
  • (3)常见的使用场景:创建一个固定的结构体
  • (4)判断是否为seal的方法: Object.isSealed(a)\color{red}{Object.isSealed(a)}

35.Object.freeze的作用是什么?

  • (1)顾名思义,是冻结对象的意思,使用的时候除了会有seal的表现外,连本身定义好的值也禁止修改了
  • (2)从内部实现上来说,seal影响的是configurable,freeze影响的是configurablewritable\color{red}{seal影响的是configurable,而freeze影响的是configurable和writable}
  • (3)判断是否是freeze的方法:Object.isFrozen(a)\color{red}{Object.isFrozen(a)}

36.Object.prevenExtensions的作用是什么?

  • (1)prevenExtensions比seal更轻量,仅仅是防止对象被扩展,防止被扩展的意思是,对象不能增加新的属性,所以属性的configurable是不会被改变的,而且对象上的属性也可以被删除,只是不能增新\color{red}{不能增新}
  • (2)判断一个对象是否为可扩展的方法:Object.isExtensible()

37.Object.assign的作用是什么?

  • (1)主要用于扩展对象,可以接受无限个参数,但是会改变第一个参数中的对象,这个方法和jQuery中的extend方法是一样的(不设置为deep的情况下)
  • (2)第一个参数是最终要被扩展的对象,这个对象会被扩展,后面的所有参数中的属性都会被扩展到第一个参数的对象中,如果有相同的key,后面的覆盖前面的,后面参数中的对象都不会被修改,这个函数的返回值和第一个参数是相等的,指的是同一个对象
  • (3)Object.assign的扩展因为本质是扩展属性,所以是浅复制\color{red}{浅复制},如果需要深复制,需要写递归实现
  • (4)Object.assign只会对可枚举值进行扩展
  • developer.mozilla.org/zh-CN/docs/…

38.Object.is的作用是什么?

  • (1)用于判断两个值是否为同一个值
  • (2)js中的一切都可以是对象,所以Object.is这里的Object是指所有的类型实例
  • (3)应用场景:
  • (4)如何判断一个变量是不是NaN呢?

isNaN()

  • 上图:第一句定义a是数字3,第二句是获取a变量也就是数字3的isNaN的属性,数字类型的原型上没有isNaN属性,所以是undefined,然后使用了全局方法isNaN判断a是不是数字,因为a是数字,所以返回false,最后,Object.is需要传2个参数进行比较,而上图只传了一个,那么第二个参数就是undefined,所以比较下来就是false

39.Vue中,在点击某个按钮进行详情页面跳转时,使用的是什么方法?

//详情页面一般是通过id的不同进行控制
 handleClick(id){
    this.$router.push(`/detail/${id}`)
 }

40.Vue中,route,router有什么区别?

this.$router //路由对象
this.$route  //当前唯一匹配的路由对象

41.Vue中的路由拦截请举例说明。

//全局路由拦截的配置  router/index.js中
//路由拦截一般用于限制用户的登录
router.beforeEach((to,from,next)=>{
    //跳转的是index页面进行拦截
    if(to.path === '/index'){
       //在此时判断是否有后端传来的token,有则放行,无则重定向到login页面
       if(localStorage.getItem("token")){  
           next()
       }else{
           next("/login")
       }
    }else{
       next()
       }
})

42.路由的原理是什么?

  • (1)hash路由:location.hash切换;window.onhashchange监听路径的切换
  • (2)history路由:history.pushState切换;window.onpopstate监听路径的切换

43.请实现一下Vue的tabbar加高亮和跳转?

<router-link tag="li" :to="data.path" v-for="data in datalist" :key="data.id" activeClass = "kerwinactive" >
      <i class = "iconfont" :class="data.icon"></i>
      <span>{{data.text}}</span>
 </router-link>

44.前端一般如何解决跨域问题呢?

  • (1)jsonp解决跨域:动态创建一个script标签,然后引入外部地址链接,通过callback传一个方法func,func函数写在script里面,这种方法只能是get请求,服务器拿到这个请求,一定会先准备好一个数据,那么如何返回服务端呢?服务器会先接收一个func,拼成这样的处理结果,客户端就相当于拿到了一个函数里面的对象,浏览器会帮助我们执行,所以这个方法就执行了,data就是从服务器获取的数据,get请求存在的问题:不安全,有缓存,传递的信息有大小限制
  • (2)基于iframe的跨域方法法:window.name;document.domin;location.hash;post.message;
  • (3)CORS跨域资源共享
  • (4)基于http proxy实现跨域请求
  • (5)nginx反向代理
  • (注):前端解决不了跨域问题,所有域的限制都是由设备本身的安全机制加上服务器的配置声明实现的,所以如果有域的限制,需要跨域,单单前端是无法实现的,必须和后端配合,通过更改域的限制实现,或者使用代理,或者使用不配有安全机制的设备请求,比如命令行curl,以前前端可以通过jsonp进行跨域,还有iframe等等,但是现代标准里对这些做了更多的安全设置,所以这些方法不一定好用了,本来跨域问题就是必须先有安全机制才会出现,如果客户端没有安全机制,随便能进行访问,后端并没有设置安全策略,就都不会出现跨域问题。
  • (注2):要解决浏览器中的跨域问题,就需要知道浏览器都做了哪些安全设定,不过这样太麻烦了,我们反过来看,要解决跨域问题,看看浏览器目前支持的跨域方式有哪些,这样可以借助这些已有的跨域方式解决跨域问题,很容易就想到的是有iframe,iframe中的地址可以和parent的不在一个域里,其他的很常见的,比如外部资源,常见的外部资源有js,css,图片等,这些资源都可以跨域访问的,iframe的parent,就是document,iframe在document里是一个标签,其实应该叫元素HTMLElement,然后,这个元素本身会创建一个额外的上下文文档,就是会创建另一个隔离的document,这样可以让2个不同的网页在一个视图内显示。
  • (注3):外部资源为了使用方便,往往不会设置跨域的安全机制,jsonp就是利用了这点,但是要清楚,如果设置了安全机制,那么外部资源还是会被域限制的,换句话说,如果设置了cors规则,其实jsonp就无法使用了,至于iframe,没有这个限制,但是即便把不同的资源加载回来了,也访问不到,这是后面新增的安全机制,上面介绍了jsonp是利用外部资源可跨域的原理,但是那么多的外部资源,哪个最适合程序呢?
  • (注4):毫无疑问就是script,所以jsonp其实就是利用script进行的一种跨域请求,具体的是,创建一个script标签,脚本路径为请求地址,因为script是可以加载其他域的脚本的,所以自然可以向这个请求地址发送请求,可以理解为把请求地址伪装成了脚本地址,使用这种方式做的话,对接口也要进行一定的改造,因为要获取响应数据,所以加载回来的也会是一段js代码,而不是纯数据,这段js代码会运行一个函数,把响应数据作为参数传入,而这个运行的函数则是在发送jsonp前定义好全局函数(一个临时的函数),所以在发送jsonp请求时,不仅要传参,还要传这个回调的函数的名字,jsonp的原理就是本身利用script可以加载外部脚本\color{red}{jsonp的原理就是本身利用script可以加载外部脚本},vue和jsonp是没有关系的,用和不用都是可以的,jsonp只是一种获取数据的方式,简而言之,单单靠前端很难彻底解决跨域问题。

45.input光标的颜色如何修改?

 input{
    caret-color:pink;
 }

46.placeholder颜色如何修改?

input::-webkit-input-placeholder{
      color:pink
}

47.input下方显示搜索(默认显示换行)字样?

 <form action="" onsubmit="return false"
      <input type="search" placeholder="棠梨煎雪1226">
 </form>

48.移动端键盘如何显示纯数字?

  input的text="tel"(是纯数字,但是左下角有符号)
  input的text="text" + 正则pattern="[0-9]*"

49.input如何自动获取焦点?

input标签内autofocus = "autofocus"

50.如何关闭ios键盘首字母的自动大写?

autocapitalize = "off"

51.请问如何可以直接拿到对象的值呢?

  • (1)ValueOf就是拿这个对象的值,内部只做了一件事,就是把上下文对象强制转成对象\color{red}{就是把上下文对象强制转成对象},然后返回,所以如果是个正常的对象,那么返回的就是本身
  • (2)和new String("a")一样,本质就是把字符串转成了对象
  • (3)上例也可以看做是类的实例化的内在过程
  • (4)为什么调用了call?
    答:因为字符串原型上的ValueOf方法不是Object的ValueOf方法
  • (5)不管是class还是function,当生成实例时,都会经历相似的过程,实例化的第一步,就是创建一个对象\color{red}{创建一个对象},然后把这个类作为这个新创建的对象的构造器,所以生成的对象上会有个constructor指向了类\color{red}{有个constructor指向了类},同时,类的prototype也就成为实例对象的原型\color{red}{prototype也就成为实例对象的原型},所以,如果这个时候,在构造过程结束时,返回了一个对象\color{red}{返回了一个对象},那么会认为返回的这个对象就是构造函数的实例对象,这也是new Object(obj)和obj相等的原因

52.ES6中的proxy了解过吗?请详细说明一下。

  • (1)先回顾一下Object的属性描述,我们可以通过设置对象的属性描述来为对象的属性设置固定值,或者动态计算值,也就是我们可以通过这个方式做一层中间层,用来处理属性值,就和代理一样,但同时,也出现了一些问题,比如,只有修改值的时候才能监测到,如果想监测删除属性的动作就不行了,或者有时候,原先的属性描述定义已将configuable设置为false,那么就无法在重新定义做代理了,因此,有了Proxy。
  • (2)这里说的Proxy是ES的一个对象接口,那么Proxy的出现就可以弥补上述的不足,而Vue3就抛弃了get/set拦截器,转而使用了Proxy来实现拦截
  • (3)之前我们讲的很多方法和构造器,都是ES对外公开的接口,但其内部会经历许多运行时的方法,有些是共用的,有些是特别的,而有些内部的方法或属性会暴露出来一部分,可以让用户有机会看到或修改,比如Symbol的一些属性所表示的内部处理方法,Proxy就是对这些内部的一些方法做代理
  • (4)Proxy只能为对象做代理
  • (5)Proxy支持修改的内部方法
12是对于原型的代理
第3个是对于查询对象是否可扩展时的代理
第4个是反过来设置不可扩展时的代理
567分别是对 对象本身属性的读、写和查的代理
89是对属性值的读和写的代理
10是对属性删除操作的代理
11是取属性key的代理
12是调用函数时的代理
函数也是对象对吧
13是构造时的代理

+(6)举例:

如果打印b,会看到b.foo1
但是如果打印b.foo,值会变成2

区别:
第一点区别:
1.设置属性的描述,是直接作用于原对象的
即直接改变原对象的属性描述,如果原对象不存在,则会创建这个属性
2.而代理不一样
代理并不改变原对象,代理增加了一个中间层做代理,并返回一个被代理的新对象
第二点区别:
1.定义对象属性描述的set,函数的返回值是void
即无需任何返回值
2.而Proxy需要在set代理结束之后,返回布尔值,用来告诉用户,设置是否成功,因为我们也可以在代理set的时候设置不可以进行set
第三点区别:
1.defineProperty只能显示对某个属性进行定义
哪怕是defineProperties也是一样的,必须申明要修改的属性
2.但是代理不同,代理可以统一设置,比如更改的例子中,如果b.bar = 100,可以看到a.bar = 99,这就是set代理造成的
set代理中,我们没去判断key,只要设置,就给新设置的值减1,所以,相当于代理了任意的key
如果需要对指定的key进行代理,只需要在代理时进行判断就好了
  • (6)应用场景:Proxy代理本身并没有修改原对象,使我们去定义代理的操作时改变了原对象,通过Proxy,我们可以做很多事情,比如记录log日志,这样就不需要每次自己console.log了
  • (7)既然我们可以检测数据的变动,并且能对此做出相应。那么如果把console的打印换成其他的操作是不是就可以实现数据变动时的更新,而读取时获取依赖的逻辑了,所以,这相当于把Vue的数据代理核心部分梳理了一遍

53.请写出下列代码的执行结果。

(() => {
 //语句测试代块的错误,一般把可能会出错的代码放到这里
  try {
    console.log(1);
    return 2;
  }
  //只有try里面的代码块发生错误时,才会执行这里的代码,参数err记录着try里面的代码的错误信息
  catch (err) {
    console.log(3);
    return 4;
  }
  //无论有无异议里面的代码都会执行
  finally {
    console.log(5);
    return 6;
  }
})();

(() => {
  try {
    console.log(1);
    return 2;
  }
  catch (err) {
    console.log(3);
    return 4;
  }
  finally {
    console.log(5);
  }
})();

(() => {
  let i = 0;
  try {
    console.log(i);
    return i;
  }
  finally {
    i += 1;
    console.log(i);
  }
})();
//return作为返回,是最后执行的,return只在函数中有用,其实和try...catch没多大关系,所以一旦执行到return,整个函数就结束了,所以return是最后执行的

(() => {
  let arr = [1];
  try {
    throw new Error();
    return 1;
  }
  catch (err) {
    return arr;
  }
  finally {
    arr.push(2);
  }
})();

54.函数的两种形式,请具体分别说明一下?

  • (1)函数的两种形式,一种是以function方式声明的,另一种是箭头函数,用function关键字声明的,有提升的作用,会先被执行
  • (2)作用域时函数必须要考虑的部分,所有的变量都有作用域,最外层的是全局作用域,里面的是函数的作用域

55.说一下js继承的方式?

  • (1)在class出现之前,只能通过apply和prototype原型链的方式继承类
  • (2)在class出现之后,可以通过extends去继承类
  • 两者之间的区别:function的方式有些限制,并不能算真的继承,我们只是手动的处理了这个继承过程,而class和function的原型属性也是有区别的,class上定义的原型属性是不可枚举的,而function上的原型因为我们往往直接写,而不是用defineProperty去定义,所以它是可以枚举的

56.简单说一下下面几行代码内容?

import Vue from "vue";
//引入Vue因为我们要创建一个Vue实例,然后通过 new Vue生成Vue的实例
const app = new Vue({
//定义render方法,这个方法用来生成要渲染的虚拟DOM
  render: (createElement) =>
    createElement("div", "Hello World"),
});
//将Vue实例挂载到一个真实的DOM节点上,这里挂载的是document.body上
//app.$mount这个是Vue实例的方法,Vue实例是个对象,每个对象都有原型,Vue类原型上有$mount方法,所有我们可以在Vue实例上调用$mount方法
app.$mount(document.body);

57.Vue中,为什么推荐使用组件来开发?

  • 使用组件可以减少虚拟DOM和Diff开销,这个是从内部原理上来说的,所以,不管何时,都应该尽量做成组件去调用

58.Vue中的每个组件都需要注册才可以使用吗?

  • 组件不一定是要注册才可以使用的,注册的目的是给组件一个组件注册表,用的时候去里面找定义,因为App只会被用一次,所以我们可以在这减少注册组件的过程,让render函数直接使用App组件定义生成虚拟DOM

59.在移动端使用click事件300ms的延迟问题应该如何解决?

  • (1)出现的原因:不能确定用户是单击页面,还是双击页面,所以厂商设置300ms的延迟
  • (2)解决方式:
    1.禁止网页缩放,meta标签,最主要的是meta:user-scalable=no
    2.插件,fastclick.js,script引入,
     if ('addEventListener' in document) {
    	        document.addEventListener('DOMContentLoaded', function() {
       	         FastClick.attach(document.body);
    	    }, false);
	}

60.移动端touch事件都有什么?移动端的touch事件有穿透问题,该如何解决?

  • (1)使用移动端的touch事件,记得加上on,touchstart:开始触摸事件;touchmove:手指滑动事件,touchend:触摸结束事件
  • (2)解决方式:
    1.阻止默认行为 e.prevenDefault()
    2.插件,fastclick.js
   if ('addEventListener' in document) {
    	        document.addEventListener('DOMContentLoaded', function() {
       	         FastClick.attach(document.body);
    	    }, false);
	}

61.懒加载的原理是什么?

  • (1)优势:提高性能
  • (2)实现原理:图片是通过img的src属性,当src赋值时,浏览器就会请求图片资源,基于这个问题,我们可以利用标签自定义的属性(data-xxx)来保存图片,当我们需要加载图片的时候,将data-xx赋值给src就可以实现按需加载了
  • (3)插件:lazyload,vant里面也有插件,element ui等等

62.说一说计算属性watcher?

  • (1)Vue对data里的属性做了劫持,所以可以当属性被set的时候,知道属性值的是否变化了,而watcher就是按需监测某个值是否变化了
  • (2)默认情况下,data中的属性只是被劫持了,如果一个监听都没有,是不会有任何作用的,所以可以说整个响应式的实现,不仅需要对数据的劫持,还需要对数据改变的监听
  • (3)Vue组件的定义中,有很多种使用watcher的方式,比如,在组件定义中,传入watch对象,或者调用Vue实例的this.$watch接口,不仅如此,属性值props的变动也是通过Watcher,当然,computed计算属性也依赖watcher,这里说的watcher是指Vue内部实现的Watcher类,它是监测数据改变的核心部分
  • (4)核心的Watcher,当数据被更新时,vm.foo=1这句话就会触发foo这个属性的set描述器,因为set被Vue劫持了,所以数据会先流经Vue的劫持器,那么Vue就读到了这个新的值1,这时候,Vue还没让新的值设置到vm.foo中,所以它可以获取到旧的vm.foo中的值,两个互相对比,如果变化了,那么就去触发监听器的更新
  • (5)Watcher是Vue的内置类,这个类是不对外暴露的,对外暴露的是封装后的方法$watcher

63.Vue的选项deep,immediate如何使用?

  • (1)deep指的是,要观察的依赖是只响应它自身的变化,当然也要响应它的子级的变化,比如this.a = {foo:1};如果改变this.a.foo,那么对于对于this.a来说,它是没改变的,所以这时候如果我们需要响应this.a.foo的改变,就要设置deep为true
  • (2)immediate,上图中第一个参数的监听函数无论如何都会执行一次,在设置监听器的时候就会执行第一次,但是回调函数要等第一次完成之后收集的依赖改变之后,通过对比在决定是否执行回调,而immediate就是不管如何,在第一次设置的时候就立即执行一次回调

64.数组去重的几种常见方法可以说一下吗?

   var arr = [1, 3, 4, 5, 1, 0, 534, 23, 1, 2, 2, 0]
        var arr1 = []
        // 第一种方法:
        //  for(var i=0; i<arr.length; i++){
        //      for(var j = i+1; j<=arr.length; j++){
        //          if(arr[i] === arr[j]){
        //              arr.splice(j, 1)
        //              j--
        //          }
        //         //  arr1.push(arr[i])
        //      }
        //  }
        // 第二种方法:
        // var newarr = new Set(arr)
        //  console.log(newarr)
        // 第三种方法:
        // for (var i = 0; i < arr.length; i++) {
        //     if (arr1.indexOf(arr[i]) === -1) {
        //         arr1.push(arr[i])
        //     }
        // }
        // console.log(arr1)

65.说一下computed下面两种写法的区别?

一种是
{
  data () {
    return {
      a: 1,
      b: 1
    };
  },
  computed: {
    sum () {
      return this.a + this.b;
    }
  }
}
另一种是
{
  data () {
    return {
      a: 1,
      b: 1,
      get sum () {
        return this.a + this.b;
      },
    };
  }
}
  • (1)在data里定义的属性都会被劫持的,但是在conputed里的不会,如果sum是定义在data里面的,那么Vue会劫持sum的get描述器,也就是说,当收集依赖的时候,收集到的依赖是this.sum
  • (2)而在computed中,因为不会劫持get描述器,所以拿sum的时候,其实拿的是this.a和this.b
  • (3)两者对比可以看出,在data里定义的sum。如果被当做依赖,那么依赖的项是sum,a,b;
    在computed定义的sum,如果被当做依赖,那么依赖项是a,b,computed中定义的属性没有被劫持,所以虽然把sum当做依赖没有问题,但是是多余的操作了,这是两者的区别之一
  • (4)第二个区别是Vue对computed做了额外的优化,因为computed相当于get,所以每次读sum的值的时候,其实就是读this.a和this.b的值,然后再做一次求和,这里做了一次求和的运算,如果说,我们定义的computed中的运算很复杂,那么computed就不好用了,所以Vue对computed做的额外的优化是,会缓存前一次返回的结果,也就是说,第一次this.a + this.b完成之后,他就缓存了这个值,下次再读this.sum的时候,不会再读a和b的值的运算了,直接就取了上次缓存的值,只有当a或b的值有变化时,才重新在计算一遍sum,并且又把重新计算的值缓存起来了
  • (5)小总结:data里的sum是没有缓存的,除了依赖项多了sum之外,每次都还需要重新计算
    computed里的sum是有缓存的,所以除了依赖性和只依赖必须项外,依赖项不变也不需要重新计算,哪怕重新获取值也只算一遍