1、JavaScript有哪些垃圾回收机制?
有以下垃圾回收机制。
标记清除( mark and sweep)
这是 JavaScript最常见的垃圾回收方式。当变量进入执行环境的时候,比如在函数中声明一个变量,垃圾回收器将其标记为“进入环境”。当变量离开环境的时候(函数执行结束),将其标记为“离开环境”。
垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量,以及被环境中变量所引用的变量(闭包)的标记。在完成这些之后仍然存在的标记就是要删除的变量。
引用计数( reference counting)
在低版本的E中经常会发生内存泄漏,很多时候就是因为它采用引用计数的方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数。
当声明了一个变量并将个引用类型赋值给该变量的时候,这个值的引用次数就加1.如果该变量的值变成了另外一个,则这个值的引用次数减1.当这个值的引用次数变为0的时候,说明没有变量在使用,这个值没法被访问。
因此,可以将它占用的空间回收,这样垃圾回收器会在运行的时候清理引用次数为0的值占用的空间在正中虽然 JavaScript对象通过标记清除的方式进行垃圾回收,但是BOM与DOM对象是用引用计数的方式回收垃圾的。
也就是说,只要涉及BOM和DOM,就会出现循环引用问题
2、谈谈 script标签中 defer和 async属性的区别。
区别如下。
(1) defer属性规定是否延迟执行脚本,直到页面加载为止, async属性规定脚本一旦可用,就异步执行。
(2) defer并行加载 JavaScript文件,会按照页面上 script标签的顺序执行, async并行加载 JavaScript文件,下载完成立即执行,不会按照页面上 script标签的顺序执行。
3、说说你对闭包的理解。
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染;缺点是闭包会常驻内存,增加内存使用量,使用不当很容易造成内存泄漏。在JavaScript中,函数即闭包,只有函数才会产生作用域
闭包有3个特性:
(1)函数嵌套函数。
(2)在函数内部可以引用外部的参数和变量
(3)参数和变量不会以垃圾回收机制回收
4、什么是闭包( closure)?,为什么要用闭包?
闭包指的是一个函数可以访问另一个函数作用域中变量。常见的构造方法,是在一个函数内部定义另外一个函数。内部函数可以引用外层的变量;外层变量不会被垃圾回收机制回收。
注意,闭包的原理是作用域链,所以闭包访问的上级作用域中的变量是个对象,其值为其运算结束后的最后一个值。
优点:避免全局变量污染。缺点:容易造成内存泄漏。
例子:
function makeFunc() {
var name = "Mozilla";
function displayName() {
console.log(name);
}
return displayName; }
var myFunc = makeFunc();
myFunc(); //输出Mozilla
myFunc 变成一个 闭包。闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。在我们的例子中,myFunc 是一个闭包,由 displayName 函数和闭包创建时存在的 "Mozilla" 字符串形成。
5、请解释一下 JavaScript的同源策略。
同源策略是客户端脚本(尤其是 JavaScript)的重要安全度量标准。它最早出自Netscape Navigator2.0,目的是防止某个文档或脚本从多个不同源装载。
这里的同源策略指的是协议、域名、端口相同。同源策略是一种安全协议。指一段脚本只能读取来自同一来源的窗口和文档的属性。
6、为什么要有同源限制?
我们举例说明。比如一个黑客,他利用 Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名、密码登录时,他的页面就可以通过 Javascript读取到你表单上 Input中的内容,这样黑客就会轻松得到你的用户名和密码。
7、js的基本数据类型有哪些?
Undefined、Number、String、Boolean、Null
ECMAScript 2015 新增:Symbol(创建后独一无二且不可变的数据类型 )
javascript的typeof返回的数据类型有:
· undefined
· number
· string
· boolean
· Object
· Function
8、js有哪些内置对象?
Object 是 JavaScript 中所有对象的父对象
数据封装类对象: Object、 Array、 Boolean、 Number 和 String
其他对象: Function、 Arguments、 Math、 Date、 RegExp、 Error
9、谈谈 This 对象的理解?
this 总是指向函数的直接调用者( 而非间接调用者) ;
如果有 new 关键字, this 指向 new 出来的那个对象;
在事件中, this 指向触发这个事件的对象, 特殊的是, IE 中的 attachEvent 中的 this 总是指向
全局对象 Window;
10、documen.wrte和 innerHTML的区别是什么?
document.wite重绘整个页面;innerHTML可以重绘页面的一部分。
11、请说几条书写 JavaScript语句的基本规范。
基本规范如下:
(1)不要在同一行声明多个变量。
(2)应使用==/!==来比较true/ false或者数值。
(3)使用对象字面量替代 new Array这种形式。
(4)不要使用全局函数。
(5) switch语句必须带有 default分支。
(6)函数不应该有时有返回值,有时没有返回值。
(7)for循环必须使用大括号括起来。
(8)if语句必须使用大括号括起来。
9)for-in循环中的变量应该使用war关键字明确限定的作用域,从而避免作用域污染。
12、实现数组的随机排序?
var arr = [1,2,3,4,5,6,7,8,9,10];
arr.sort(function(){
return Math.random() - 0.5;
})
console.log(arr);
13、Javascript 作用链域?
全局函数无法查看局部函数的内部细节, 但局部函数可以查看其上层的函数细节, 直至全局
细节。
当需要从局部函数查找某一属性或方法时, 如果当前作用域没有找到, 就会上溯到上层作
用域查找,
直至全局函数, 这种组织形式就是作用域链。
14、JavaScript原型,原型链?有什么特点?
每个对象都会在其内部初始化一个属性, 就是 prototype(原型), 当我们访问一个对象的属
性时, 如果这个对象内部不存在这个属性, 那么他就会去 prototype 里找这个属性, 这个 prototype
又会有自己的 prototype,于是就这样一直找下去, 也就是我们平时所说的原型链的概念。
关系: instance.constructor.prototype = instance.proto
特点:
JavaScript 对象是通过引用来传递的, 我们创建的每个新对象实体中并没有一份属于自己的
原型副本。 当我们修改原型时, 与之相关的对象也会继承这一改变。
15、null, undefined 的区别?
null 表示一个对象是“ 没有值” 的值, 也就是值为“ 空” ;
undefined 表示一个变量用 var 声明了但有初始化(赋值);
undefined 不是一个有效的 JSON, 而 null 是;
undefined 的类型(typeof)是 undefined;
null 的类型(typeof)是 object;
注意:
在验证 null 时, 一定要使用 === , 因为 == 无法分别 null 和 undefined
null == undefined // true
null === undefined // false
16、 new操作符具体干了什么呢?
- 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
- 属性和方法被加入到 this 引用的对象中。
- 新创建的对象由 this 所引用,并且最后隐式的返回 this 。
17、IE 与火狐的事件机制有什么区别?如何阻止冒泡?
- 事件处理机制: IE 是事件冒泡、 Firefox 同时支持两种事件模型, 也就是: 捕获型事件
和冒泡型事件; - ev.stopPropagation();(旧 ie 的方法 ev.cancelBubble = true;)
18、Ajax 是什么? 如何创建一个 Ajax?
ajax 的全称: Asynchronous Javascript And XML。
异步传输+js+xml。
所谓异步, 在这里简单地解释就是: 向服务器发送请求的时候, 我们不必等待结果, 而是
可以同时做其他的事情, 等到有了结果它自己会根据设定进行后续操作, 与此同时, 页面是
不会发生整页刷新的, 提高了用户体验。
(1)创建 XMLHttpRequest 对象,也就是创建一个异步调用对象
(2)创建一个新的 HTTP 请求,并指定该 HTTP 请求的方法、 URL 及验证信息
(3)设置响应 HTTP 请求状态变化的函数
(4)发送 HTTP 请求
(5)获取异步调用返回的数据
(6)使用 JavaScript 和 DOM 实现局部刷新
简单的 ajax 原理分析:
//打开浏览器
var xhr = new XMLHttpRequest();
//在地址栏输入地址
xhr.open('get','1.txt',true);
//提交
xhr.send(); //在这一步才会发送网络请求(上面是准备工作)
//等待服务器返回内容
xhr.onreadystatechange = function() {
if ( xhr.readyState == 4 ) {
if ( xhr.status == 200 ) { //200 表示 http 请求正确
alert( xhr.responseText );
} else {
alert('出错了,Err: ' + xhr.status); //返回错误信息
}
}
}
/js 封装好后的 ajax 函数/
function ajax(opt) {
defaultOpt = { //默认函数参数
"method":'get', //默认为 get 传输
"data":'', //默认没有数据
"url":'',
"succeed": function(datas){} //默认获取到数据后什么都不做
}
extend(defaultOpt, opt); //配置参数赋值给默认参数
var xhr = new XMLHttpRequest();
if (defaultOpt.method == 'get' && defaultOpt.data) { //调用默认参数
defaultOpt.url += '?' + defaultOpt.data;
} x
hr.open(defaultOpt.method, defaultOpt.url, true);
if (defaultOpt.method == 'get') {
xhr.send();
} else {
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
xhr.send(defaultOpt.data);
} x
hr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
| defaultOpt.succeed && defaultOpt.succeed(xhr.responseText); 方用参数传入, 代码块就用函数传入 | //可变的地 |
| ----------------------------------------------------------------------------- | ------ |
} else {
alert('出错了' + xhr.status);
}
}
}
} f
unction extend(obj1, obj2) {
for (var attr in obj2) {
obj1[attr] = obj2[attr]
}
}
调用形式:
ajax({
"url": 'url 地址',
"method":'请求方式',
"data": '传给后台的参数数据',
"succeed": function (datas) { //datas 为后台传回来的数据
//var data = JSON.parse(datas); //把字符串类数组, 转换为对象
}
});
19、什么是跨域问题 ,如何解决跨域问题?
要明白什么是跨域之前,首先要明白什么是同源策略?
同源策略就是用来限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。那怎样判断是否是同源呢?
如果协议,端口(如果指定了)和主机对于两个页面是相同的,则两个页面具有相同的源,也就是同源。也就是说,要同时满足以下3个条件,才能叫同源:
- 协议相同
- 端口相同
- 主机相同
举个例子就一目了然了:
我们来看下面的页面是否与 http://store.company.com/dir/index.html 是同源的?
http://store.company.com/dir/index2.html同源http://store.company.com/dir2/index3.html同源 虽然在不同文件夹下https://store.company.com/secure.html不同源 不同的协议(https)http://store.company.com:81/dir/index.html不同源 不同的端口(81)http://news.company.com/dir/other.html不同源 不同的主机(news)
跨域的几种解决方案
1)、document.domain方法
我们来看一个具体场景:有一个页面 http://www.example.com/a.html ,它里面有一个iframe,这个iframe的源是 http://example.com/b.html ,很显然它们是不同源的,所以我们无法在父页面中操控子页面的内容。
解决方案如下:
<!-- b.html -->
<script>document.domain = 'example.com';</script>
<!-- a.html -->
<script>
document.domain = 'example.com';
var iframe = document.getElementById('iframe').contentWindow.document;
//后面就可以操作iframe里的内容了...
</script>
所以我们只要将两个页面的document.domain设置成一致就可以了,要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域。
但是,这种方法只能解决主域相同的跨域问题。
2)、window.name方法
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
我们来看一个具体场景,在一个页面 example.com/a.html 中,我们想获取 data.com/data.html 中的数据,以下是解决方案:
<!-- data.html -->
<script>window.name = 'data'; //这是就是我们需要通信的数据</script>
<!-- a.html -->
<script>
function getData () {
var iframe = document.getElementById('iframe');
iframe.src = 'example.com/b.html'; // 这里让iframe与父页面同源
iframe.onload = function () {
var data = iframe.contentWindow.name; //在这里我们得到了跨域页面中传来的数据
};
}
</script>
3)、JSONP方法
JONSP(JSON with Padding)是JSON的一种使用模式。基本原理如下:
<!-- a.html -->
<script>
function dealData (data) {
console.log(data);
}
</script>
<script src='http://example.com/data.php?callback=dealData'></script>
<?php $callback = $_GET['callback']; $data = 'data'; echo $callback.'('.json_encode($data).')';?>
这时候在a.html中我们得到了一条js的执行语句dealData('data'),从而达到了跨域的目的。
所以JSONP的原理其实就是利用引入script不限制源的特点,把处理函数名作为参数传入,然后返回执行语句,仔细阅读以上代码就可以明白里面的意思了。
如果在jQuery中用JSONP的话就更加简单了:
<script>
$.getJSON(''http://example.com/data.php?callback=?', function (data) {
console.log(data);
})
</script>
注意jQuery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用JSONP的回调函数。
4、CORS(跨域资源共享)
20、DOM 操作——怎样添加、移除、移动、复制、创建和查找节点?
( 1) 创建新节点
| createDocumentFragment() | //创建一个 DOM 片段 |
|---|---|
| createElement() createTextNode() | //创建一个具体的元素 //创建一个文本节点 |
( 2) 添加、 移除、 替换、 插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子节点前插入一个新的子节点
( 3) 查找元素
//通过标签名称
document. getElementsByTagName("标签名")
//通过 name 属性来获取表单元素
document.getElementsByName("name 属性的属性值")
//通过元素 Id,唯一性
document.getElementById("id 名")
//通过 class 来选中元素
document. getElementsByClassName("类名")
使用HTML5新增的选择器
querySelector()表示选取满足选择条件的第 1 个元素
querySeletorAll()表示选取满足条件的所有元素。
21、js 中某些兼容性的问题的解决方案?
1.把 input 元素的 type 属性在发生某事件后变成自己想要的 type 值。
比如在点击单行文本框时, 变成复选框。 那么在旧版本的 ie 浏览器是不支持的, 那么我们
就需要学会一个思想, 就是不要直接改 type 值, 而是把文本框在点击时隐藏起来, 实现隐
藏的复选框在点击时出现。
所以说我们为了实现一个效果可以换个思想实现。
2.当我们要改 div 的 float 值时, 也存在兼容性问题。
odiv.style.styleFloat = 'left';
odiv.style.cssFloat = 'left';
IE(styleFloat)、非IE(cssFloat)
22、call,apply,bind的用法与区别?**
call/apply/bind方法的来源
首先,在使用call,apply,bind方法时,我们有必要知道这三个方法究竟是来自哪里?为什么可以使用的到这三个方法?
call,apply,bind这三个方法其实都是继承自Function.prototype中的,属于实例方法。
console.log(Function.prototype.hasOwnProperty('call')) //true
console.log(Function.prototype.hasOwnProperty('apply')) //true
console.log(Function.prototype.hasOwnProperty('bind')) //true
上面代码中,都返回了true,表明三种方法都是继承自Function.prototype的。当然,普通的对象,函数,数组都继承了Function.prototype对象中的三个方法,所以这三个方法都可以在对象,数组,函数中使用。
(1)、Function.prototype.call()
函数实例的call方法,可以指定该函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。并且会立即执行该函数。
看个例子来好好理解这段话。
var keith = {
rascal: 123
};
var rascal = 456;
function a() {
console.log(this.rascal);
}
a(); //456
a.call(); //456
a.call(null); //456
a.call(undefined); //456
a.call(this); //456
a.call(keith); //123
上面代码中,a函数中的this关键字,如果指向全局对象,返回结果为456。可以看到,如果call方法没有参数,或者参数为null或undefined或者this,则等同于指向全局对象。如果使用call方法将this关键字指向keith对象,也就是将该函数执行时所在的作用域为keith对象,返回结果为123。
call()方法可以传递两个参数。第一个参数是指定函数内部中this的指向(也就是函数执行时所在的作用域),第二个参数是函数调用时需要传递的参数。
function keith(a, b) {
console.log(a + b);
}
keith.call(null, 1, 2); //3
第一个参数是必须的,可以是null,undefined,this,但是不能为空。设置为null,undefined,this表明函数keith此时处于全局作用域。第二个参数中必须一个个添加。而在apply中必须以数组的形式添加。
(2)、Function.prototype.apply()
apply方法的作用与call方法类似,也是改变this指向(函数执行时所在的作用域),然后在指定的作用域中,调用该函数。同时也会立即执行该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。
apply方法的第一个参数也是this所要指向的那个对象,如果设为null或undefined或者this,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,在调用时传入原函数。原函数的参数,在call方法中必须一个个添加,但是在apply方法中,必须以数组形式添加。
看一下call,apply的细微差别。
function keith(a, b) {
console.log(a + b);
}
keith.call(null, 2, 3); //5
keith.apply(null, [2, 3]); //5
上面代码中,第一个参数为null,指向全局作用域;第二个参数传入的形式稍稍不同。
apply、call方法有以下应用:
找出数组中的最大值
var a = [2, 4, 5, 7, 8, 10];
console.log(Math.max.apply(null, a)); //10
console.log(Math.max.call(null,2, 4, 5, 7, 8, 10)); //10
(4)、Function.prototype.bind()
bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数。
var keith = {
a: 1,
count: function() {
console.log(this.a++);
}
};
keith.count(); //1
keith.count(); //2
keith.count(); //3
上面代码中,如果this.a指向keith对象内部的a属性,如果这个方法赋值给另外一个变量,调用时就会出错。
var keith = {
a: 1,
count: function() {
console.log(this.a++);
}
};
var f = keith.count;
f(); //NaN
上面代码中,如果把count方法赋值给f变量,那么this对象指向不再是keith对象了,而是window对象。而window.a默认为undefined,进行递增运算之后undefined++就等于NaN。
为了解决这个问题,可以使用bind方法,将keith对象里的this绑定到keith对象上,或者是直接调用。
var f = keith.count.bind(keith);
f(); //1
f(); //2
f(); //3
当然,this也可以绑定到其他对象上。
var obj = {
a: 100
};
var f = keith.count.bind(obj);
f(); //100
f(); //101
f(); //102
同样,我们也可以给bind方法传递参数,第一个参数如果为null或者undefined或者this,会将函数内部的this对象指向全局环境;第二个为调用时需要的参数,并且传递参数的形式与call方法相同。
function keith(a, b) {
return a + b;
}
console.log(keith.apply(null,[1,4])); //5
console.log(keith.call(null,1,4)); //5
console.log(keith.bind(null, 1, 4)); //keith()
console.log(keith.bind(null, 1, 4)()); //5
上面代码中,可以看出call,apply,bind三者的区别:call和apply方法都是在调用之后立即执行的。而bind调用之后是返回原函数,需要再调用一次才行, 有点像闭包的味道
23、数组去重方式?
es6方式
let arr = [1, 2, 2, 3, "a", "a"];
let result = Array.from(new Set(arr));
console.log(result); //[1, 2, 3, "a"]
24、一个页面从输入URL到页面加载显示完成的详细过程
1、 浏览器查找域名对应的 IP 地址;
2、 浏览器根据 IP 地址与服务器建立socket连接( 三次握手) ;
主机向服务器发送一个建立连接的请求( 您好, 我想认识您 ) ;
服务器接到请求后发送同意连接的信号( 好的, 很高兴认识您 ) ;
主机接到同意连接的信号后, 再次向服务器发送了确认信号( 我也很高兴认
识您) , 自此, 主机与服务器两者建立了连接。
3、 浏览器与服务器通信: 浏览器请求, 服务器处理请求;
浏览器根据 URL 内容生成 HTTP 请求, 请求中包含请求文件的位置、 请求文件的方式
等等;
服务器接到请求后, 会根据 HTTP 请求中的内容来决定如何获取相应的 HTML 文件;
服务器将得到的 HTML 文件发送给浏览器;
在浏览器还没有完全接收 HTML 文件时便开始渲染、 显示网页;
在执行 HTML 中代码时, 根据需要, 浏览器会继续请求图片、 CSS、 JavsScript 等文件,
过程同请求 HTML ;
4、 浏览器与服务器断开连接(四次挥手) 。
主机向服务器发送一个断开连接的请求( 不早了, 我该走了 ) ;
服务器接到请求后发送确认收到请求的信号( 知道了 ) ;
服务器向主机发送断开通知( 我也该走了 ) ;
主机接到断开通知后断开连接并反馈一个确认信号( 嗯, 好的 ) , 服务器收到确认信
号后断开连接;
25、 优雅降级与渐进增强
渐进增强(progressive enhancement)
针对低版本浏览器进行构建页面, 保证最基本的功能, 然后再针对高级浏览
器进行效果、 交互等改进和追加功能达到更好的用户体验。
优雅降级(graceful degradation)
一开始就构建完整的功能, 然后再针对低版本浏览器进行兼容。
26、sql注入原理
就是通过把 SQL 命令插入到 Web 表单递交或输入域名或页面请求的查询字符串, 最终
达到欺骗服务器执行恶意的 SQL 命令。
总的来说有以下几点:
1.永远不要信任用户的输入, 要对用户的输入进行校验, 可以通过正则表达式, 或
限制长度, 对单引号和双"-"进行转换等。
2.永远不要使用动态拼装 SQL, 可以使用参数化的 SQL 或者直接使用存储过程进行
数据查询存取。
3.永远不要使用管理员权限的数据库连接, 为每个应用使用单独的权限有限的数据
库连接。
4.不要把机密信息明文存放, 请加密或者 hash 掉密码和敏感的信息。
27、对组件化和模块化的理解
模块化中的模块一般指的是 Javascript 模块,侧重于功能或者数据的封装,比如一个用来格式化时间的模块。
组件化更多关注的是 UI 部分, 你看到的一个管理界面的弹出框,头部,内容区,确认按钮和页脚都可以是个组件, 这些组件可以组成一个弹出框组件, 跟其他组件组合又是一个新的组件。
28、js的继承方式有哪些?
一、原型链继承
function Person(name){
this.name = name;
this.sum = function(){
alert(this.name)
}
}
Person.prototype.age = 10; //给构造函数添加了原型属性
function Child(){
this.name = 'Mike';
}
Child.prototype = new Person();
var child = new Child();
console.log(child.age)
console.log(child instanceof Person); //true
二、借用构造函数继承(原型冒充)
<script type="text/javascript">
function Person(name, age) {
this.name = name,
this.age = age,
this.setName = function () {}
}
Person.prototype.setAge = function () {}
function Student(name, age, price) {
Person.call(this, name, age) // 相当于: this.Person(name, age)
/*this.name = name this.age = age*/
this.price = price
}
var s1 = new Student('Tom', 20, 15000)
这种方式只是实现部分的继承,如果父类的原型还有方法和属性,子类是拿不到这些方法和属性的。
console.log(s1.setAge())//Uncaught TypeError: s1.setAge is not a function
三、复制继承(其实没有继承,只是复制) 就是把父对象的所有属性,直接复制到自己对象上来
function Good(){
this.iq=120;
this.study=function(){
console.log('高效学习');
}
}
function Bad(){
this.play=function(){
console.log('玩玩玩');
}
this.extend=function(obj){
for(var k in obj){
this[k]=obj[k];
}
}
}
var good=new Good();
var bad=new Bad();
bad.extend(good);
console.log(bad);
四、ES6中class 的继承
class Person {
//调用类的构造方法
constructor(name, age) {
this.name = name this.age = age
}
//定义一般的方法
showName() {
console.log("调用父类的方法")
console.log(this.name, this.age);
}
}
let p1 = new Person('kobe', 39)
console.log(p1)
//定义一个子类
class Student extends Person {
constructor(name, age, salary) {
super(name, age)//通过super调用父类的构造方法
this.salary = salary
}
showName() {
//在子类自身定义方法
console.log("调用子类的方法")
console.log(this.name, this.age, this.salary);
}
}
let s1 = new Student('wade', 38, 1000000000)
console.log(s1) s1.showName()
29、如何阻止事件冒泡和默认事件
e. stopPropagation();//标准浏览器
event.canceBubble=true;//ie9之前
阻止默认事件:
为了不让a点击之后跳转,我们就要给他的点击事件进行阻止
return false
e.preventDefault();
30、箭头函数和普通函数的区别
箭头函数在定义之后, this 就不会发生改变了, 无论用什么样的方式调用它, this 都不会改
变
箭头函数的 this 永远指向其上下文的 this, 任何方法都改变不了其指向, 如 call(), bind(), apply()
普通函数的 this 指向调用它的那个对象
31、页面重绘(repaint) 和页面回流(reflow)
css 与 dom 解析完毕后, 合并为渲染树(render tree)
重绘(repaint): 当 render tree 中的一些元素需要更新属性, 这些属性只会影响元素的
外观, 风格, 而不会影响到元素的布局, 此类的页面渲染叫作页面重绘。
回流(reflow): 当 render tree 中的一部分( 或全部) 因为元素的规模尺寸, 布局, 隐藏
等改变而引起的页面重新渲染。
可以看出, 回流必将引起重绘, 而重绘不一定会引起回流。
当页面布局和几何属性改变时就需要回流。
32、字符串反转
//思路:先将字符串转换为数组 split(),利用数组的反序函数 reverse()颠倒数组,再利用 join() 转为字符串
var str = '12345678';
str = str.split('').reverse().join('');
33、图片懒加载的原理及实现
懒加载的原理:
原理: 先将 img 标签中的 src 链接设为同一张图片( 空白图片) , 将其真正的图片地址
存储再 img 标签的自定义属性中( 比如 data-src) 。 当 js 监听到该图片元素进入可视窗口时,
即将自定义属性中的地址存储到 src 属性中, 达到懒加载的效果。
这样做能防止页面一次性向服务器响应大量请求导致服务器响应慢, 页面卡顿或崩溃等
问题。
既然懒加载的原理是基于判断元素是否出现在窗口可视范围内, 首先我们写一
个函数判断元素是否出现在可视范围内:
function isVisible($node){
var winH = $(window).height(),
scrollTop = $(window).scrollTop(),
offSetTop = $($node).offSet().top;
if (offSetTop < winH + scrollTop) { //元素到可视窗口顶部的距离 < window 高度+
滚动条高度的距离时, 说明元素已经进入了可视区范围。
return true;
} else {
return false;
}
}
2、 再添加上浏览器的事件监听函数, 让浏览器每次滚动就检查元素是否出现在窗口
可视范围内:
$(window).on("scroll", function{
if (isVisible($node)){
console.log(true);
}
})
3、 我们已经很接近了, 现在我们要做的是, 让元素只在第一次被检查到时打印 true,
之后就不再打印了
var hasShowed = false;
$(window).on("sroll",function{
if (hasShowed) {
return;
} else {
if (isVisible($node)) {
hasShowed = !hasShowed;
console.log(true);
}
}
})
34、CSS 预处理器的优缺点有哪些
优点: 用一种专门的编程语言, 为 CSS 增加了一些编程的特性, 减少冗余代码, 提高样
式代码的可维护性
缺点: 简单来说 CSS 预处理器语言较 CSS 玩法变得更高级了, 但同时降低了自己对最终
代码的控制力。 更致命的是提高了门槛, 首先是上手门槛, 其次是维护门槛, 再来是团队整
体水平和规范的门槛。 这也造成了初学学习成本的昂贵。
35、三栏布局之中间固定,左右两栏自适应
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>三栏布局之中间固定,左右两栏自适应</title>
<style type="text/css">
.layout.flex .page {
display: flex;
}
.layout.flex .left, .layout.flex .right {
flex: 1;
}
.layout.flex .center {
width: 200px;
}
</style>
</head>
<body>
<section class="layout flex">
<!-- flex布局方案 -->
<article class="page">
<div class="left">左边自适应</div>
<div class="center">flex布局-中间固定宽度部分</div>
<div class="right">右边自适应</div>
</article>
</section>
36、高度已知,三栏布局,左栏和右栏宽度固定,中间自适应
实现原理:首先定义三个区块,分别为左中右,并且统一设置高度为200px,然后在这三个区块的父元素中设置display:flex,设置左边栏和右边栏宽度为200px,中间区块设置flex:1
优点:比较完美的一种方式,在移动端基本都是使用这个布局方式,这是css3中的新的布局方式,当设置最小高度后,中间区块内容溢出时高度会自动撑开,左右两边的高度也可以跟着撑开
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
html *{
padding: 0;
margin: 0;
}
.layout.flexbox article div{
min-height: 200px;
}
.layout.flexbox .left-right-center{
display: flex;
}
.left{
width: 200px;
background-color: red;
}
.right{
width: 200px;
background-color: blue;
}
.center{
background-color: green;
flex: 1;
}
</style>
<body>
<section class="layout flexbox">
<article class="left-right-center">
<div class="left"></div>
<div class="center">flexbox解决方案</div>
<div class="right"></div>
</article>
</section>
</body>
</html>
效果如下:拉动浏览器窗口的时候,中间宽度自动变化,左右边栏不会变化
37、js中的隐式类型转换
基本数据类型的转换
1.加减乘除
加法:如果字符串加数字,数字就会转成字符串。而 数字加数字 或 字符串加字符串 则不需要进行转换直接进行运算或字符串拼接。
减法: 数字减字符串,字符串转成数字。如果字符串不是纯数字就会转成NaN。字符串减数字也一样。两个字符串相减也先转成数字。
乘,除,大于,小于跟减法的转换一样。
双等号 == :
undefined等于null
字符串和数字比较时,字符串转数字
布尔和数字比较时,布尔转数字
字符串和布尔比较时,两者转数字
// ==
undefined == null; //true
'0' == 0; //true,字符串转数字
false == 0; //true,布尔转数字
'0' == false; //true,两者转数字
38、事件绑定和普通事件有什么区别?(传统事件绑定和符合 W3C 标准的事件绑定有什么区别?)
div1.onclick=function(){};
1、 如果说给同一个元素绑定了两次或者多次相同类型的事件,那么后面的绑定会覆盖前面的绑定
2、 不支持 DOM 事件流 事件捕获阶段è目标元素阶段=>事件冒泡阶段
addEventListener(第三个参数默认为false,表示冒泡阶段)
1、 如果说给同一个元素绑定了两次或者多次相同类型的事件,所有的绑定将会依次触发
2、 支持 DOM 事件流的
3、 进行事件绑定传参不需要 on 前缀
addEventListener(“click”,function(){},true);
39、IE和 DOM 事件流的区别
1)执行顺序不一样
IE: 冒泡
DOM:捕获
2)参数不一样
IE:要加“on”(比如:onclick),且没有第三个参数
DOM:没有on(比如:click),有第三个参数,true为捕获,false为冒泡
3)事件对象event属性方法的差别
4)this指向问题
IE:this指向window
DOM:this指向触发该事件的对象
兼容写法:调用函数的call()方法
40、IE和标准下有哪些兼容性的写法
var ev = ev || window.event
document.documentElement.clientWidth || document.body.clientWidth
var target = ev.srcElement||ev.target
41、JavaScript中的this指针,闭包,作用域
this:指向调用上下文
闭包:内层作用域可以访问外层作用域的变量
作用域:定义一个函数就开辟了一个局部作用域,整个 js 执行环境有一个全局作用域
42、闭包是什么,有什么特性,对页面有什么影响
闭包就是能够读取其他函数内部变量的函数。
闭包的缺点:滥用闭包函数会造成内存泄露,因为闭包中引用到的包裹函数中定义的变量都永远不会被释放,所以我们应该在必要的时候,及时释放这个闭包函数
43、JavaScript中本地对象、内置对象和宿主对象有哪些**
1、本地对象
ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。
再来看一下,“本地对象”包含哪些内容:
Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError
由此可以看出,简单来说,本地对象就是 ECMA-262 定义的类。
2、内置对象
ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。
同样是“独立于宿主环境”。根据定义我们似乎很难分清“内置对象”与“本地对象”的区别。而ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。
可这个Global对象是啥东西呢?
Global对象是ECMAScript中最特别的对象,因为实际上它根本不存在,但大家要清楚,在ECMAScript中,不存在独立的函数,所有函数都必须是某个对象的方法。类似于isNaN()、parseInt()和parseFloat()方法等,看起来都是函数,而实际上,它们都是Global对象的方法。
3.宿主对象
由ECMAScript实现的宿主环境提供的对象,可以理解为:浏览器提供的对象。所有的BOM和DOM都是宿主对象。
43、document load 和document ready的区别
load是当页面所有资源全部加载完成后(包括DOM文档树,css文件,js文件,图片资源等),执行一个函数,load方法就是onload事件。
缺点:如果图片资源较多,加载时间较长,onload后等待执行的函数需要等待较长时间,所以一些效果可能受到影响。
$(document).ready()是当DOM文档树加载完成后执行一个函数 (不包含图片,css等)所以会比load较快执行
在原生的jS中不包括ready()这个方法,Jquery才有,jquery中有 $().ready(function)。
44、”==” 和 “===” 的不同
前者会自动转换类型后者不会
1==”1” //字符串转数字,结果为true
null==undefined //true
===先判断左右两边的数据类型,如果数据类型不一致,直接返回false 之后才会进行两边值的判断
45、javascript的同源策略
一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合
如果说想要请求其他来源的js文件,或者json数据,那么可以通过jsonp来解决
45、Javascript的事件流模型都有什么?
事件冒泡:事件开始由最具体的元素接受,然后逐级向上传播 事件捕捉:事件由最不具体的节点先接收,然后逐级向下,一直到最具体的
“DOM事件流”:三个阶段:事件捕捉,目标阶段,事件冒泡
46、MVC 与 MVVM 区别?
在 MVC 里, View 是可以直接访问 Model 的! 从而, View 里会包含 Model 信息, 不可避免
的还要包括一些业务逻辑。 MVC 模型关注的是 Model 的不变, 所以, 在 MVC 模型里, Model
不依赖于 View, 但是 View 是依赖于 Model 的。 不仅如此, 因为有一些业务逻辑在 View 里
实现了, 导致要更改 View 也是比较困难的, 至少那些业务逻辑是无法重用的。
MVVM 在概念上是真正将页面与数据逻辑分离的模式, 它把数据绑定工作放到一个 JS
里去实现, 而这个 JS 文件的主要功能是完成数据的绑定, 即把 model 绑定到 UI 的元素上。
有人做过测试: 使用 Angular(MVVM) 代替 Backbone(MVC) 来开发, 代码可以减少
一半。
此外, MVVM 另一个重要特性, 双向绑定。 它更方便你同时维护页面上都依赖于某个
字段的 N 个区域, 而不用手动更新它们。
47、jQuery 和 vue 有哪些区别, 分别使用场景
jquery: 使用选择器($) 选取 DOM 对象, 对其进行赋值、 取值、 事件绑定等操作, 其
实和原生的 javascript 的区别只在于可以更方便的选取和操作 DOM 对象, 而数据和页面是在一
起的。
vue: 通过 Vue 对象将数据和 View 完全分离开来了。 对数据进行操作不再需要引用相应
的 DOM 对象, 可以说数据和 View 是分离的, 他们通过 Vue 对象这个 vm 实现相互的绑定。
这就是传说中的 MVVM。
vue 适用的场景: 复杂的单应用页面; 复杂数据操作的后台页面, 表单填写页面, 侧重
数据绑定。
jquery 适用的场景: 比如说一些 html5 的动画页面, 一些需要 js 来操作页面样式的页面,
侧重样式操作, 动画效果等。
48、window.onload 何时执行, 浏览器如何渲染
window.onload 顾名思义 在页面加载后执行,包括文档, css, script, img, 以及 css 里的
background, 这个函数是确保页面所有元素加载完成时执行
49、对 seo 的理解和使用
SEO(Search Engine Optimization):汉译为搜索引擎优化。是一种方式:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名目的是让其在行业内占据领先地位,获得品牌收益。
1、 title: 只强调重点即可, 重要关键词出现不要超过 2 次, 而且要靠前, 每个页面 title 要
有所不同
2、 description: 把网页内容高度概括到这里, 长度要合理, 不可过分堆砌关键词, 每个页
面 description 要有所不同
3、 keywords: 列举出几个重要关键词即可, 也不可过分堆砌。
4、 语义化书写 HTML 代码, 符合 W3C 标准。
对于搜索引擎来说, 最直接面对的就是网页 HTML 代码, 如果代码写的语义化, 搜索引擎就
会很容易的读懂该网页要表达的意思。 例如文本模块要有大标题, 合理利用 h1-h6, 列表形
式的代码使用 ul 或 ol, 重要的文字使用 strong 等等。
5、 利用布局, 把重要内容 HTML 代码放在最前。
搜索引擎抓取 HTML 内容是从上到下, 利用这一特点, 可以让主要代码优先读取, 广告等不
重要代码放在下边。
6、 布局层次不要太深, 一般重要内容控制在三层之内。
7、 重要内容不要用 JS 输出。
蜘蛛不会读取 JS 里的内容, 所以重要内容必须放在 HTML 里。
8、 尽少使用 iframe 框架。
搜索引擎不会抓取到 iframe 里的内容, 重要内容不要放在框架中。
50、JS 中的 Navigator 对象
Navigator 对象包含有关浏览器的信息。
很多时候我们需要在判断网页所处的浏览器和平台, Navigator 为我们提供了便利
我们使用比较多的是userAgent, 经常需要判断的情况有:
(1) PC还是移动端
(2) 安卓还是 IOS
(3) 浏览器的类型
51、git 和 svn 的区别
1.git 是分布式的 scm,svn 是集中式的。 (最核心)
分布式: 因为每一个开发人员的电脑上都有一个本地仓库,所以即使没有网络也一样可
以 Commit, 查看历史版本记录, 创建项 目分支等操作, 等网络再次连接上 Push 到 Server
端。
集中式: SVN 只能有一个指定中央版本库。 当这个中央版本库有问题时, 所有工作成员
都一起瘫痪直到版本库维修完毕或者新的版本库设立完成。
2.git 是每个历史版本都存储完整的文件,便于恢复,svn 是存储差异文件,历史版本不可恢复。
(核心)
3.git 可离线完成大部分操作,svn 则不能。
4.git 有着更优雅的分支和合并实现。
5.git 有着更强的撤销修改和修改历史版本的能力
6.git 速度更快,效率更高。
基于以上区别,git 有了很明显的优势,特别在于它具有的本地仓库。
52、浏览器的 http 缓存机制
浏览器为什么要缓存? 什么会缓存下来?
首先当我们访问网页的时候, 很多大的图片从服务器上传输过来的时候, 试想一下, 如
果浏览器不把图片缓存下来而是每次都要到服务器去取, 那么每次都给服务器和网络造成了
巨大的负担。
对于静态资源来说, 浏览器不会缓存 html 页面的, 所以你每次改完 html 的页面的时候,
html 都是改完立即生效的, 不存在什么有缓存导致页面不对的问题。 浏览器缓存的东西有
图片, css 和 js。 这些资源将在缓存失效前调用的时候调用浏览器的缓存内容。
http 缓存是基于 HTTP 协议的浏览器文件级缓存机制。 即针对文件的重复请求情况下, 浏览
器可以根据协议头判断从服务器端请求文件还是从本地读取文件, 以下是浏览器缓存的整个
机制流程。 主要是针对重复的 http 请求。
53、dom 是什么
DOM (文档对象模型) 就是针对 HTML 和 XML 提供的一个 API(接口) 。 我们可以通过
DOM 来操作页面中各种元素, 例如添加元素、 删除元素、 替换元素等。
54、dom 的 api 有什么
document.forms 获取当前页面的所有form,返回一个HtmlCollection
55、POST和GET的区别
56、什么是事件代理,事件代理怎么实现?
事件代理(Event Delegation),又称之为事件委托。是JavaScript中绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown......)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
57、es6数组去掉重复且重新排序的方法
1、数组去掉重复元素
1)可以利用Array.from(new Set(arr))语句
2)可以利用[...new Set(arr)]语句
2、升序
var arr1 = arr.sort((x, y) => {
return x - y
});
58、# js对象赋值会影响原对象吗?
直接用=的方式把一个对象赋值给另一个对象,会导致修改新对象时,原对象也发生变化
var obj1 = {'name': '1111'};
var obj2 = obj1;
obj2.name = '2222';
console.log(obj1.name); //'2222'
原因:JavaScript 中对象的赋值是引用赋值(两个对象指向相同的内存地址)
59、看下面代码,给出输出结果
for(var i=0;i<=3;i++){
setTimeout(function(){
console.log(i);
},0);
};
答案:打印4次4
解析如下:
这道题涉及了异步、作用域、闭包
settimeout是异步执行,0ms后往任务队列里面添加一个任务,只有主线上的全部执行完,才会执行任务队列里的任务,当主线执行完成后,i是4,所以此时再去执行任务队列里的任务时,i全部是4了。对于打印4次是:
每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了4次,就放了4次,当主线程执行完成后,才进入任务队列里面执行。
(注意:for循环从开始到结束的过程,需要维持几微秒或几毫秒。)
首先我们都知道JS的执行机制是单线程环境。什么是单线程环境?打个比方,多线程就相当于一条公路上有多个车道,一次可以通过多辆车子。单线程就相当于这条公路就只有一个车道,每次只能通过一辆车。同理,在JS的单线程环境里,每次只能从上到下一条一条的把代码执行下去。但是这样一条一条按顺序执行下去有的时候在面对特殊要求的时候速度太慢了。例如这条单车道的公路上现在要通行一辆救护车,救护车要是等到车道里的车子都通过了才能走那就太浪费时间了,不符合要求。那怎样才能让救护车以最快的速度通过这条单车道呢?这时候就引入了一个异步函数的概念。异步函数不是按正常代码那样要按顺序等前面的代码都执行完了才执行自己,当JS遇到异步函数的时候,会把异步函数插入到队列中等待。也就是所谓的插队。而setTimeOut 就是一个异步函数。所以当JS检测到setTimeOut()的时候,会把setTimeOut()插入到队列中,然后继续执行后面的代码,也就是接下来的循环。由于setTimeOut()设置了一秒后才执行,所以插入的队列位置是一秒后。 而在这个一秒内for循环已经全部完成,i经过五次循环后变成了5。所以当一秒后开始执行setTimeOut()方法的时候i的值已经变成5了。因为循环了5次,所以有5次setTimeOut()方法的调用,即输出4个4。
当我把var 变成let 时
for(let i=0;i<=3;i++){ setTimeout(function() { console.log(i) }, 0);}
或者用匿名函数
for(var i=1;i<=3;i++){undefined
setTimeout((function(a){ //改成立即执行函数
console.log(a);
})(i),0);
};
打印出的是:0,1,2,3
当解决变量作用域,
因为for循环头部的let不仅将i绑定到for循环快中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过 var 定义的变量是无法传入到这个函数执行域中的,通过使用 let 来声明块变量,这时候变量就能作用于这个块,所以 function就能使用 i 这个变量了;这个匿名函数的参数作用域 和 for参数的作用域 不一样,是利用了这一点来完成的。这个匿名函数的作用域有点类似类的属性,是可以被内层方法使用的。
60、分析代码,得出正确的结果。
var a=10, b=20 , c=30;
++a;
a++;
e=++a+(++b)+(c++)+a++;
alert(e);
解析:弹出提示对话框:73
因为前置的++与后置的++都比+的优先级高,这个式子可以看成是
e=(++a)+(++b)+(c++)+(a++);
(前置的++要到本行变量就加1,而后置的++下一行变量才会加1)
根据从左到右相加的原理。++a(11)加上++b(21)加上c++(30,下一行才会变为31)加上a++(11,a已经由于++a变为11了,下一行会变为12。),即11+21+30+11=73。
61、let 和 var 的区别?
1.let不存在变量提升
2.let声明的变量不会声明的window上(ES5中,顶层对象的属性等价于全局变量。ES6中,有所改变:var、function声明的全局变量,依然是顶层对象的属性;let、const、class声明的全局变量不属于顶层对象的属性,也就是说ES6开始,全局变量和顶层对象的属性开始分离、脱钩。)
3.声明的变量具有块级作用域
{ let num = 5; //只能在当前大括号内部使用 }
4.不允许重复声明变量
let a = 20;
let a = 10;
console.log(a); //报错