1.判断以下程序的输出结果:
var age=100;
function test(){
this.age=50;
return funtion(){
return this.age;
}
}
var m = new test();
alert( m() );
var n=test();
alert( n() );
答案:100,50
构造函数一旦返回一个对象,就不再创建新对象
m获得的是function(){ return this.age;}
n=test(), this指向window. 先将全局变量age变为50,
又返回一个函数function(){ return this.age;} 保存变量
n中,调用n时,this指向window.
2.判断以下程序的输出结果:
var name ="The Window";
var obj ={
name:"My obj",
getName:function(){
return function(){
return this.name;
}
}
};
console.log(obj.getName()());
答案:The window
obj.getName()返回的是一个函数对象function(){ return this.name;}
(function(){return this.name;}()) 相当于匿名函数自调,this指向window
3.判断以下程序的输出结果:
var length =10;
function fn(){
console.log(this.length);
}
var obj ={
length:5;
method:function(fn){
fn();
arguments[0]();
}
}
obj.method(fn,1)
答案:10 2
fn() this指向window,所以输出10
arguments[0]()属于特殊情况,this->arguments,相当于arguments.0(),所以,
this指向arguments。fn也属于arguments的成员,所以length输出的是obj.method()的参数个数,2
4.统计一个字符串中出现次数最多的字符是?共出现多少次?
答案:
var dict={};
var c="",max=1;
for(var i=0;i<str.length;i++){
var char =str[i];
if(dict[chart]===undefined)
dict[char]=1;
else {
dict[char]+=1;
if(dict[char]>max){
max=dict[char];
c=char;
}
}
}
console.log(c,max);
提前创建一个空对象,用于保存每个字母出现的次数。
提前创建变量,准备保存出现次数最多的字符和出现的次数.
然后,遍历字符串中的每个字母,每遍历一个字母就判断结果
对象中是否包含以当前字母为属性名的属性。如果不包含以
当前字母为属性名的属性,说明是首次遇见该字母,就向结
果对象中强行添加以该字母为属性名的属性,值暂时为1。如
果结果对象中已经包含以当前字母为属性名的属性,说明不是
第一次碰见该字母。则取出该字母名属性对应的次数+1。只要
当前字母出现的次数>之前变量中记录的最大次数,就用当前字
母和出现次数,取而代之。
5.判断以下程序的输出结果:
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i);
},0)
}
console.log(i);
答案:5 5 5 5 5
函数定义时,函数内容是不执行的,所以i还是i,不会变成0,1,2,3,4
定时器中的回调函数只能在主程序执行完才能开始执行
当主程序执行完,循环变量i,已经被改为5了.
6.判断以下程序的输出结果:
window.color ="red";
let color="green";
let obj={
color:"blue"
};
let sayColor=()=>{
return this.color;
}
console.log(sayColor.apply(obj));
let a=10;
console.log(window.a);
答案: red undefined
let 相当于匿名函数自调,所以,let 声明的变量,不会自动加入到window.
箭头函数内外this通用,所以apply也无法替换sayColor函数内的this,
所以this指向window,所以输出red.
7.判断以下程序的输出结果:
var c=1;
function c(c){
console.log(c);
var c=3;
}
c(2);
答案:报错:TypeError:c 不是一个函数
function c(c){} 整体被声明提前,后又被c=1代替.所以,
c最后不是一个函数,而是数字1
8.判断以下程序的输出结果:
function change(){
alert(typeof fn)
function fn(){ alert('hello') }
var fn;
}
change();
答案:function
function fn(){ ... }被整体声明提前了
var fn发现已经有fn变量了,就不再重复创建,所以,
var fn 没作用.
9.判断以下程序的输出结果:
a=3;
a.prop=4;
alert(a+a.prop);
答案:NaN
a.prop=4;等效于new Number(a).prop =4,但是new Number(a),
使用后自动释放,4也不存在了.
再次使用a.prop,又等效于新的new Number(a),所以没有prop属性,
值为undefined.
数字+undefined,undefined隐式转换为数字NaN,导致计算结果为NaN
10.判断以下程序的输出结果:
var o={
a=10,
b:{
a:12,
fn:function(){
var a=13;
console.log(this.a);
}
}
}
o.b.fn();
答案:12 this指.前的o.b对象,所以a为12
11.判断以下程序的输出结果:
var obj1={
name:'obj1',
fn:function(){
document.write(this.name);
}
};
var obj2 ={ name:'obj2' };
var obj3 ={ name:'obj3' };
obj1.fn();
var newFn =obj1.fn;
newFn();
newFn.call(obj2);
obj3.fn=newFn;
obj3.fn();
答案: obj1 空字符串 obj2 obj3
this指.前的obj1
因为newFn调用时,前没有. ,所以this->window,
call是强行替换newFn中的this为obj2
this指 .前的obj3
12.一个数组par中存放有多个人员的信息,
每个人员的信息由年龄age和姓名name组成,如{age:2,name:'xx'}.
请写一段JS程序,对这个数组按年龄从小到大进行排序.
答案:function parSort(arr,propName){
arr.sort(function(a,b){
return a[propName]-b[propName];
});
}
parSort(arr,"age");
1)数组的sort函数的参数,是一个比较器函数。比较器函数
的形参a和b,指当前要排序的数组中的任意两个作比较的元素。
如果要作比较的a和b两个元素时简单的数字类型,则a直接和b相减,
就可比较两数大小。但是,如果a和b都是对象类型的元素。要比较
两个对象中某个属性的值的大小,就必须用a.属性-b.属性。如果属性
名是灵活的,来自于变量,则必须用a[属性名变量]-b[属性名变量],
就可比出两个对象的某个属性值的大小.
2)最后,数组是引用类型的对象,在函数内修改数组,等效于修改原数组。
所以不用返回值。
13.有字符串var =' abc345efgabcab';请写出3条JS语句分别实现如下
3个功能:
1)去掉字符串中的a 、b、c字符,形成结果:'345efg'
2)将字符串中的数字用中括号括起来,形成结果:'abc[345]efgabcab'
3)将字符串中的每个数字的值分别乘以2,形成结果:'abc6810efgabcab'
答案:
1)str.replace(/([a-c])/g,'');
2)str.replace(/(d+)/g,'[$1]');
3)str.replace(/(d)/g,function(num){ return num*2 });
1)将字符串中的a,b,c三个字符都替换为空字符串
2)找到字符串中多个连续的数字,分为一组,然后将这一组的内容,替换为用[ ]包裹。$1,
可获得关键词第一个()包裹的内容.
3)找到字符串中的每个数字,*2后,再放回原位置.
14.判断以下程序的输出结果:
var a=10;
var obj={
a:20,
intr:function(){
var a=30;
console.log(this.a);
}
}
obj.intr();
var intr=obj.intr;
intr();
答案:20 10
obj.intr(),this指.前的obj,所以输出20
intr(),this指window,所以输出10
15.判断以下程序的输出结果:
function fun(){
for(var i=0;arr=[];i<3;i++){
arr[i]=function(){
console.log(i);
}
}
return arr;
}
var funs=fun();
funs[0]();
funs[1]();
funs[2]();
答案:3 3 3
16.介绍JavaScript的原型,原型链?有什么特点?
答案:
原型:
- JavaScript的所有对象中都包含了一个[proto]内部属性,这个属性所对应的就是该
对象的原型.
- JavaScript的函数对象,除了原型[proto]之外,还预置了prototype属性
- 当函数对象作为构造函数创建实例时,该prototype属性值将被作为实例对象的原型[proto].
原型链:
- 当一个对象调用的属性/方法自身不存在时,就会去自己[proto]关联的前辈prototype对象上去找
- 如果没找到,就会去该prototype原型[proto]关联的前辈prototype去找。依次类推,直到找到属性/
方法或undefined为止。从而形成了所谓的"原型链"
原型特点:
-JavaScript对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变。
17.谈谈JavaScript垃圾回收方法
答案:标记清除(mark and sweep),
- 这是JavaSript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,
垃圾回收器将其标记为"进入环境",当变量离开环境的时候(函数执行结束)将其标记为"离开环境"
- 垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境
变量中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了.
引用计数(reference counting)
- 在低版本 IE 中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个 变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加 1,如果该变量的值变成了另外一个,则这个值得引用次数减 1,当这个值的引用次数变为 0 的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运
行的时候清理掉引用次数为 0 的值占用的空间
18.说说严格模式的限制?
答案:严格模式主要有以下限制:
- 变量必须声明后再使用
- 函数的参数不能有同名的属性,否则报错
- 不能使用width语句
- 不能对只读属性赋值,否则报错
- 不能使用前缀0 表示八进制数,否则报错
- 不能删除变量 delete prop,会报错,只能删除属性delete global[prop]
- eval 不会再它的外层作用域引入变量
- eval 和arguments不能被重新赋值
- arguments不会自动反映函数参数的变化
- 不能使用arguments.callee
- 不能使用arguments.caller
- 禁止this指向全局对象
- 不能使用fn.caller 和 fn.arguments获取函数调用的堆栈
- 增加了保留字(比如protected、static 和interface)
19。使用正则表达式验证邮箱格式
答案:
var reg =/^(w)+(.w+)*@(w)+(.w{2,3}){1,3}$/;
var email="example@qq.com";
console.log(email);//true
20.使用typeof bar ==="object" 来确定bar是否是一个对象时有什么潜在的缺陷?
这个陷阱如何避免?
答案:尽管typeof bar ==="object"是检查bar是否是对象的可靠方法,
但JavaScript中令人惊讶的问题null也被认为是一个对象!
因此,对于大多数开发人员来说,下面的代码会将true(而不是false)打印到控制台:
var bar = null;
console.log(typeof bar === "object"); /// logs true
只要知道这一点,就可以通过检查bar是否为空来轻松避免该问题:
console.log((bar !== null) && (typeof bar === "object")); // logs false
为了让我们的答案更加的完整,还有两件事值得注意: 首先,如果bar是一个函数,上面的解决方案将返回false。在大多数情况下,这是所期望的行为,但是在您希望函数返回true的情况下,您可以将上述解决方案修改为:
console.log((bar !== null) && ((typeof bar === "object") || (typeof bar === "function")));
其次,如果bar是数组,则上述解决方案将返回true(例如,如果var bar = [];)。在大多数情况下,这是所希望的行为,因为数组确实是对象,但是在您想要对数组也是false的情况下,可以将上述解决方案修改为:
console.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]"));
但是,还有一个替代方法对空值,数组和函数返回false,但对于对象则为true:
console.log((bar !== null) && (bar.constructor === Object));
或者,如果您使用jQuery:
console.log((bar !== null) && (typeof bar === "object") && (! $.isArray(bar)));
ES5使得数组的情况非常简单,包括它自己的空检查:
console.log(Array.isArray(bar));
20.以下代码的输出是什么?解释你的答案
var a={ },
b={key:'b'},
c={key:'c'};
a[b] =123;
a[c] =456;
console.log(a[b]);
答案: 456
原因如下:设置对象属性时,JavaScript会隐式地将参数串联起来。
在这种情况下,由于b和c都是对象,他们都将转换为"[objet Object]"。
因此,a[b]和a[c]都等价于["[objet Object]"],并且可以互换使用。因此,
设置或引用[c]与设置或引用[b]完全相同。