引言:
最近开始着手认真学习JS,大三下学期经历了一系列的面试,越来越意识到JS的重要和知识的匮乏,不甘于再偷懒用着第三方库,所以开始认真学习JS,下面会贴出一些很基础的小函数来体现JS的一些细节的知识。
一、setTimeout是否会阻碍进程:
//alert分别输出什么值??
function test() {
var a = 1;
setTimeout(function() {
alert(a);
a = 3;
}, 1000);
a = 2;
setTimeout(function() {
alert(a);
a = 4;
}, 3000);
}
test();
alert(0);
结果:
依次输出0 2 3;
setTimeout()不会影响进程,只是会暂时“挂起”,等到计时结束后再运行其中的函数,所以调用test()函数时,创建a变量,值为1、第一个计时器开始计时、a的值变为2、第二个计时器开始计时、输出0、第一个计时器计时完毕,先输出2、a的值赋为3、第二个计时器计时完毕,输出3。
二、变量的作用域:
//程序依次输出什么?
var foo = 1;
function main(){
alert(foo); //由于变量提升 所以输出undefined
var foo = 30 ; // 定义了一个main()局部环境中的局部变量foo,赋值为30
alert(this.foo); //通过this来引用全局变量,输出1
this.foo = 3;
alert(this.foo);//输出3
}
var m0 = main();
结果:
依次输出 undefined 1 3
此处需要注意的问题是如果在main()函数的局部环境中没有定义与其上级的局部环境同名的变量,不需使用this就可引用foo变量,因为JS作用域链能向上查找而不能向下查找
三、没有块级作用域!
//输出10还是undefined?
function outer() {
for (var i = 0 ;i < 10; i++){
var t = "aaa";
}
alert(i);
alert(t);
}
outer();
结果:
输出10,aaa
因为在JS中没有块级作用域,在for if等执行完成后,其中定义的变量并不会被销毁,而是添加到最近的环境中,所以outer函数中可以获取for定义的变量
三、作用域链进一步探究
//作用域链探究
var person = {
name:"wangyihua",
age:21,
sex:1
};
function usePerson() {
var phone = "1092118325";
function add() {
with (person){
var info = name + age.toString() + sex.toString()+phone;
}
alert(person.sex) //报错 with会延长作用域链 把person添加进来 但是运行结束后会销毁 所以with外不能调用person
return info ;
}
alert(info); //报错 is not defined
var inf = add();
return inf;
}
var information = usePerson();
alert(information); //输出wangyihua2111092118325
结果:
见代码注释
四、阿里面试的一道题:
//实现add(1)(2)(3) == 6
function add(a){
return function(b){
return function(c){
return a+b+c;
}
}
}
alert(add(1)(2)(3));
结果:
这是阿里笔试的一道题,当时没有做出来,因为JS学的不多,根本没有见过这种形式,只见过(function(a){})(2)的这种形式,之后被一点拨就明白了,JS不仅可以返回一个数值,也可以返回一个函数,解决起来就很简单了
-----------------2016.4.29.第一次
四 、没有重载
在java中,我们可以根据构造函数传入的变量的不同来调用不同的构造函数来构造我们想要的对象,但是对于JS,JS的参数是由包含零或多个值组成的数组来表示的,也就是传说中的arguments,我们可以给函数传递若干个参数解析器也不会有怨言,他们都存在函数体中的arguments对象中,我们可以根据arguments[n]来获取传入的参数,使用arguments.length来获知传入了多少个参数。
function constructor (name,age) {
var person = new Object();
person.name = name;
person.age = age;
alert("性别:"+arguments[2]+"籍贯:"+arguments[3]);
return person;
}
var person1 = constructor("wangyihua",21,"men","山东青岛");
alert("姓名:"+person1.name+"年龄:"+person1.age.toString());
结果:
下面我们对“构造函数”进行升级,使其能模仿重载:
function constructor (name,age,sex,address) {
var person = new Object();
switch (arguments.length){
case 2 :
person.name = name;
person.age = age;
break;
case 3 :
person.name = name;
person.age = age;
person.sex = sex;
break;
case 4 :
person.name = name;
person.age = age;
person.sex = sex;
person.address = address;
break;
default:
alert("吃不下啦!")
}
return person;
}
var person1 = constructor("wangyihua",21,"男","山东青岛");
alert("姓名:"+person1.name+"年龄:"+person1.age.toString()+"性别:"+person1.sex+"籍贯:"+person1.address);
var person2 = constructor("wangyihua",21,"男");
alert("籍贯:"+person2.address);
结果:
TIP:函数后面命名的参数只是帮我们提供便利,便于使用传入的参数,但不是必须的,我们可以使用arguments[n]来获取传入的参数,也就是说name与arguments[0]是等价的。
------------------------------------ 五一休息了三天,所以没有更新,很抱歉 2016.05.03 第二次更新
五、由Arraty.sort()发现的一些小细节
本来Array的栈方法pop()、push()、队列方法shift()、unshift()和操作方法concat()、slice()、splice()重排序方法sort()都已经有所了解,但是在细看的时候还是引出了一些小细节的问题,一个是slice()不会改变原数组,而且传入的第二个参数是结束的位置(在复制时不包括结束位置)
1.
//slice(-3,-1) 输出什么?
var arr = ["a","b","c"];
var arr2 = arr.slice(-3,-1);
alert(arr2);
结果:
输出a,b,相当于slice(0,2),当参数为负数时,实际参数的值相当于传入的负值加上数组的长度
2.
//程序会输出什么?
var arr = [1,2,5,15,20];
var arr2 = arr.sort();
alert(arr2);
结果:
输出1,15,2,20,5
因为重排序方法sort()无论接收什么类型的值,都会当作字符串来进行比较,所以会出现原本顺序正确的数组被打乱的现象,所幸sort()可以接受一个函数来辅助排序,对于数值,我们可以设计一个函数compare()来进行辅助:
var arr = [1,2,5,15,20];
var arr2 = arr.sort(compare);
alert(arr2);
function compare(val1,val2) {
return val1 - val2;
}
结果:
输出1,2,5,15,20
借助函数进行排序的原理是,先将值传入辅助函数进行对比,然后根据传回的值(正数为大于,负数为小于,零为相等)来进行排序,所以对于Number类型返回两者相减的结果就正好解决的这个问题