函数
JavaScript中的函数通过function进行声明,一个函数可以有return语句也可以没有。
函数的参数与其他语言有所不同,可以随意传进参数,不管参数个数或者数据类型。
函数体内可通过arguments对象访问参数,其使用类似数组。
因为其没有函数签名(接受的参数类型和数量),所以没有重载,若定义了两个相同的函数,则该函数名属于后面的函数。
但是可以通过arguments来模仿函数的重载
<script>
function sayHi(){
if(arguments.length==0)
return "Hi";
if(arguments.length==1)
return arguments[0];
if(arguments.length==2)
return "hello"+arguments[1];
}
</script>
rest参数
由于js中传进来的参数可以有多个,所以ES6引进了rest参数,它的用法如下
var pig=function(a,b,...rest){
console.log(a);
console.log(b);
console.log(rest);
}
pig(1,2,3,4,5);//a=1 b=2 Array[3,4,5]
若参数数量不够,rest为空数组。
由于js巨大的设计失误,this的指向变幻莫测,所以ECMA引入了apply与call来控制this的指向。
apply接收两个参数,第一个参数就是要绑定的this变量,第二个参数是Array,表示函数本身的参数。call与apply类似,只不过apply将参数以数组形式打包传入,call按顺序一个个传入。
function getAge(){
var y=new Date().getFullYear();
return y-this.birth;
}
var years={
birth:2000,
age:getAge
}
console.log(getAge());//NaN
console.log(getAge.apply(years,[]));//18
高阶函数
一个函数接受另一个函数作为其参数,那么它就是高阶函数
var i=function(x,y,f){
return f(x)+f(y);
}
var j=i(-2,1,Math.abs);
console.log(j);//3
map/reduce
map()方法定义在js的Array对象中,调用某一个Array的map方法,会返回一个新的Array。
function pow(x){
return x*x;
}
var arr=[1,2,3,4,5];
console.log(arr.map(pow));
reduce也是同样,但是传入的函数必须要有两个参数,reduce()把算出来的结果与下一个元素做累计计算。
fliter
fliter可以将arr中的某些元素过滤掉,返回剩下的元素。filter也传入一个函数,根据函数返回时true还是false决定元素是否保留。
var arr=[1,2,3,4,5];
console.log(arr.filter(function(x){
return x%2!==0;
}))//删除偶数
排序
sort的排序非常坑爹,它通过ASCII码进行排序,如果是数字的话,会先将其转换为字符串,由于'1'的ASCII小于'2'所以'10'排在'2'前面。
但是sort()方法本身也是一个高阶函数,可以通过接收一个比较函数实现正确的排序
arr.sort(function(x,y){
if(x>y)
return 1;
if(x<y)
return -1;
return 0;
})
闭包
当函数不需要立即计算时,可以使用闭包,
闭包即在函数中定义另外一个函数,这个函数可以引用外部函数的参数和变量,这样的函数就叫做闭包。
但是闭包中不要引用任何循环变量,或者后续会发生变化的变量。
箭头函数
箭头函数相当于匿名函数,只包含一个表达式时可以省掉return,包含多个表达式时不可省掉return。,如果参数大于一个,要用()括起来,(x,y)=>{....}
并且箭头函数修复了this的指向,this总是指向词法作用域。
x=>x*x
相当于
function(x){
return x*x;
}
变量
变量有基本类型和引用类型两种
基本类型有 Undefined,Null,Boolean,Number,String五种
这五种类型是按值访问的,可以操作保存在变量值中实际的值
但是引用类型为内存中的对象,但是js不允许直接操作内存,
所以操作对象是按引用访问的,对引用类型的值,我们可以操作其属性和方法
<script>
var person=new Object();
person.name="IDLER";
</script>
除了上述不同,它们在复制的时候也有不同
例如:
var name="IDLER";
var me=name;
name和me两个变量是相互独立的
但是对于引用类型,这两个变量其实是相互关联的,
相当于me是一个指向name的指针,
而name是指向它存的值的指针。
var name=new Object();
var me=name;
但是函数的参数传递只能按值传递,类似c语言中的形参。形参只是函数内的局部变量。但是若传入的是一个对象,对其修改仍然会改变实参,因为即使是形参也指向的是同一片内存。但若在函数内改变了形参的指向,其就无效了
function setName(obj){
obj.name="abc";
obj=new Object();
obj.name="sufei";
}
最终输出结果obj.name还是abc。
检测类型
可以用typeof检测变量的类型,但是不管是对象还是null,其返回的都是object。
其语法为 变量 instanceof constructor
若用其检测基本类型,返回结果永远为false
person instanceof Object;
colors instanceof Array;
执行环境
全局环境是最外围的环境,在Web浏览器中,执行环境是window对象,所有全局变量和函数都是作为window的属性和方法创建的。同样的,每个函数都有它的执行环境。当变量在一个环境中执行的时候,会产生一个作用域链,每个作用域链的前端永远都是当前的执行环境,函数最开始只包含一个变量arguments,作用域的下一个对象来自外部环境,再下一个变量来自下一个外部环境,这样一直延续到全局环境。
var color="blue";
function change(){
color="red"
function rechange(){
var newcolor="pink";
newcolor=color;
}
rechange();
}
change();
rechange()中包含三个变量对象,即自身的变量对象,change()的变量对象,以及全局的变量对象。若外部对象与内部对象重名,由于作用域的查找是由内到外,所以内部的变量会屏蔽外部的变量。
由于for循环中的var定义的不是具有局部作用域的对象,所以ES6新增了let。
for(let i=0;i<1000;i++){
.......
}
i+=1//undefined
ES6新增了const关键字定义常量,const定义的变量也具有块级作用域。
ES6新特性:Map和Set
Map
js中的{}对象可以表达其他语言中的Map或是字典的数据结构,即一组键值对,但是{}中的键必须伪字符串,为了解决这个问题,ES6新增了Map
初始化Map需要用一个二维数组
var m=new Map([['IDLER',1],['yuan',2]]);
m.get('IDLER');//1
Map中还有set方法可以对其初始化,delete方法删除某一对键值。
m.set('pig',3);
m.delete('pig');
Set
Set是一组键的集合,但是不包含对应的value,并且没有重复的key
var s=new Set([1,2,3,4,5]);
s.add(5);
s.delete(4);
//s{1,2,3,5}
iterable
由于Map和Set不能像数组一样用下标进行遍历,ES6引入新类型iterable,其包含Array,Map,Set三种类型,都可以通过for...of...进行循环
var s=new Set([1,2,3,4,5]);
var m=new Map([['yuan',1],['zhou',2]]);
var x=[1,2,3,4,5];
for(var i of s){
console.log(i);
}
for(var j of m){
console.log(j[0]+":"+j[1]);
}
for(var k of x){
console.log(k);
}
ES6新特性:解构赋值
var [x,y]=[1,'pig'];
面向对象编程
js与其他语言的面向对象不太一样,其不区分类和实例的概念,而是通过原型实现面向对象编程。
var Student = {
name: 'Robot',
height: 1.2,
run: function () {
console.log(this.name + ' is running...');
}
};
var xiaoming = {
name: '小明'
};
xiaoming.__proto__ = Student;
最后一行将xiaoming这个对象的原型指向了Student对象,于是实现了方法和属性的继承,此时,如果将xiaoming这个对象的原型指向另一个对象比如bird,它就失去了Student中含有的方法和属性.
此时小明变成了一只鸟,不能跑,只能飞
var Bird = {
fly: function () {
console.log(this.name + ' is flying...');
}
};
xiaoming.__proto__ = Bird;
另一种方法是使用Object.create()方法
Object.create()方法可以传入一个原型对象,并创建一个基于该原型的新对象,但是新对象什么属性都没有,因此,我们可以编写一个函数来创建xiaoming
function createStudent(name) {
// 基于Student原型创建一个新对象:
var s = Object.create(Student);
// 初始化新对象:
s.name = name;
return s;
}
若使用obj.xxx,js会先从该对象上查找该属性,找不到就到它的原型上找,直到上溯到Object.prototype,如果还没有找到就返回undefined。
以下摘自廖雪峰的博客:
例如,创建一个Array对象:
var arr = [1, 2, 3];
其原型链是:
arr ----> Array.prototype ----> Object.prototype ----> null
Array.prototype定义了indexOf()、shift()等方法,因此你可以在所有的Array对象上直接调用这些方法。
当我们创建一个函数时:
function foo() {
return 0;
}
函数也是一个对象,它的原型链是:
foo ----> Function.prototype ----> Object.prototype ----> null
由于Function.prototype定义了apply()等方法,因此,所有函数都可以调用apply()方法。
很容易想到,如果原型链很长,那么访问一个对象的属性就会因为花更多的时间查找而变得更慢,因此要注意不要把原型链搞得太长。
js中除了用{}直接创建一个对象,还可以通过构造函数创建一个对象
function Student(){...}
var xiaoming=new Student();
此时原型链为xiaoming ----> Student.prototype ----> Object.prototype ----> null
也就是说新创建的对象xiaoming的原型链指向Student的原型链
同时xiaoming还获得了一个constructor属性,指向Student对象
原型继承
JavaScript的原型继承实现方式就是:
1.定义新的构造函数,并在内部用call()调用希望“继承”的构造函数,并绑定this;
2.借助中间函数F实现原型链继承,最好通过封装的inherits函数完成;
3.继续在新的构造函数的原型上定义新方法。
class继承
ES6中正式引用了class
如果用新的class关键字来编写Student,可以这样写:
class Student {
constructor(name) {
this.name = name;
}
hello() {
alert('Hello, ' + this.name + '!');
}
}
class中包含构造函数和定义在原型对象上的函数hello()
所以现在可以直接使用extends实现继承,调用父类的构造方法要在前面加上super
class PrimaryStudent extends Student {
constructor(name, grade) {
super(name); // 记得用super调用父类的构造方法!
this.grade = grade;
}
myGrade() {
alert('I am at grade ' + this.grade);
}
}
如何编写原生AJAX
步骤:1.new一个XMLHttpRequest()对象
2.监听Http的相应结果和状态码
3.如果成功就调用open方法和send方法,open方法两个参数,一个是提交方式(get/post),一个是打开的文件路径。send方法用来send一些数据
function success(text) {
var textarea = document.getElementById('test-response-text');
textarea.value = text;
}
function fail(code) {
var textarea = document.getElementById('test-response-text');
textarea.value = 'Error code: ' + code;
}
var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象
request.onreadystatechange = function () { // 状态发生变化时,函数被回调
if (request.readyState === 4) { // 成功完成
// 判断响应结果:
if (request.status === 200) {
// 成功,通过responseText拿到响应的文本:
return success(request.responseText);
} else {
// 失败,根据响应码判断失败原因:
return fail(request.status);
}
} else {
// HTTP请求还在继续...
}
}
// 发送请求:
request.open('GET', '/api/categories');
request.send();
准备面试的一些提问:
1.HTML
一.遇到script标签时浏览器的行为
(1.不带async,defer标签:阻值文档渲染,直到脚本加载完毕
(2.带async属性
由脚本插入的script标签默认是async的。对內联脚本设置async属性是没有意义的,也不产生其他效果。其包含的脚本总是立即执行的。
(3.带defer属性
推迟脚本执行,不阻止文档解析
defer属性是会确保脚本在文档解析完毕后执行的——即使这个脚本在文档解析过程中就已经下载完毕变成可执行的状态,浏览器也会推迟这个脚本的执行,直到文档解析完毕,并在DOMContentLoaded之前。
二.遇到link标签浏览器的行为
link标签也会阻塞文档的渲染
<link>标签的rel属性
rel属性是<link>标签的核心属性,利用rel属性,搜索引擎可以获取更多有关链接的信息。
三.href和src的区别
和你这么说吧,href 表示超文本引用(hypertext reference),在 link和a 等元素上使用。src 表示来源地址,在 img、script、iframe 等元素上。
src 的内容,是页面必不可少的一部分,是引入。href 的内容,是与该页面有关联,是引用。区别就是,引入和引用。
四.meta标签的作用
供机器解读,告诉机器如何解析这个页面
还有一个用途是可以添加服务器发送到浏览器的http头部内容,例如我们为页面中添加如下meta标签:
<meta http-equiv="charset" content="iso-8859-1">
<meta http-equiv="expires" content="31 Dec 2008">
meta标签中还有charset的可选属性<meta charset="utf-8">
五.onload函数的作用
页面加载完后立即执行的函数
1、当 onload
事件触发时,页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了。
2、当 DOMContentLoaded
事件触发时,仅当DOM加载完成,不包括样式表,图片,flash。
DOMContentLoaded机制更加合理,因为我们可以容忍图片,flash延迟加载,却不可以容忍看见内容后页面不可交互。
2.CSS
一.行级元素与块级元素的区别与联系
行级元素与块级元素可以转换
display:inline display:block
行级元素占一整行,不会自动换行
块级元素独占一行,块级元素想要在一行,必须设置浮动
行级元素上下margin,padding无效
块级元素内可以包含行级和块级元素
行级元素中只能包含行级元素。
二.如何实现垂直水平居中
margin: 0 auto;是最好的居中方法
水平垂直居中方法:margin-top,margin-left各50%,然后减去自身宽高。
父元素position:relative 子元素position:absolute
如果宽高未知,可改为:transform: translate(-50%,-50%);
三.position的属性和意义
position中的属性有top,left,right,bottom
absolute:绝对定位相对第一个父元素进行定位
fixed:生成绝对定位,相对于浏览器窗口进行定位
relative:相对定位
static:没有定位
inherit:从父元素继承定位
四.z-index的作用
z-index相当于网页的z轴,当定位的元素重叠时,越在上面的元素越优先显示
五.vertical-align的作用
设置元素垂直对齐的方式
六.什么是盒模型?
盒模型的组成大家肯定都懂,由里向外content,padding,border,margin.
3.JavaScript
一.基本类型和引用类型的区别
基本数据类型:按值访问,可操作保存在变量中的实际的值。基本类型值指的是简单的数据段。
基本数据类型有这五种:Undefined、Null、String、Number、Boolean。
引用类型:当复制保存着对象的某个变量时,操作的是对象的引用,但在为对象添加属性时,操作的是实际的对象。引用类型值指那些可能为多个值构成的对象。
引用类型有这几种:object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)。
① 引用类型值可添加属性和方法,而基本类型值则不可以。
② 在复制变量值时,基本类型会在变量对象上创建一个新值,再复制给新变量。此后,两个变量的任何操作都不会影响到对方;而引用类型是将存储在变量对象的值复制一份给新变量,但是两个变量的值都指向存储在堆中的一个对象,也就是说,其实他们引用了同一个对象,改变其中一个变量就会影响到另一个变量。
typeof:确定变量是字符串、数值、布尔值还是undefined的最佳工具。
instanceof :判断是否是某个对象类型。
二.cookie,session
cookie在客户端,session在服务器端
localstroage和sessionstorage都保存在客户端,sessionstorage会话期间可用,localstorage只有不清除,理论上一直可用,后两者有易用的原生接口