JavaScript部分

一 js基础知识

1.js分为七种内置类型

  基本类型:string,number,boolean,null,undefiend,Symbol;引用类型:Object

2.TypeOf 

  TypeOf除了null,其他基本类型都会正确显示

  NaN是number类型

  

typeOf null //Object

 

3.类型转换

  • 转Boolean

  在条件判断时,除了undefined,null,0,-0,NaN, false,“ ”;其他所有值都转换为 true

  • 对象转基本类型

  对象在转换基本类型时,首先会调用 valueOf 然后调用 toString。并且这两个方法都是可以重写的

let a = {
    valueOf() {
       return 0 
    }
}

  当然也是可以重写 Symbol.toPrimitive,该方法在转基本类型时调用优先级最高

let a = {
  valueOf() {
    return 0;
  },
  toString() {
    return "1"
   },
   [Symbol.toPrimitive]() {
        return 2;
    }   
}

1 + a //  3
"1" + a  // "12"
  • 四则运算符

  只有当加法运算时,其中一方是字符串类型,会把另一个也转为字符串类型;且加法会触发三种类型转换:值→原始值(toPrimitive),数字,字符串

  其他运算只要其中一方是数字,那另一方就转为数字

1 + “1”  // "11"
2 * "2"  // 4
[1, 2] + [2, 1]  // "1,22,1"

// [1, 2].toString()    →“1,2”
// [2, 1].toString()    →“2,1”
// "1,2" + "2,1" = "1,22,1"

  对于 +  需要注意这个表达式 ‘a’ + + ‘b’

'a' + + 'b'     //'aNaN'
//因为 + 'b' →NaN
  • ==操作符

  [ ] == ![ ]   // true

[] == ![]    //true
// []转为true,然后取反变成false
[] == false
[] == ToNumber(false)
[] == 0
ToPrimitive([]) == 0
//[].toString()  → ‘ ’
“ ” == 0
0 == 0     //true
  • 比较运算符

  如果是对象,就通过 toPrimitive 转换对象

  如果是字符串,就通过 unicode 字符索引来比较

 

二  引起内存泄漏的操作有哪些?

  1 全局变量引起

function leaks () {
    leak = "我是全局变量";      //leak会成为全局变量,不会被回收
}

  2 闭包引起

var leaks = (function() {
     var leak = "我是闭包";    //被闭包所引用,不会被回收
     return function() {
        console.log(leak);
    }
})

  3 dom清空,事件未清除

$("#container").bind("click", function() {
    console.log("click");
}).rremove();
//zepto和原生js下,#container还在内存里;
//Jquery的empty和remove会帮助开发者避免这个问题



$("#container").bind("click", function() {
    console.log("click");
}).off("click").remove();
//把事件清除了,即可从内存中移除

 

  4 子元素存在引用

var refA = document..getElementById("refA");
var refB = document..getElementById("refB");
document.body.removeChild(refA);
refA = null;
refB = null;

 

  5 被遗忘的计时器

 

三  如何实现ajax请求

  通过实例化XMLHttpRequest对象得到一个实例,调用实例的open方法为这次ajax请求设定相应的http方法,相应的地址以及是否异步,多数情况下异步,以异步为例,之后调用send方法ajax请求,这个方法可以设定需要发送的报文主体,然后通过监听readystatechange事件,通过这个实例的readyState属性来判断这个ajax请求状态,当状态为4时,数据接收完成,这是可以通过实例的status属性判断请求是否成功;代码实现如下:

var xhr = XMLHttpRequest();
xhr.open('get', 'aaa.php', true);
xhr.send(null);
xhr.onreadystatechange = function() {
    if(xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
    }
}

 

