面试时经常遇到的一些javascript问题,在此整理下,也是对于知识的梳理
1.闭包(老生常谈)
可以这样理解:闭包是定义在一个函数内部的函数,
用于封闭变量比如
(function(){
var a=1;
alert(a);
})();//这就是一个闭包,它执行不会为外部添加全局变量,也就是不会对外部产生影响
其实jq中使用了大量的闭包,所有的方法和变量都通过闭包设为私有,并使用$在全局进行调用。闭包就是使局部变量和方法常驻内存,可以在全局进行访问,从而防止全局重名的现象。不过也正因为这个特性,闭包会占用大量的内存空间,所以使用的时候也要慎重。
2.构造函数,原型,原型链
(1)先从构造函数讲起
function Foo(){};
var f1 = new Foo();
构造函数:用来初始化新创建的对象的函数就是构造函数,在例子中Foo()就是构造函数
(2)实例对象
通过构造函数的new操作创建的对象就是实例对象,可以用一个构造函数创建多个实例对象
function Foo(){};
var f1 = new Foo();
var f2 = new Foo();
console.log(f1===f2)//false
(3)原型及prototype
构造函数有一个prototype属性,指向实例对象的原型对象,通过同一个构造函数
实例化的多个对象具有相同的原型对象,经常使用原型对象来实现继承
function Foo(){};
Foo.prototype.a = 1;
var f1 = new Foo();
var f2 = new FOO();
console.log(Foo.prototype.a)//1;
console.log(f1.a)//1;
console.log(f2.a)//1
(4)constructor属性
原型对象上有一个constructor属性,指向该原型对象对应的构造函数
function Foo(){};
console.log(Foo.prototype.constructor === FOO)
由于实例对象可以继承原型对象的属性,所以实例对象也拥有constructor属性,指向原型对象对应的构造函数
function Foo(){};
var f1 = new Foo();
console.log(f1.constructor === Foo)//true
(5)proto属性
实例对象有一个--proto--属性,指向该实例对象对应的原型对象
function Foo(){};
var f1 = new Foo();
console.log(f1.--proto--==Foo.prototype)//true
实例对象的--proto--属性指向原型对象,通过--proto--属性构成的链式关系叫做原型链
3.函数中的(this)
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。所以,this.birth可以拿到xiaoming的birth属性
3.数组
1.首先从创建数组开始:
在JavaScript中创建数组有两种方式如下所
(一)使用 Array 构造函数:
var arr1 = new Array(); //创建一个空数组
var arr2 = new Array(20); // 创建一个包含20项的数组
var arr3 = new Array("lily","lucy","Tom"); // 创建一个包含3个字符串的数组
(二)使用数组字面量表示法:
var arr4 = []; //创建一个空数组
var arr5 = [20]; // 创建一个包含1项的数组
var arr6 = ["lily","lucy","Tom"]; // 创建一个包含3个字符串的数组
2.数组的内建方法
1、join()
join(separator): 将数组的元素组起一个字符串,以separator为分隔符,省略的话则用默认用逗号为分隔符,该方法只接收一个参数:即分隔符
var arr = ['A','B','C','D'];
console.log(arr.join()); // A,B,C,D
console.log(arr.join("-")); // A-B-C-D
console.log(arr); // ['A','B','C','D'](原数组不变)
2.indexOf()
搜索一个指定的元素的位置
var arr = ['A','B','C','D'];
arr.indexOf('C');//2
arr.indexOf('d');//-1,不存在返回-1
3.slice()
截取数组的长度然后返回新的数组
var arr = ['A','B','C','D'];
arr.slice(0,3);//从开始索引0开始,到结束索引结束,但不包括结束索引,['A','B','C']
arr.slice(3);//从3开始到结束,['D']
4.push()
数组尾部添加若干内容
var arr = ['A','B','C','D'];
arr.push('J');//['A','B','C','D','J']
5.pop()
删除数组尾部最后一个元素
var arr = ['A','B','C','D'];
arr.pop()//['A','B','C']
5.unshift()
向数组头部添加若干内容
var arr = ['A','B','C','D'];
arr.unshift('J','K');//['J','K','A','B','C','D']
5.shift()
删除数组的第一个元素
arr.shift();arr.shift();arr.shift();//连续删除3次
7.sort()
给数组排序
var arr = ['1','100','10','52','845']
arr.sort();
arr;//1,10,100,52,845
8.reverse()
给数组倒序
var arr = ['A','B','C','D'];
arr.reverse();//['D','C','B','A']
9.concat()
把当前的数组和另一个数组合并为一个新的数组
var arr = ['A','B','C','D'];
var arr2 = [1,2,3]
arr.concat(arr2);//['A','B','C','D',1,2,3],arr并没有被修改
10.splice()
从指定的索引开始向数组中添加或者删除元素
arr.splice(1,3,'E','F');//删除+添加,返回删除的元素['B','C','D']
arr;//['A','E','F']
arr.splice(1,3);//只删除,不添加,返回翻出的元素['B','C','D']
arr;//['A']
arr.splice(2,0,'E','F','G');//返回[],因为没有删除任何元素
arr;//['A','B','C','D','E','F','G']
数组内建的发布有时不能满足我们的需求时,我们需要扩展数组的方法 如数组去重:
思路: 1)构建一个新的数组存放结果;
2)for循环中每次从原数组中取出一个元素,用这个元素循环与结果数组对比;
3)若结果数组中没有该元素,则存到结果数组中。
Array.prototype.unique1 = function(){
var res = [this[0]];
for(var i = 1; i < this.length; i++){
var repeat = false;
for(var j = 0; j < res.length; j++){
if(this[i] == res[j]){
repeat= true;
break;
}
}
if(!repeat){
res.push(this[i]);
}
}
return res;
}
var arrNum2 = [1,4,1,1,3,3,4,6,7,8,3,7,0,2,11,2,2,22,11,22];
console.log(arrNum2.unique1());
数组去重这里再加上一个方法
遍历将数组的值添加到一个对象的属性名里,并给属性赋值,对象不能添加相同的属性名,依据这个可以实现数组的去重,然后用Object.keys(对象)返回这个对象可枚举属性组成的数组,这个数组就是去重后的数组
let a = ['1','2','3','3',NaN,undefined,undefined,'a','b','c'];
const unique = arr =>{
var obj = {}
arr.forEach(value =>{
obj[value] = 0
})
return Object.keys(obj)
}
console.log(unqiue(a))//['1','2','3','NaN','undefined','a','b','c']
4.字符串
String对象属性
(1)length属性
length算是字符串非常常用的属性了,它的功能是获取字符串的长度,当然需要注意的是js中的中文每个汉字也只能代表一个字符
var str = 'abc';
console.log(str.length);//3
(2)prototype属性
prototype在面向对象编程中经常使用到,用来给对象添加属性或方法,并且添加的方法或属性在所有的实例上共享,因此也常用来扩展js内置对象,如下面的代码给字符串添加了一个去除两边空格的方法
String.prototype.trim = function(){
return this.replace(/^\s*|\s*$/g, '')
}
String对象方法 获取类方法 (1)charAt()用来制定位置的字符串,index为字符串索引值,从0开始到string.length-1,若不在这个范围将返回一个空字符串
stringObject.charAt(index)
var str = 'abcde'
console.log(str.charAt(2))// 返回c
console.log(str.charAt(8))//返回空字符串
截取类方法
(1)substring()
stringObject.substring(start,end)
substring()是最常用的字符串截取方法,它可以截取两个参数(参数不能为负值),分别是要截取的开始位置和结束位置,它将返回一个新的字符串,其内容是从start处到end-1处的字符,若截取参数(end)省略,则表示从start位置一直截取到最后 var str = 'abcdefghj'; console.log(str.substring(1,4));//返回bcd console.log(str.substring(1));//返回bcdefg console.log(str.substring(-1))//返回abcdefghj,传入负值时会视为0
split()方法
split()方法用于把一个字符串分割成字符串数组,第一个参数separator表示分割位置(参考符),第二个参数表示返回数组的允许最大长度
var str = 'a|b|c|d|e';
console.log(str.split('|'));//返回["a","b","c","d","e"]
console.log(str.split('|',3));//返回["a","b","c"]
console.log(str.split(''));//返回["a", "|", "b", "|", "c", "|", "d", "|", "e"]