判断 js 类型的方式及基本数据类型
js 中常见的数据类型:
string
number
boolean
underfined
Null
NaN
object
symbol
- typeof
可以判断出'string','number','boolean','underfined','symbol'
当判断typeof(null)时值为'object',判断数组和对象的值均为'object'
- instanceof
原理是 构造函数的 prototype 属性是否出现在对象的原型链中的任何位置
function A() {}
let a = new A();
a instanceof A
- Object.prototype.toString
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用
Axios
Vue2.0之后,尤雨溪推荐大家用axios替换JQuery ajax,想必让axios进入了很多人的目光中。
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,
它本身具有以下特征:
1.从浏览器中创建 XMLHttpRequest
2.支持 Promise API
3.客户端支持防止CSRF
4.提供了一些并发请求的接口(重要,方便了很多的操作)
5.从 node.js 创建 http 请求
6.拦截请求和响应
7.转换请求和响应数据
8.取消请求
9.自动转换JSON数据
防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
cookie,sessionStorage和localStorage
- cookie用来保存登录信息,大小限制为4KB左右
- localStorage是Html5新增的,用于本地数据存储,保存的数据没有过期时间,一般浏览器大小限制在5MB
- sessionStorage接口方法和localStorage类似,但保存的数据的只会在当前会话中保存下来,页面关闭后会被清空。
cookie 跨域问题
- nginx反向代理
反向代理是以代理服务器来接受Internet上的请求,然后将请求转发给内部网络服务器;并将从服务器上得到的结果返回给Internet上连接的客户端,此时代理服务器对外就表现为一个服务器。
upstream web1{
server 127.0.0.1:8089 max_fails=0 weight=1;
}
upstream web2 {
server 127.0.0.1:8080 max_fails=0 weight=1;
}
location /web1 {
proxy_pass http://web1;
proxy_set_header Host 127.0.0.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
log_subrequest on;
}
location /web2 {
proxy_pass http://web2;
proxy_set_header Host 127.0.0.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
log_subrequest on;
}
- jsonp
- nodejs superagent 其实本质也是jsonp的方式
postMessage
是浏览器自带属性,支持IE8+,假如你的网站不需要支持IE6和IE7,那么可以使用,支持跨域;window.postMessage是客户端和客户端直接的数据传递,既可以跨域传递,也可以同域传递。
localStorage跨域
可以使用postMessage和iframe
思路如下:
假设有a页面和b页面,两个页面。
通过a页面去修改b页面的本地数据:
> ① 在a页面创建一个iframe,嵌入b页面。
> ② a页面通过postMessage传递指定格式的消息给b页面。
> ③ b页面解析a页面传递过来的消息内容,调用localStorage API 操作本地数据。
> ④ b页面包装localStorage的操作结果,并通过postMessage传递给a页面。
> ⑤ a页面解析b页面传递回来的消息内容,得到 localStorage 的操作结果。
跨域
什么是跨域?
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。
什么是同源策略?
同源策略/ SOP(Same origin policy)是一种约定,由Netscape公司发布。它是浏览器最核心,也最基本的安全功能,如果有了同源策略,所谓相似是指协议+域名+端口三者相同,如果有一个不同,即为非同源。
跨域解决方案:
- cors 跨域资源共享
服务器设置响应头:
response.setHeader("Access-Control-Allow-Origin", "*")
可能引起CSRF攻击
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
- jsonp
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
jsonp缺点:只能实现get一种请求。
- jquery ajax
$.ajax({
url: 'http://www.domain2.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
CORS与JSONP 区别
- JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
- 使用CORS,可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
- JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。[低版本IE7以下不支持,要支持IE7还是要用jsonp方式]
var 、let 和const区别
- 在作用域方面
var 声明的变量不存在块及作用
let 声明的变量存在块及作用域、
- 在变量提升方面
var 声明的变量存在变量提升
let const声明的变量不存在变量提升 唯一不同的是 const 声明的变量一旦赋值就不能再改变了
- 在重复声明方面
var 可以多次声明,let不存在多次声明
const和let基本相同 唯一不同的是const声明的变量一旦赋值就不能在改变。
promise
promise 是异步编程的解决方案和回调函数的使用有关.多个回调函数使用行成回调地狱。
function timeout(time){
return new Promise((resolve,reject)=>{
setTimeout(resolve,time);
})
Promise.all() 所有的promise实例状态,以长时间为准
Promise.race() 任一个状态改变,以短时间为准
基础promise封装
functionajax(url) {
return newPromise(function (resolve, reject) {
if (window.XMLHttpRequest) {
var xhr=newXMLHttpRequest();
} else {
var xhr=newActiveXObject("Microsoft.XMLHTTP");
}
xhr.open("GET", url, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState==4) {
if (xhr.status==200) {
var data = xhr.responseText;
resolve(data);
}
}
}
})
}
闭包的概念及优缺点?
闭包的概念:
就是在一个函数外部能够访问该函数内部局部变量的函数。
优点:
避免全局变量的污染。
希望一个变量长期储存在内存中。
缺点:
内内存泄漏
增加内存的使用量
深拷贝和浅拷贝的区别
浅拷贝:是将原对象和原数组的引用直接赋值给新数组,新对象/新数组只是原对象的一个引用。
Object.assign()
Array.prototype.slice()
扩展运算符 ...
深拷贝:是将原对象和原数组的值直接拷贝给新的对象和数组。
JSON.parse(JSON.stringify())
谈谈js的垃圾回收机制
JavaScript拥有自动的垃圾回收机制,当一个值,在内存中失去引用时,垃圾回收机制会根据特殊的算法找到它,并将其回收,释放内存。
标记清除算法:
- 标记阶段,垃圾回收器会从根对象开始遍历。每一个可以从根对象访问到的对象都会被添加一个标识,于是这个对象就被标识为可到达对象。
- 清除阶段,垃圾回收器会对堆内存从头到尾进行线性遍历,如果发现有对象没有被标识为可到达对象,那么就将此对象占用的内存回收,并且将原来标记为可到达对象的标识清除,以便进行下一次垃圾回收操作。
- 缺点:垃圾收集后有可能会造成大量的 内存碎片。
引用计数算法:
- 引用计数的含义是跟踪记录每个值被引用的次数,如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。
- 缺点: 循环引用没法回收。
ajax的用途,ajax请求的五种状态
- AJAX是“Asynchronous JavaScript And XML”的缩写,是一种实现无页面刷新获取服务器数据的混合技术。
- XMLHttpRequest 对象是浏览器提供的一个API,用来顺畅地向服务器发送请求并解析服务器响应,当然整个过程中,浏览器页面不会被刷新。
- .open()方法接收三个参数:请求方式(get or post),请求URL地址和是否为异步请求的布尔值。“同步”意味着一旦请求发出,任何后续的JavaScript代码不会再执行,“异步”则是当请求发出后,后续的JavaScript代码会继续执行,当请求成功后,会调用相应的回调函数。
http和https的区别?
- https协议需要申请证书,一般不免费
- http是超文本传输协议,信息是明文传输的,https具有安全性,https采用的是加密传输协议。
- http和https采用的不同的连接方式,http端口号是80,https端口号是443.
get 和 post 区别
- get 传输不安全,因为数据放在请求的 url 中;post 所有操作用户是看不到的。
- get 传输数据量小,因为受到 url 长度的限制;post 传输的数据量较大,一般不受限制。
- get 执行效率比 post 更好。get 是 form 提交的默认方式。
数组去重
- ES6的set
let arr = [1,1,2,3,4,5,5,6]
let arr2 = [...new Set(arr)]
- reduce()
let arr = [1,1,2,3,4,5,5,6];
let arr2=arr.reduce()
- 双层 for 循环嵌套
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) {
//如果第一个等于第二个,splice方法删除第二个
arr.splice(j, 1);
j--;
}
}
}
- es5 方法,Ie8 以下不支持
var arrs = [];
//遍历当前数组
for (var i = 0; i < array.length; i++) {
//如果临时数组里没有当前数组的当前值,则把当前值push到新数组里面
if (arrs.indexOf(array[i]) == -1) {
arrs.push(array[i]);
}
}
return arrs;
- es6 利用 set 去重
function newArr(arr) {
return Array.from(new Set(arr));
}
- sort 去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
arr = arr.sort()
var arrry= [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对
开头结尾的空格
xxx.trim()
bom 和 dom 有什么区别,常见的 bom 对象有哪些?
区别:
BOM 是 Browser Object Model 缩写,即浏览器对象模型
Dom 是 Document Object Model 缩写,即文档对象模型
常见的 bom 对象有:
- window 对象——BOM 核心
- document 对象
-
location 对象
获得当前页面的 URL,并重定向到新的页面- location.herf
- location.port
- navigator 对象
获得与浏览器有关的信息
userAgent 是最常用的属性,用来完成浏览器判断 - screen 对象
主要用来获取用户的屏幕信息。 -
history 对象
- back() 返回上一页。
- forward() 返回下一页
- go(“参数”) -1 表示上一页,1 表示下一页。
变量提升(变量的声明提升)
第一步:预编译阶段。先扫描当前环境中所有声明的变量,包括变量声明和函数声明,将这些声明提升到原来的位置。
第二步:代码执行阶段。在原来的位置进行运算或者输出等操作。
DOM 事件有哪些阶段?谈谈对事件代理的理解
或者问:js 事件传播流程是什么?
主要分为三个阶段,分别是:
捕获阶段
目标阶段
冒泡阶段
事件代理,通俗的说是事件委托,就是说利用冒泡原理,事件不直接绑定到某原元素上,而是绑定到该元素的父元素上。
好处:(1)代码更简洁 (2)节省内存开支
同步和异步
Javascript语言的一大特色就是单线程,同一时间只能做一件事。这门语言的设计者意识到这个问题,于是将任务分为两种,一种是同步任务;另外一种就是异步任务。
同步是阻塞模式,当一个方法被调用时,调用者需要等待该发法执行完毕才能执行,我们就称这种方法时同步方法。
异步是非阻塞模式,当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法。
阻止事件流方式有哪些
- 阻止冒泡的方式有哪些?
IE8: 事件对象.cancelBubble=true
火狐:事件对象.stopPropagation();
- 阻止浏览器的默认行为有哪些?
event.preventDefault();//现代浏览器。
event.returnValue=false; //IE 低版本及部分现代浏览器。
return false;//兼容性比较好 最好用在代码的最后面。
DOM二级事件和普通事件的区别
1.捕获由外向内传播;冒泡由内向外。
2.传统事件不支持捕获;DOM2级事件支持捕获。
3.传统事件多个相同的事件名,会覆盖 ;DOM2级事件会依次执行。
4.DOM2级事件有兼容性的。
对前端性能优化有什么了解?一般都通过那几个方面去优化的?
- 减少请求数量
- 减小资源大小
- 优化网络连接
- 优化资源加载
- 减少重绘回流
- 性能更好的API
- webpack优化
回流和重绘有什么区别?以及分别介绍它们。
区别:
回流必将引起重绘,而重绘不一定引起回流。
回流:
当render tree中的一部分(或全部)元素的属性改变而需要更新构建页面。这就称为回流。
重绘:
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不影响布局的,称为重绘。
比方说:只有颜色改变的时候就只会发生重绘而不会引起回流,当页面布局和几何属性改变时就需要回流。
常用数组方法:
- isArray 监测该对象是否为数组 是为 true 否 为 false。
- filter
返回新数组,不会改变原数组,不会对空数组进行检测,只能做筛选,此方法会遍历完数组。
var arr = [1, 2, 3, 4];
var newArr = arr.filter((item, index) => {
return item % 2;
});
console.log(newArr); // [1,3];
- find
返回新数组,不会改变原数组,不会对空数组进行检测,只能做筛选,此方法满足条件立即跳出。
var arr = [1, 2, 3, 4];
var newArr = arr.filter((item, index) => {
return item === 1;
});
console.log(newArr); // [1];
- map
返回新数组,不会改变原数组,可以在原有数据基础上做运算。
var arr = [1, 2, 3, 4];
var newArr = arr.map((item, index) => {
return item + 1;
});
console.log(newArr); // [2,3,4,5];
- every
检测数组中的每一个元素是否都通过了 callback 测试,全部通过返回 true,否则返回 false。
var arr = [1, 2, 3, 4];
var arr1 = [1, 2, 3, "4"];
var newArr = arr.every(item => {
return typeof item === "number";
});
var newArr1 = arr1.every(item => {
return typeof item === "number";
});
console.log(newArr); // true
console.log(newArr1); // false
- reduce
对数组中的每个元素(从左到右或从右到左)执行 callback 函数累加,将其减少为单个值。
var arr = [1, 2, 3, 4];
var newArr = arr.reduce((sum, value) => {
return sum + value;
}, 0);
console.log(newArr); // 10
const concatArr = [
[0, 1],
[2, 3],
[4, 5]
].reduce((a, b) => {
return a.concat(b);
}, []);
字符串常用方法
1. split(),把字符串分割为子字符串数组。
2. slice() 提取字符串中两个指定索引号之间的字符(索引可以为负值,-1就是倒数第二位)。
3. substring() 提取字符串中两个索引之间的字符(两个索引不能为负值)。
4. indexOf() 返回指定字符创第一次出现的位置。
5. trim(),移除字符串首位空格,经常在对input和textarea的值做判断时用到。
6. search(),检索指定子串或者与正则表达式匹配的值,返回的值是数字。
7. replace(),替换指定子串或者与正则表达式匹配的子串。
8. match(),找到一个或者多个子串或者正则表达式的匹配。
9. toLowerCase(),把字符串转换成小写的。
10. toUpperCase(),把字符串转换成大写的。
map 和 foreach 区别
区别:
forEach(),不改变原数组,不会返回一个新的数组,没有返回值。
map(),不会改变原数组,会返回一个新的数组。
共同点:
参数一:function(currentValue, index, arr)必需
参数二: thisValue 可选
如何获取用户的浏览器是什么?
navigator.userAgent
排序算法
- 选择排序
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { // 寻找最小的数
minIndex = j; // 将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
- 冒泡排序
var examplearr=[8,94,15,88,55,76,21,39];
function sortarr(arr){
for(i=0;i<arr.length-1;i++){
for(j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
var temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
return arr;
}
sortarr(examplearr);
console.log(examplearr);
- 快速排序
function quickSort(arr){
if(arr.length<1){
return arr;
}
var pivotIndex=Math.floor(arr.length/2);//找到那个基准数
var pivot=arr.splice(pivotIndex,1)[0]; //取出基准数,并去除,splice返回值为数组。
var left=[];
var right=[];
for(var i=0;i<arr.length;i++){
if(arr[i]<pivot){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot],quickSort(right)); //加入基准数
}
arr=[2,1,5,8,3,7,4,6,9];
console.log(quickSort(arr)); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
- 斐波那契
特点:第三项等于前面两项之和
function fibonacci(num) {
if (num === 1 || num === 2) {
return 1
}
return fibonacci(num - 1) + fibonacci(num - 2)
}
函数的创建方式
- 函数声明
function functionName(){
}
- 函数表达式
functionName=function(){
}
- 构造函数
var functionName=new Function()
target、this、currentTarget 的区别
- target:触发事件的某个具体对象,只会出现在事件流的目标阶段(谁触发谁命中,所以肯定是目标阶段)
- currentTarget:绑定事件的对象,恒等于 this,可能出现在事件流的任意一个阶段中。
- 通常情况下 terget 和 currentTarget 是一致的,我们只要使用 terget 即可,但有一种情况必须区分这三者的关系,那就是在父子嵌套的关系中,父元素绑定了事件,单击了子元素(根据事件流,在不阻止事件流的前提下他会传递至父元素,导致父元素的事件处理函数执行),这时候 currentTarget 指向的是父元素,因为他是绑定事件的对象,而 target 指向了子元素,因为他是触发事件的那个具体对象。
<div id="one">
<div id="three"></div>
</div>
one.addEventListener('click',function(e){
console.log(e.target); //three
console.log(e.currentTarget); //one
},false);
target:获得触发事件的标签,currentTarget:得到绑定事件的标签
this 指向问题
宗旨就是:谁调用它,它就指向谁
- 箭头函数中的this指向它的环境。
- 构造函数调用,this 指向实例对象
- 对象方法调用, 此时 this 指向 该方法所属的对象
- 通过事件绑定, 此时 this 指向 绑定事件的对象
es6 新增的东西有哪些?
- 定义变量加入了 let const
- 封闭空间
- 字符串和变量的拼接
- 解构赋值
- 类和面向对象
如何改变this指向以及它们的区别
call apply bind
call和apply区别是参数个数不同。
call的参数可以无限个;而apply的参数最多只能有两个。
bind是创建一个新函数,与被调函数有相同的函数体。
jquery 中的绑定事件,有什么区别?
- on 支持事件委托。
- bind 不支持事件委托。
- one 为每一个匹配元素的特定事件(像 click)绑定一个一次性的事件处理函数。
jquery 中常见的元素选择方式有哪些,如何获取属性值?
一 选择器:
1. id 选择器: \$("#ID 名")
2. class 选择器: \$(".class 名")
3. 节点选择器:\$("标签名")
二 属性选择器:
- \$("div[id]") 选择所有含有 ID 属性的 div 元素
- \$("input[name='keyicom']") 选择所有的 name 属性等于的 div 元素
- \$("input[name!='keyicom']") 选择所有 name 属性不等于 keyicom 的 div 元素
- \$("input[name^="keyicom"]") 选择所有 name 属性以 keyicom 开头的 input 元素
- $("input[name$="keyicom"]") 选择所有 name 属性以 keyicom 结尾的 input 元素
- \$("input[name*="keyicom"]") 选择所有 name 属性以 keyicom 结尾的 input 元素
三 jQuery CSS 选择器.
$("p").css("background-color","red");
四.jQuery 表单选择器.
:input $(":input") 所有 表单 元素
:text $(":text") 所有 type="text" 的 <input> 元素
:password $(":password") 所有 type="password" 的 <input> 元素
:radio $(":radio") 所有 type="radio" 的 <input> 元素
:checkbox $(":checkbox") 所有 type="checkbox" 的 <input> 元素
:submit $(":submit") 所有 type="submit" 的 <input> 元素
:reset $(":reset") 所有 type="reset" 的 <input> 元素
:button $(":button") 所有 type="button" 的 <input> 元素
:image $(":image") 所有 type="image" 的 <input> 元素
:file $(":file") 所有 type="file" 的 <input> 元素
:enabled $(":enabled") 所有激活的 input 元素
:disabled $(":disabled") 所有禁用的 input 元素
:selected $(":selected") 所有被选取的 input 元素
:checked $(":checked") 所有被选中的 input 元素
面向对象
特点:封装,继承,多态
- 封装
把一些数据和对数据的操作集中在一起,向外暴露需要的接口(属性和方法) -
继承
一个类型的实例能够访问另外一个类型的属性和方法。 类和类之间的关系 子类继承父类,你只不过是子类中的实例。构造函数继承
function Person(name,age){
this.name = name;
this.age = age;
this.sayHello = function(){
console.log(this.name);
}
}
function Male(name,age){
1. /*this.name = name;
this.age = age;
this.sayHello = function(){
console.log(this.name);
};*/
2. Person.call(this,name,age);//实现继承
this.sexy = "male";
}
var male = new Male("john1",21);
male.sayHello();
原型链继承
function Person() {}
Person.prototype.name = "john1";
Person.prototype.age = 21;
Person.prototype.sayHello = function () {
console.log(this.name);
}
// var person = new Person();
// console.log(person.age,person.hasOwnProperty('age'));
function Male() {
}
Male.prototype = new Person(); //让子类的原型对象等于父类的实例 实现继承
Male.prototype.sexy = "male";
var male = new Male();
male.sayHello();
console.log(male.__proto__ == Male.prototype);
console.log(Male.prototype.__proto__ == Person.prototype);
组合继承
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function(){
console.log(this.name);
}
function Male(name,age){
Person.call(this,name,age);//继承实例属性
}
//Male.prototype = new Person();//构造函数再次执行一次
/*Male.prototype = Person.prototype;//指向一致,修改会受到影响
Male.prototype.sayHi = function(){
console.log("hi");
}*/
for(var i in Person.prototype){
Male.prototype[i] = Person.prototype[i];//继承原型方法
}
Male.prototype.sayHi = function(){
console.log("hi");
}
var male = new Male("john1",21);
male.sayHello();
male.sayHi();
var person = new Person();
person.sayHi();
寄生组合式继承
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function(){
console.log(this.name);
}
function Male(name,age){
Person.call(this,name,age);//继承实例属性
}
//Object.create(obj) obj是创建出来的对象的原型对象 obj1.__proto__ == obj
/*var obj = {a:1,b:2};
var obj1 = Object.create(obj);
console.log(obj1);*/
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
class 继承
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
sayHello(){
console.log(this.name);
}
static foo(){
//类本身的方法
console.log("foo");
}
}
Person.foo();
class Male extends Person{
constructor(name,age){
super(name,age);//创建this对象,改变this指向;指向父类的构造函数
this.sexy = "male";
}
sayHi(){
console.log("hi");
super.sayHello();//在子类的原型方法里,super指向父类的原型对象
}
static bar(){
super.foo();//在静态方法里,super指向父类
}
}
Male.bar();
let male = new Male("john1",21);
//male.sayHello();
male.sayHi();
-
多态
所谓多态,就是同一个方法的多种调用方式
ajax 请求是以什么格式发送请求
- put 请求正文是类似 get 请求 url 的请求参数
-
post,请求正文是一个 json 格式的字符串
$.ajax({ type: "post", url: "topupRecordController.do?updateReceiptInfo", data: { refNo: rowsData[0].refNo }, dataType: "json", success: function(result) {} });
原型和原型链
- 原型对象也是普通的对象,是对象一个自带隐式的 proto 属性,原型也有可能有自己的原型,如果一个原型对象的原型不为 null 的话,我们就称之为原型链
- 原型链是由一些用来继承和共享属性的对象组成的(有限的)对象链
- 每一个构造函数都有一个原型对象prototype,每一个原型对象都有一个指向构造函数的指针construct,每一个实例都有一个指向原型对象的内部指针-proto-,原型对象上的属性和方法都能被实例所访问到。
对象的常见操作
- Object.keys(obj) 返回对象的key组成的数组。
返回一个所有元素为字符串的数组,其元素来自于从给定的object上面可直接枚举的属性,不会返回原型上的方法。
const obj = {
firstname:"John",
lastname:"Doe",
age:50,
eyecolor:"blue"
};
console.log(Object.keys(obj))
['firstname', 'lastname', 'age', 'eyecolor'] //返回key组成的数组
- Object.values(obj) 返回对象的value组成的数组。
返回一个由value组成的数组,其元素是在对象上找到的可枚举属性值。
const obj = {
firstname:"John",
lastname:"Doe",
age:50,
eyecolor:"blue"
};
console.log(Object.values(obj))
['John', 'Doe', 50, 'blue'] //返回value组成的数组
- Object.assign() 可以将源对象复制到目标对象中
Object.assign(target, ...sources)
target 为目标对象,...sources 为源对象(可以为多个对象)
// 浅拷贝对象
const obj = {
firstname:"John",
lastname:"Doe",
age:50,
love:{
color: "blue",
sport: "football"
}
};
const copy = Object.assign({}, obj);
console.log(copy) // 返回浅拷贝的对象,修该obj会同时修改copy的值
// 合并多个对象
const obj = {
firstname:"John",
lastname:"Doe",
age:50,
love:{
color: "blue",
sport: "football"
}
};
const obj2 = { other: "cat" };
const obj3 = { car: "Benz" };
const compose = Object.assign(obj, obj2, obj3); // 返回三个对象合并组成的对象,如有相同属性则会被后续参数中具有相同属性覆盖。
// 深拷贝对象
const obj = {
firstname:"John",
lastname:"Doe",
age:50,
love:{
color: "blue",
sport: "football"
}
};
const deepClone = JSON.parse(JSON.stringify(obj)); // 返回深拷贝的对象,修改obj不会影响该对象
- Object.entries(obj) 返回对象的key和value组成的数组
Object.entries(obj) 方法返回一个对象key和value键值对组成的数组
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj));
// [["foo", "bar"], ["baz", 42]]
- obj.hasOwnProperty() hasOwnProperty 方法判断对象中属性是否存在
const obj = {
firstname:"John",
lastname:"Doe",
age:50,
love:{
color: "blue",
sport: "football"
}
};
console.log(obj.hasOwnProperty('love')) // true
浏览器安全问题 xss 和 cors
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
XSS 全称“跨站脚本”,是注入攻击的一种。其特点是不对服务器端造成任何伤害,而是通过一些正常的站内交互途径,例如发布评论,提交含有 JavaScript 的内容文本。
节流和防抖
防抖
防抖是指在一段时间内,函数被触发多次,但是只执行一次,当达到了一定的时间间隔就会执行一次
function debounce(fn, delay) {
let timer = null;
return function () {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
}
}
节流
节流是会有规律的每隔时间n就执行一次函数。
function throttle(fn, cycle) {
let start = Date.now();
let now;
let timer;
return function () {
now = Date.now();
clearTimeout(timer);
if (now - start >= cycle) {
fn.apply(this, arguments);
start = now;
} else {
timer = setTimeout(() => {
fn.apply(this, arguments);
}, cycle);
}
}
}
浏览器打开网页都经历了什么?
浏览器的主要功能是将用户选择的web资源呈现出来,它从服务器请求资源,并将得到的资源(HTML,PDF,image等等)显示在浏览器窗口。
整个过程大致如下:
1. 输入URL,浏览器根据域名寻找IP地址
2. 浏览器发送一个HTTP请求给服务器,如果服务器返回以301之类的重定向,浏览器根据相应头中的location再次发送请求
3. 服务器接受请求,处理请求生成html代码,返回给浏览器,这时的html页面代码可能是经过压缩的
4. 浏览器接收服务器响应结果,如果有压缩则首先进行解压处理
5. 浏览器开始显示HTML
6. 浏览器发送请求,以获取嵌入在HTML中的对象。在浏览器显示HTML时,它会注意到需要获取其他地址内容的标签。这时,浏览器会发送一个获取请求来重新获得这些文件——包括CSS/JS/图片等资源,这些资源的地址都要经历一个和HTML读取类似的过程。所以浏览器会在DNS中查找这些域名,发送请求,重定向等等
说一下浏览器是如何渲染的?
浏览器渲染引擎在获取到内容后的基本流程:
1. 解析HTML
2. 构建DOM树
3. DOM树与CSS样式进行附着构造呈现树(render树)
4. 布局
5. 绘制
如何实现对一个DOM元素的深拷贝,包括元素的绑定事件?
//使用cloneNode,但是在元素上绑定的事件不会拷贝
function clone(origin) {
return Object.assign({},origin);
}
//实现了对原始对象的克隆,但是只能克隆原始对象自身的值,不能克隆她继承的值,如果想要保持继承链,可以采用如下方法:
function clone(origin) {
let originProto=Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto),origin);
}
谈谈js事件循环机制
- 程序开始执行之后,主程序则开始执行 同步任务,碰到 异步任务 就把它放到任务队列中,等到同步任务全部执行完毕之后,js引擎便去查看任务队列有没有可以执行的异步任务,将异步任务转为同步任务,开始执行,执行完同步任务之后继续查看任务队列,这个过程是一直 循环 的,因此这个过程就是所谓的 事件循环,其中任务队列也被称为事件队列。通过一个任务队列,单线程的js实现了异步任务的执行,给人感觉js好像是多线程的。
async 和 await
原理:async 和 await 用了同步的方式去做异步,async 定义的函数的返回值都是 promise,await 后面的函数会先执行一遍,然后就会跳出整个 async 函数来执行后面js栈的代码
== 和 === 区别
- ==, 两边值类型不同的时候,要先进行类型转换,再比较
- ===,不做类型转换,类型不同的一定不等。
==类型转换过程:
- 如果类型不同,进行类型转换
- 判断比较的是否是 null 或者是 undefined, 如果是, 返回 true .
- 判断两者类型是否为string 和 number, 如果是, 将字符串转换成 number
- 判断其中一方是否为 boolean, 如果是, 将boolean 转为 number 再进行判断
- 判断其中一方是否为 object 且另一方为 string、number 或者
symbol , 如果是, 将 object 转为原始类型再进行判断
经典面试题:[] == ![] 为什么是true
转化步骤:
- !运算符优先级最高,![]会被转为为false,因此表达式变成了:[] == false
- 根据上面第(4)条规则,如果有一方是boolean,就把boolean转为number,因此表达式变成了:[] == 0
- 根据上面第(5)条规则,把数组转为原始类型,调用数组的toString()方法,[]转为空字符串,因此表达式变成了:'' == 0
- 根据上面第(3)条规则,两边数据类型为string和number,把空字符串转为0,因此表达式变成了:0 == 0
- 两边数据类型相同,0==0为true
0.1+0.2!=0.3怎么处理
把需要计算的数字升级(乘以10的n次幂)成计算机能够精确识别的整数,等计算完成后再进行降级(除以10的n次幂),即:
(0.1*10 + 0.2*10)/10 == 0.3 //true
更多关于浮点数精度处理请看JS中浮点数精度问题
谈谈你对函数柯里化理解
- 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
- 用途:1.延迟计算;2.参数复用;3.动态生成函数
const curry = (fn, currArgs=[]) => {
return function() {
let args = Array.from(arguments);
[].push.apply(args,currArgs);
if (args.length < fn.length) {
return curry.call(this,fn,...args);
}
return fn.apply(this,args);
}
}
JS如何实现继承
首先创建一个父类
// 定义一个动物类
function Animal(name, color) {
// 属性
this.name = name || 'Animal';
this.color = color || ['black'];
// 实例方法
this.sleep = function () {
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function (food) {
console.log(this.name + '正在吃:' + food);
};
- 原型链继承
new了一个空对象,这个空对象指向Animal并且Cat.prototype指向了这个空对象,这种就是基于原型链的继承。
function Cat(name) {
this.name = name || 'tom'
}
Cat.prototype = new Animal()
var cat = new Cat()
cat.color.push('red')
cat.sleep() //tom正在睡觉!
cat.eat('fish') //tom正在吃:fish
console.log(cat.color) //["black", "red"]
console.log(cat instanceof Animal) //true
console.log(cat instanceof Cat) //true
var new_cat = new Cat()
console.log(new_cat.color) //["black", "red"]
特点:基于原型链,既是父类的实例,也是子类的实例。
缺点:1.无法实现多继承;2.所有新实例都会共享父类实例的属性。
- 构造继承
function Dog(name) {
Animal.call(this)
this.name = name || 'mica'
}
var dog = new Dog()
dog.color.push('blue')
dog.sleep() // mica正在睡觉!
dog.eat('bone') //Uncaught TypeError: dog.eat is not a function
console.log(dog.color) //["black", "blue"]
console.log(dog instanceof Animal) //false
console.log(dog instanceof Dog) //true
var new_dog = new Dog()
console.log(new_dog.color) //["black"]
特点:可以实现多继承(call多个),解决了所有实例共享父类实例属性的问题。
缺点:1.只能继承父类实例的属性和方法;2.不能继承原型上的属性和方法。
- 组合继承
function Mouse(name){
Animal.call(this)
this.name = name || 'jerry'
}
Mouse.prototype = new Animal()
Mouse.prototype.constructor = Mouse
var mouse = new Mouse()
mouse.color.push('yellow)
mouse.sleep() //jerry正在睡觉!
mouse.eat('carrot') //jerry正在吃:carrot
console.log(mouse instanceof Animal)//true
console.log(mouse instanceof Mouse)//true
var new_mouse = new Mouse()
console.log(new_mouse.color) //["black"]
特点:可以继承实例属性/方法,也可以继承原型属性/方法
缺点:调用了两次父类构造函数,生成了两份实例。
讲讲对d3的理解,讲讲d3与echarts的区别
- d3正如其名 Data Driven Documents,其本质是将数据与 DOM 绑定,并将数据映射至 DOM 属性上;
- d3与echarts的区别:
- d3通过svg绘制图形,可以自定义事件。svg不依赖分辨率,继续xml绘制图形,可以操作dom。支持事件处理器,复杂度高,会减慢页面的渲染速度。
- echarts通过canvas来绘制图形,用户通过配置 options 参数,就可很容易绘制指定图表。canvas依赖分辨率,基于js绘制图形,不支持事件处理,能以png或者jpg的格式保存图片。
递归函数
function cloneObject(obj) {
var newObj = {} //如果不是引用类型,直接返回
if (typeof obj !== 'object') {
return obj
}
//如果是引用类型,遍历属性
else {
for (var attr in obj) {
//如果某个属性还是引用类型,递归调用
newObj[attr] = cloneObject(obj[attr])
}
}
return newObj
}
设计模式
一、单例模式
二、策略模式
三、代理模式
四、迭代器模式
五、发布—订阅模式
六、命令模式
七、组合模式
八、模板方法模式
九、享元模式
十、职责链模式
十一、中介者模式
十二、装饰者模式
十三、状态模式
十四、适配器模式
十五、外观模式
HTTP
- 什么是 HTTP
HTTP 是一个连接客户端,网关和服务器的一个协议。
- 特点
支持客户/服务器模式:可以连接客户端和服务端;
简单快速:请求只需传送请求方法,路径和请求主体;
灵活:传输数据类型灵活;
无连接:请求结束立即断开;
无状态:无法记住上一次请求。
- 请求过程
HTTP(S) 请求地址 → DNS 解析 → 三次握手 → 发送请求 → 四次挥手
- 三次握手
- 四次挥手
- 状态码
- 浏览器请求分析
- 总结
协议
缓存
判断是否是数字?
isNaN 是数字返回 false,不是数字返回 true
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。