四 简要介绍ES6

  ES6在变量和声明方面增加了let、const声明变量,有局部变量的概念,赋值中有比较吸引人的解构赋值,同时ES6对字符串,数组,正则,对象,函数等都扩展了一些方法,如字符串方面的模板字符串,函数方面的默认参数,对象方面属性的简洁表达方式,ES6也引入了新的数据类型symbol,新的数据结构set和map,symbol可以通过typeof检测出来,为解决异步回调的问题,引入了promise和generator,还有最为吸引人的实现Class和模块,通过Class可以更好的面向对象编程,使用模块加载方便模块化编程,当然考虑到浏览器的兼容性,我们在实际开发中需要使用babel进行编译。

 

五 对JS原型的理解

  在ES6之前,js没有类和继承的概念,js是通过原型来实现继承的。在js中一个构造函数默认自带一个prototype属性,这个的属性值是一个对象,同时这个prototype对象自带一个constructor属性,这个属性指向这个构造函数,同时每一个实例都有一个_proto_属性指向这个prototype对象,我们可以将这个叫做隐式原型,我们在十一一个实例的方法的时候,会先检查这个实例中是否有这个方法,没有则继续往上查找这个prototype对象是否有这个方法,刚刚我们说到prototype是一个对象,那么也即是说这个是一个对象的实例,那么这个对象同样也会有一个_proto_属性指向对象的prototype对象

 

六 对JS模块化的理解

  在ES6之前,js没有标准的模块化概念,这也就造成了许多人开发容易造成全局污染的情况,以前我们可能会采用立即执行函数,对象等方式来尽量减少变量这种情况,后面社区为了解决这个问题陆续提出了AMD和CMD规范,这不同于Node.js的CommonJS的原因在于服务端所有模块都是存在于硬盘中,加载和读取几乎是不需要时间的,而浏览器端因为加载速度取决于网速,因此需要采用异步加载,AMD规范中使用define来定义一个模块,使用require方法来加载一个模块,现在ES6也推出了标准的模块加载方案,通过export和import来导出和导入模块。

 

七 简要介绍事件代理,以及什么时候使用,事件代理发生在事件处理流程的哪个阶段,有什么好处?

  事件代理就是将事件添加到本来要添加事件的父节点,将事件委托给父节点来触发处理函数,通常会使用咋大量同级元素需要添加同一类事件的时候;比如一个动态的非常多的列表,需要为每个列表项都添加点击事件,这时可以使用事件代理,通过判断e.target.nodeName来判断发生的具体元素,从而判断是否是在列表项中触发,这样的好处是可以减少事件绑定,同时动态的DOM依然可以监听。事件代理发生在事件冒泡阶段

 

八 使用new操作符实例化一个对象的具体步骤

  1.构造一个新的对象

  2.将构造函数的作用域赋给新对象(也就是this指向了新的对象)

  3.执行构造函数中的代码

  4.返回新对象

 

九 js如何判断网页中图片加载成功或失败

  使用onload事件运行加载成功,使用onerror事件判断失败

 

十 递归和迭代的区别是什么,各有什么优缺点?

  程序调用自身称为递归,利用变量的原值推出新值称为迭代,递归的优点(大问题转化为小问题,可以减少代码量,同事代码精简,可读性好),缺点是(浪费了空间,而且递归太深容易造成堆栈的溢出);迭代的好处是(代码运行效率高,因为时间只因循环次数增加而增加,而且没有额外的空间开销),缺点就是(代码不如递归简洁)。

 

十一 策略模式是什么,说一下理解?

  策略模式就是说我们将一系列的算法封装起来,使其相互之间可以替换,封装的算法具有一定的独立性,不会随客户端的变化而变化,比较常见的使用就是类似于表单验证这种多场景的情况,我们使用策略模式就可以避免使用一堆if…else。

 

十二 什么是事件循环(EVENT LOOP)?

  我们常说JS是单线程的,是指js执行引擎是单线程的,除了这个县城,还有一个任务队列,在执行js代码的过程中,执行引擎遇到注册是延时方法,如定时器,DOM事件,会将这些方法交给相应的浏览器模块处理,当这些延时方法有触发条件去触发的时候,这些延时方法会被添加至任务队列,而这些任务队列中的方法只有js的主线程空闲了才会执行,这也就说我们常常用的定时器的时间参数只是一个触发条件,具体多少时间后执行其实还需要看js主线程空闲与否

 

