演示代码下载(gitee):
https://gitee.com/zhaodave/jsdemo.git
2.1Js中使用typeof能得到的哪些类型?
undefined;对未经声明的变量或声明后未赋值的变量会返回undefined
boolean;true
string;’abc’
number;123
object;检测null值(因为表示空对象指针),对象,数组会返回object
function;
变量计算-强制类型转换
字符串拼接
Var b = 100 + ‘10’
==运算符
100 == ‘100’;0==’’;null==undefined
If语句
If中是false的情况除undefined和false本身:
if(0){}
if(NaN){}
if(''){}
if(null){}
逻辑运算(与或非)
2.2何时使用===和==?
三等没有类型转换;
比较过程:
双等号==:
(1)如果两个值类型相同,再进行三个等号(===)的比较
(2)如果两个值类型不同,也有可能相等,需根据以下规则进行类型转换在比较:
1)如果一个是null,一个是undefined,那么相等
2)如果一个是字符串,一个是数值,把字符串转换成数值之后再进行比较
三等号===:
(1)如果类型不同,就一定不相等
(2)如果两个都是数值,并且是同一个值,那么相等;如果其中至少一个是NaN,那么不相等。(判断一个值是否是NaN, 只能使用isNaN( ) 来判断)
(3)如果两个都是字符串,每个位置的字符都一样,那么相等,否则不相等。
(4)如果两个值都是true,或是false,那么相等
(5)如果两个值都引用同一个对象或是函数,那么相等,否则不相等
(6)如果两个值都是null,或是undefined,那么相等
2.3js中有哪些内置函数?
Object类型:
为新对象定义了默认的属性和方法
方式:
var person = new Object() ;
var person = {
name: "dave",
sex: "girl"
}
var person = {}
Array类型:
concat 返回一个由两个数组合并组成的新数组。
join 返回一个由数组中的所有元素连接在一起的 String 对象。
pop 删除数组中的最后一个元素并返回该值。
push 向数组中添加新元素,返回数组的新长度。
shift 删除数组中的第一个元素并返回该值。
unshift 返回一个数组,在该数组头部插入了指定的元素。
sort 返回一个元素被排序了的 Array 对象
reverse 返回一个元素反序的 Array 对象。
slice 返回数组的一个片段。
splice 从数组中删除元素。
Date类型:
getYear() 返回年份(2位或4位)
getFullYear() 返回年份(4位)
getMonth() 返回月份 0-11
getDate() 返回日期 1-31
getDay() 返回星期数 0-6
getHours() 返回小时数 0-23
getMinutes() 返回分钟数 0-59
getSeconds() 返回秒数 0-59
getMilliseconds() 返回亳秒数0-999
基本包装类型:Boolean,Number,String
Boolean
Number
String:
length属性:长度
concat 方法(String)连接两个或更多个字符串。
indexOf(string) 返回出现字符串的位置
substr(num1,[num2])截取字符串
toLowerCase() 转换成小写
toUpperCase() 转换成大写
replace(str1,str2) 字符串替换
单位内置对象:Math,Global
Math:
ceil(数值) 大于或等于该数的最小整数
floor(数值) 小于或等于该数的最大整数
min(数值1,数值2) 返回最小值
max(数值1,数值2) 返回最大值
pow(数值1,数值2) 返回数值1的数值2次方
random() 返回随机数 0---1
round(数值) 四舍五入
sqrt(数值) 开平方根
Regexp类型:
Function类型:
Error类型:
2.4js变量按照存储方式区分为哪些类型,描述其特点?
变量类型和计算:
变量类型:值类型和引用类型;typeof运算符。
常用的引用类型:对象、数组、函数。
特点:
(1)值类型:1、占用空间固定,保存在栈中(当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。)
2、保存与复制的是值本身
3、使用typeof检测数据的类型
4、基本类型数据是值类型
(2)引用类型:1、占用空间不固定,保存在堆中(当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。)
2、保存与复制的是指向对象的一个指针
3、使用instanceof检测数据类型
4、使用new()方法构造出的对象是引用型
2.5如何理解json?
Json是一个js对象,其常用的两种方法:
将对象转换为json
JSON.stringify({a:10,b:20})
将json转换为对象
JSON.parse('{"a":10,"b":20}')
原型和原型链
知识点:
构造函数:
以大写字母开头;
function Foo(name, age) {
this.name = name
this.age = age
this.class = 'class-1'
//return this
}
var f =new Foo('zhangsan',20);
console.log(f);
构造函数-扩展:
原型规则和示例:
- 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了null以外)
- 所有的引用类型(数组、对象、函数),都具有__proto__(隐式原型)属性,属性值是一个普通的对象
- 所有的函数,都有一个prototype(显式原型)属性,属性值是一个普通的对象
- 所有的引用类型(数组、对象、函数),__proto__(隐式原型)属性值指向它的构造函数的prototype(显式原型)属性
- 当试图得到一个对象的额某个属性时,如果这个对象本身没有这个属性,那么他会去它的__proto__(即它的构造函数的prototype)中寻找。
1234测试如下:
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {}
fn.a = 100;
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);
console.log(fn.prototype)
console.log(obj.__proto__=== Object.prototype)
答案:
[Running] node "d:\js面试demo\jsdemo\yuanxin.js"
{}
[]
[Function]
fn {}
true
5测试如下:
//构 造函数,验证第五条规则
function Foo(name, age) {
this.name = name
}
Foo.prototype.alertName = function () {
console.log(this.name)
}
var f =new Foo('zhaojiawei')
f.printName = function () {
console.log(this.name)
}
f.printName()
f.alertName()
答案:
[Running] node "d:\js面试demo\jsdemo\yuanxin.js"
{}
[]
[Function]
fn {}
true
zhaojiawei
zhaojiawei
原型链:
f.toString() //要去f.__proto__.__proto__中查找
Instanceof:
用于判断引用类型属于哪个构造函数的方法。
- f instanceof Foo的判断逻辑是
- F的__propto__一层一层往上,能否对应到Foo.prototype
- 再试着判断f instanceof Object
2.6如何准确判断一个变量是数组类型
var arr = []
var a = arr instanceof Array; //TRUE
var b = typeof arr; //object,typeof 是无法判断是否是数组的
console.log(a)
console.log(b)
[Running] node "d:\js面试demo\instanceof.js"
true
object
2.7写一个原型链继承的例子
一个实用的例子:输出dom元素
function Elem(id) {
this.elem = document.getElementById(id)
}
Elem.prototype.html = function (val) {
var elem = this.elem
if (val) {
elem.innerHTML =val
return this //链式操作
} else {
return elem.innerHTML
}
}
Elem.prototype.on = function (type, fn) {
var elem = this.elem
elem.addEventListener(type, fn)
return this
}
var div1 = new Elem('div1')
// console.log(div1.html())
div1.html('<p>爱你奥。。。</p>').on('click',function(){
alert('clicked')
}).html("<p>不爱了。。。</p>")
2.8描述new一个对象的过程
考察对构造函数的理解;
2.9Zepto(或其他框架)源码中如何使用原型链
慕课网“zepto设计和源码分析”
- 作用域和闭包
知识点:
- 执行上下文:
- 范围:一段<script>或者一个函数
- 全局:变量定义、函数声明;先去这段<script>中把变量声明和函数定义拿出来
- 函数:变量定义、函数声明、this、arguments;函数体中把上述先执行。
先执行var a,和5行的函数声明,在执行1,a=100,4行。
函数声明和函数表达式的区别:
函数声明将会被提前执行
1.函数声明
函数声明以function关键字开头,接着是必须的函数(变量)名和以逗号分隔的可选的参数列表,再接着就是以大括号封装的函数体。函数声明必须是一个单独的JavaScript语句。
2.函数表达式
在任何情况下都是其它JavaScript语句的一部分(比如赋值表达式等号的右侧、函数的参数)的函数被称为函数表达式。
- This:
- This要在执行时才能确认值,定义时无法确认
- 作为构造函数执行,作为对象属性执行,作为普通函数执行(window),call apply bind。演示
// 构造函数中的this
function Foo(name) {
this.name = name
}
var f= new Foo('zhangsan')
// 对象的this
var obj = {
name: 'A',
printName: function () {
console.log(this.name)
}
}
obj.printName()
// 作为普通函数来执行
function fn() {
console.log(this)
}
fn()
// call apply bind
function fn1(name, age) {
console.log(name)
console.log(this)
}
fn1.call({x:100},'zhangsan',20)
// .bind必须函数表达式的方式
var fn2 = function fn2(name, age) {
console.log(name)
console.log(this)
}.bind({y:200})
fn2('zhangsan',20)
- 作用域:
- 没有块级作用域;声明变量在快内虽然没有影响,但是会使程序不易读
- 但是有全局作用域和函数作用域
// 作用域
if (true) {
var name = 'zhangsan'
}
console.log(name)
// 函数和全局作用域
var a =100
function fn() {
var a =200
console.log('fn', a)
}
console.log('global', a)
fn()
答案:
[Running] node "d:\jsdemo\jsdemo\第三章\3-5.js"
zhangsan
global 100
fn 200
// 无块级作用域解释:无块级作用域,函数内部变量的无法在函数外部使用。
- 作用域链:
一个自由变量不断的取父级作用域中找,直至找到标识符为止。
// 作用域链
var a = 100
function F1() {
var b =200
function F2() {
var c =300
console.log(a) //a是自由变量
console.log(b) //b是自由变量
console.log(c)
}
F2()
}
F1()
答案:
[Running] node "d:\jsdemo\jsdemo\第三章\3-5.js"
100
200
300
解释:当函数作用域中是自由变量时,在父级作用域中找,若无继续在父级找。外部环境不能访问内部环境的任何变量和函数
- 闭包:
使用场景:
- 函数作为返回值
- 函数作为参数传递
// 闭包
function F1() {
var a =100
return function () {
console.log(a)
}
}
// f1得到一个函数
var f1 = F1()
var a = 200
f1()
答案:
[Running] node "d:\jsdemo\jsdemo\第三章\3.6-3.8.js"
100
解释:一个函数的父级作用域是他定义时的作用域而不是执行时的作用域。
3.1说一下对变量提升的理解
JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
3.2说明this几种不同的使用场景
作为构造函数执行,作为对象属性执行,作为普通函数执行,call apply bind。
3.3创建10个<a>标签,点击的时候弹出来对应的序号
// 创建10个<a>标签,点击的时候弹出来对应的序号
var i
for (i = 0; i < 10; i++) {
(function (i){
var a=document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click',function (e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
})(i)
}
3.4如何理解作用域
自由变量:凡是跨了自己的作用域的变量都叫自由变量。
作用域链,即自由变量的查找。
闭包的两个场景:函数作为返回值;函数作为参数传递。
3.5实际开发中闭包的应用
封装变量,收敛权限;
个人认为这篇博客还不错
转载:https://blog.youkuaiyun.com/baidu_33295233/article/details/79127733
闭包的三大特点为:
1、函数嵌套函数
2、内部函数可以访问外部函数的变量
3、参数和变量不会被回收。
举例来说:
function test(){
var a=1;
return function(){
alert(a);
}
}
var try = test()
try(); //弹出a的值
这个例子中,变量a在test方法外部是无法访问的,但test方法里面,嵌套了一个匿名函数,通过return返回,test作用域中的变量a,可以在匿名函数中访问。并且当test方法执行后,变量a所占内存并不会释放,以达到嵌套的函数还可以访问的目的。
闭包的作用在于,可以通过闭包,设计私有变量及方法。
举例来说:在java中创建perosn类,含有私有变量name。
public class Person{
private String name='wy';
public Person(val){
name=val;
}
public void setName(val){
name=val;
}
public String getName(){
return name;
}
}
在js中实现类似java创建类的功能:
(function(){
var name="wangyu";
Person=function (val) {
name=val;
}
Person.prototype.setName=function(val){
name=val;
}
Person.prototype.getName=function () {
return name;
}
})();
var person1=new Person("sj");
alert(this.name)//undefined 因为在function作用域外不能访问
alert(person1.getName());//wangyu
在function里面的name,由于是在function作用域中,所以外部无法访问,但是可以通过创建person对象,调用person的方法,来达到修改和访问name值的目的,类似于java类中的私有变量,外部无法访问,只能通过类方法访问。
再看一个私有变量的例子:
var aaa = (function(){
var a = 1;
function bbb(){
a++;
alert(a);
}
function ccc(){
a++;
alert(a);
}
return {
b:bbb, //json结构
c:ccc
}
})();
alert(aaa.a)//undefined
aaa.b(); //2
aaa.c() //3
总结:
1、闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
2、不必纠结到底怎样才算闭包,其实你写的每一个函数都算作闭包,即使是全局函数,你访问函数外部的全局变量时,就是闭包的体现。
4.异步和单线程
知识点:
- 什么是异步(对比同步)
console.log(100)
setTimeout(function(){
console.log(200)
},1000)
console.log(300)
答案
[Running] node "d:\jsdemo\jsdemo\第四章\4.1.js"
100
300
200
不阻塞程序的进行,不等待,将setTime中的函数放入异步队列后执行下面的,再返回来操作。
- 前段使用异步的场景
定时任务:setTimeout,setInterval
网络请求:ajax请求,动态img的加载(用户体验)
事件绑定,事件监听
Onload事件为异步操作;为图片加载完成后执行;
- 异步和单线程
(个人理解)Js是单线程的语言,只能一步一步执行代码,异步是处理单线程各种问题的解决方案。
题目:
4.1同步和异步的区别是什么?分别举一个同步和异步的例子
同步会阻塞代码执行,而异步不会
Alert是同步,settimeout是异步
4.2一个关于setTimeout的笔试题
console.log(1)
setTimeout(function (){
console.log(2)
},0)
console.log(3)
setTimeout(function (){
console.log(4)
},0)
console.log(5)
答案:
[Running] node "d:\jsdemo\jsdemo\第四章\4.4.js"
1
3
5
2
4
4.3前段使用异步的场景有哪些
定时任务:setTimeout,setInterval
网络请求:ajax请求,动态img的加载(用户体验)
事件绑定,事件监听
其他知识:
date
Date.now() //获取当前时间毫秒数
var dt = new Date()
dt.getTime() //获取毫秒数
dt.getFullYear() //年
dt.getMonth() //月
dt.getDate() //日
dt.getHours() //小时
dt.getMinutes() //分
dt.getSeconds() //秒
Math
获取随机数Math.random()
数组api:
- forEach遍历所有元素
- Every判断所有元素是否都符合条件
- Some判断是否有至少一个元素符合条件
- Sort排序
- Map对元素重新组装,生成新数组
- Filter过滤符合条件的元素
敲一下代码:4.5.js中演示上述代码
对象api:
4.4获取2017-06-10格式的日期
function formatDate (dt) {
if(!dt) {
dt = new Date()
}
var year = dt.getFullYear()
var month = dt.getMonth()+1
var date = dt.getDate()
if (month < 10) {
month = '0' +month
}
if (date < 10) {
date = '0' +date
}
return year+'-'+month +'-'+date
}
var sj =new Date()
var formatDate = formatDate(sj)
console.log(formatDate)
结果:
[Running] node "d:\jsdemo\jsdemo\第四章\4.8.js"
2018-07-26
4.5获取随机数,要求是长度不变的字符串格式
/ 4.5题
var random = Math.random()
var random = random + "0000000000"
var random = random.slice(0,10)
console.log(random)
/
4.6写一个能遍历对象和数组的通用forEach函数
function forEach(obj, fn) {
var key
if (obj instanceof Array) {
obj.forEach(function(item, index){
fn(index, item)
})
} else {
for (key in obj){
fn(key,obj[key])
}
}
}
var arr =[1,2,3]
forEach(arr, function(index, item){
console.log(index,item)
})
var obj = {x:100, y:200}
forEach(obj, function (key, value){
console.log(key,value)
})
5.js-web-api上
- Js基础知识:ECMA262标准,它定义的只是这门语言的基础,ECMAScript与Web浏览器没有依赖关系
- Js-web-api:w3c标准
- W3c标准中关于JS的规定有:
DOM操作;BOM操作;事件绑定;ajax请求(包括http协议);存储
总结:
- 常说的js(浏览器执行的js)包含了两部分:js基础知识(ECMA262标准),Js-web-api:w3c标准。
DOM操作
文档对象模型,dom把整个页面映射为一个多层节点结构。
知识点:
DOM的本质:
是一种针对xml但经过扩展用于HTML的应用程序编程接口。
目的:通过DOM创建的这个表示文档的树形图,开发人员获得了控制页面和结构的主动权。借助DOM提供的API,开发人员可以轻松的删除、添加、替换或修改任何节点。
理解:浏览器把拿到的html代码,结构化成一个浏览器能识别并且js可操作的一个模型而已
DOM节点操作:
获取DOM节点;prototype;Attribute
DOM结构操作:
新增节点;获取父元素;获取子元素;删除节点
5.1DOM是哪种基本的数据结构?
树
5.2dom操作的常用API有哪些
DOM节点操作:
获取DOM节点;prototype;Attribute
DOM结构操作:
新增节点;获取父元素;获取子元素;删除节点
5.3DOM节点的attribute和property有何区别
Property只是一个JS对象的属性的修改
Attribute是对html标签属性的修改
BOM操作知识点
- Window对象
- Navigator
- Screen
- Location
- history
5.4如何检测浏览器的类型
// 如何检测浏览器的类型
var ua = navigator.userAgent
var isChorme = ua.indexOf('Chorme')
console.log(isChorme)
有时无法通过navigator.userAgent来区分浏览器种类。
5.5拆解url的各部分
转载:https://blog.youkuaiyun.com/py941215/article/details/77825921
- js-web-api下
知识点
- 通用事件绑定
在JavaScript中,有三种常用的绑定事件的方法:
- 在DOM元素中直接绑定;
- 在JavaScript代码中绑定;
- 绑定事件监听函数。
var btn =document.getElementById('btn1')
btn.addEventListener('click', function(event) {
console.log('clicked')
})
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
var a = document.getElementById('link1')
bindEvent(a, 'click', function(e) {
e.preventDefault(); //阻止默认行为
alert('clicked')
})
Ie低版本使用attachEvent绑定事件,和w3c标准不一样
- 事件冒泡
参考:https://www.cnblogs.com/qq9694526/p/5653728.html
- 代理
一个div里面有很多个a标签,通过父组件的形式让子组件有事件的绑定。
代理的优点:代码简洁、减少浏览器内存的使用。
6.1编写一个通用的事件监听函数
function bindEvent(elem, type, selector, fn) {
if (fn== null) {
fn = selector
selector = null
}
elem.addEventListener(type, function (e){
var target
if (selector) {
// 代理
target = e.target
if (target.matches(selector)) {
fn.call(target, e)
}
}else {
// 不是代理
fn (e)
}
})
}
解释:bindEvent函数使里面的参数对应;
6.2描述事件冒泡流程
- DOM树形结构
- 事件冒泡
- 阻止冒泡
- 冒泡的应用
6.3对于一个无限下拉加载图片的页面,如何给每个图片绑定事件
使用代理,知道代理的两个优点:代码简洁,给浏览器压力小效率高。
AJAX
知识点:
- XMLHttpRequest
var xhr = new XMLHttpRequest()
xhr.open("GET","/api",false)
xhr.onreadystatechange = function () {
// 这里的函数异步执行
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert(xhr.responseText)
}
}
}
xhr.send(null)
- 状态码说明
- 跨域
什么是跨域:浏览器的同源策略,不允许ajax访问其他接口。
跨域条件:协议、域名、端口,有一个不同就算跨域。
可以跨域的三个标签:
Img的src;link;script
- 跨域注意事项:
所有的跨域请求都必须经过信息提供方允许
如果未经允许获取,是浏览器出现漏洞
- Jsonp实现原理:
- 服务器端设置http header:
题目:
6.4手动编写ajax,不依赖第三方库:
6.5跨域的几种实现方式
6.6请描述一下cookie,sessionStorage和localStorage的区别?
项目中遇到过:
7.3常用git命令
- Git add .
- Git checkout xxx
- Git commit -m “xxx”
- Git push origin master
- Git pull orgin master
- Git branch
- Git merge xxx
7.6模块化
不使用模块化:使用模块化:
代码描述:
传递出相关函数,被其他模块引用,引用要用的就行,
模块化工具:
require.js
全局define函数
全局require函数
依赖js会自动、异步加载
AMD 即Asynchronous Module Definition,中文名是异步模块定义的意思。
举例:一层一层的依赖去加载函数
data-main放入入口js文件
7.8common.js
Nodejs模块化规范,现在被大量用前端,原因:
前端开发依赖的插件和库,都可以从npm中获取
构建工具的高度自动化,使得使用npm的成本非常低
CommonJS不会异步加载JS,而是同步一次性加载出来
Amd和commonJS的使用场景
需要异步加载JS,使用AMD
使用了Npm之后建议使用common.js
http-server的使用
7.10安装配置webpack
Webpack的操作
- Npm i 初始化项目,生成有package.json的文件
- Npm install webpack --save-dev save表示保存,dev表示开发环境 安装项目插件
- 新建一个webpack.config.js文件,设置入口出口等,package.json设置运行语句
- 若运行出错,注意webpack版本3.0.0
- http-server -p 8888检测下打包是否成功
8运行环境
8.2页面加载,渲染过程
知识点:
- 加载资源的形式
- 加载一个资源的过程
- 浏览器渲染页面的过程
题目:
从输入url到得到html的详细过程
浏览器根据DNS服务器得到域名的IP地址
向这个IP的机器发送http请求
服务器收到、处理并返回http请求
浏览器得到返回的内容
Window.onload和DOMContentLoaded的区别
第一是:页面的全部资源加载完才会执行,包括图片、视频等
第二是:DOM渲染完即可执行,此时图片、视频还没有加载完
8.5性能优化
原则:
减少硬盘读写;
从哪里入手:加载页面和静态资源、页面渲染
加载资源优化:
静态资源的压缩合并、静态资源缓存、使用CDN让资源加载更快、使用ssr后端渲染,数据直接输出到HTML中
渲染优化:
Css放前面,js后面、懒加载(图片懒加载、下拉加载更多)、减少DOM查询,对DOM查询做缓存、减少DOM操作,多个操作尽量合并在一起执行、事件节流、尽早执行操作(domcontentloaded)
优化示例:
真正的图片是放在DATA后面
100毫秒的延时让事件节流。
8.7安全性
Xss跨站请求攻击
- 插入script代码,可以输入脚本
- 攻击代码中,获取cookie,发送自己的服务器
- 发布博客,有人查看博客内容
- 会把查看者的cookie发送到攻击者的服务器
解决:
XSRF跨站请求伪造
解决:增加验证流程,如输入指纹、密码、短信验证码
8.9补充