十三 原生JS操作DOM的方法有哪些?

  获取节点的方法有getElementById,getElementsByClassName,getElementsByTagName,getElementsByName,querySelector,querySelectorAll

  对元素属性进行操作的getAttribute,setAttribute,removeAttribute 方法

  对节点进行增删改的appendChild,insertBefore,replaceChild,removeChild,createElement等

 

十四 typeof操作符返回值有哪些,对undefined,null,NaN使用这个操作符分别返回什么?

  typeof的返回值有undefined,boolean,string,number,object,function,symbol;

  对undefined使用返回undefined,null使用返回object,NaN使用返回number

 

十五 实现一个类型判断函数,需要鉴别出基本类型,function,null,NaN,数组,对象?

  

function type(ele) {
    if (ele == null) {
        return null;
    } else if (typeof ele === 'object') {
        if (Array.isArray(ele)){
            return 'array';
        } else {
            return typeof ele;
        }
    } else if (typeof ele === 'number'){
        if (isNaN(ele)) {
            return NaN;
        } else {
            return typeof ele
        }
    } else {
        return typeof ele;
    }
}        

 

十六 javascript做类型判断的方法有哪些?

  typeof,instanceof,Object.prototype.toString() ……

 

十七 javascript严格模式下有哪些不同?

  1.不允许不使用var关键字去创建全局变量,抛出ReferenceError;

  2.不允许对变量使用delete操作符,抛ReferenceError

  3.不可对对象的只读属性赋值,不可对对象的不可配置属性使用delete操作符,不可为不可扩展对象添加属性,均抛ReferenceError

  4.对象的属性名必须唯一

  5.函数中不可有重名参数

  6.在函数内部对参数修改不会反应到arguments中

  7.淘汰arguments.callee和arguments.caller

  8.不可在if内部声明函数

  9.抛弃with语句

 

十八 setTimeOut和setInterval的区别,包含内存方面的分析?

  setTimeOut表示间隔一段时间之后执行一次调用,而setIntervel则是每间隔一段时间循环调用,知道clearInterval结束。内存方面,setTimeout只需要进入一次队列,不会造成内存溢出,setInterval因为不计算代码执行时间,有可能同时执行多次代码,导致内存溢出

 

十九 同源策略是什么?

  同源策略是指只有具有相同源的页面才能共享数据,比如cookie,同源是指页面具有相同的协议,域名,端口号,有一项不同就不是同源。同源策略能够保证web网页的安全性

 

二十 ES6之前javascript如何实现继承?

  ES6之前的继承是通过原型来实现的,也就是每一个构造函数都会有一个prototype属性,然后如果我们调用一个实例的方法或者属性,首先会在自身寻找,然后在构造函数的prototype上寻找,而prototype本质上就是一个实例,因此如果prototype上还没有则会往prototype上的构造函数的prototype寻找,因此试下继承可以让构造函数的prototype是父级的一个实例就是以实现继承

二十一 如何阻止事件冒泡和默认事件?

  标准的DOM对象转给你可以使用事件对象的stopPropagation()方法来阻止事件冒泡,但在IE8以下中IE的事件对象通过设置事件对象的cancelBubble属性为true来阻止冒泡;默认事件的话通过事件对象的preventDefault()方法来阻止,而IE通过设置事件对象的returnValue属性为false来阻止默认事件。

 

二十二 addEventListener有哪些参数?

  三个参数,第一个是事件的类型,第二个是事件的回调函数,第三个是一个表示事件是冒泡阶段还是捕获阶段的布尔值,true表示捕获,false表示冒泡

 

二十三 介绍一下Promise,底层如何实现?

 

二十四 如何实现懒加载?

  懒加载就是根据用户浏览需要记载内容,也就是在用户即将浏览完当前的内容时进行继续加载内容,这种技术常常用来加载图片时使用,我们判断用户是否即将浏览到底部之后进行加载内容,这时候可能会需要加载大量的内容,可用fragment来优化一下,因为大部分是使用滑动和滚轮来触发的,因为很有可能会不断触发,可以使用函数节流做一个优化,防止用户不断触发

 

二十五 函数节流是什么?

  函数节流就是让一个函数无法在很短的时间间隔内连续调用,而是间隔一段时间执行,这在我们为元素绑定一些事件的时候经常会用到,比如为window绑定了一个resize事件,如果用户一直改变窗口大小,就会一直触发这个事件处理函数,这对性能影响很大

 

二十六 浏览器内核有哪些?分别对应哪些浏览器?

  Trident对应于IE,Geoko对应火狐浏览器,Webkit有chrome和safari,Presto有Opera

 

二十七 什么是深拷贝,什么是浅拷贝?

  浅拷贝是指仅仅复制对象的引用,而不是复制对象本身;深拷贝则是把复制对象所引用的全部对象都复制一遍。

 

二十八 原生JS字符串方法有哪些?

  获取类的方法有charAt,charCodeAt,fromCharCode;

  查找类的方法有indexOf(),lastIndexOf(),search(),match()

  截取类的方法有substring,slice,substr

  其他replace,split,toLowerCase,toUpperCode

 

二十九 原生js字符串截取的方法有哪些,有什么区别?

  js字符串截取方法有substring,slice,substr三个方法,substring和slice都是指定截取的首尾索引值,不同的是传递负值时,substring当做0处理,而slice传入负值的规则是-1表示最后一个字符;substr方法则是从第一个参数开始截取字符串,第二个是截取的字符串的数量,和slice类似,传入的负值也从尾部算起的。

 

三十 介绍一下装饰者模式,职责链模式,并实现?

  装饰者模式:在不改变原对象的基础上,对这个对象进行包装和扩展(包括添加属性和方法),从而使这个对象可以有更复杂的功能;

  职责链模式:将一个流程进行分解,让这个流程在多个对象中进行传递,由最后一个对象完成这个流程。通过职责链模式能够将流程进行分解,从而解耦。

 

三十一 请说一下实现jsonp的实现思路?

  (1) jsonp是一种跨域通信的手段,原理如下:

  • 首先是利用script标签的src属性来实现跨域。
  • 通过将前端方法作为参数传递到服务器,然后由服务器注入参数之后再返回,实现服务器端向客户端通信
  • 由于使用script标签的src属性,因此只支持get方法

  (2) 实现流程

  • 设定一个script标签
    <script src="http://jsonp.js?callback=xxx"></script>
  • callback定义一个函数名,而远程服务端通多调用指定的函数并传入参数来实现传递参数,将fn(response)传递回客户端
    $callback = !empty($_GET['callback']) ? $_GET['callback'] : 'callback';
    echo $callback.'(.json_encode($data).)';
  • 客户端接收到返回的js脚本,开始解析和执行fn(response)

  (3) jsonp简单实现

  • 一个简单的jsonp实现,其实就是拼接url,然后将动态添加一个script元素到头部
    function jsonp(req){
        var script = document.createElement('script');
        var url = req.url + '?callback=' + req.callback.name;
        script.src = url;
        document.getElmentsByTagName('head')[0].appendChild(script);
    }
  • 前端js示例
    function hello(res){
        alert('hello' + res.data)
    };
    jsonp({
        url: '',
        callback: hello
    })
  • 服务器端代码
    var http = require('http');
    var urllib = require('url');
    
    var port = 8080;
    var data = {'data':'world'};
    
    http.createServer(function(req,res){
        var params = urllib.parse(req.url,true);
        if(params.query.callback){
            console.log(params.query.callback);
            //jsonp
            var str = params.query.callback + '(' + JSON.stringify(data) + ')';
            res.end(str);
        } else {
            res.end();
        }
        
    }).listen(port,function(){
        console.log('jsonp server is on');
    });

     

 

  

posted @ 2020-06-08 16:16  落燕喃飞  阅读(135)  评论(0)    收藏  举报