2020.04.03 Javasrcipt专项练习错误总结

一、

2020.04.03 Javasrcipt专项练习错误总结关系不大

 

二、

2020.04.03 Javasrcipt专项练习错误总结

块内声明的变量只要没加var 都算作全局变量。

js看起来像支持块级作用域,实际上只有函数作用域和全局作用域。

JavaScript语言精粹内对全局变量有明确的批判

A:函数声明的形式定义函数有声明提升的特性,也就是不论是否进入if(x),foo都定义了

C,声明一个全局函数foo

D,ES6才规定块级作用域。

不要在块内声明一个函数(严格模式会报语法错误)。如果确实需要在块中定义函数,可以使用函数表达式来声明函数。

2020.04.03 Javasrcipt专项练习错误总结

三、

function fun1(){

var val; console. log(val);//undefined

val = 20; console.log(val);//20

}

fun1();

解析:由于函数内重新定义val,导致变量val被提升到了顶端,但它被赋予的值并没有提升,所以第一个console.log(val)输出的只是定义过但没有被赋值的val,第二个console.log输出的是被赋值20的val。

变量提升,赋值语句不提升

var val = 20 等价于 var val ,val = 20

所以第一个console.log(val)只能读取到val而读取不到20

 

js里有域的概念,函数外边的是全局值,在fun1函数里是局部域,可以读取外部变量,但是这个局部域里又重新定义,就不会再读取外部,覆盖

 

四、

2020.04.03 Javasrcipt专项练习错误总结

    concat()连接两个或者更多的数组并返回结果。pop()删除并返回数组的最后一个元素。sort()是对数组进行排序,splice()删除元素并向数组中添加新元素。

concat连接数组但是不改变院数组,splice删除数据会改变数组,sort排序会改变数组,pop出栈返回最后一个最后一个元素,改变数组

 

五、

var myObject = {

    foo: "bar",

    func: function() {

        var self = this;

        console.log(this.foo);  

        console.log(self.foo);  

        (function() {

            console.log(this.foo);  

            console.log(self.foo);  

        }());

    }

};

myObject.func();

程序的输出是什么?bar bar undefined bar

解析:

1.第一个this.foo输出bar,因为当前this指向对象myObject。

2.第二个self.foo输出bar,因为self是this的副本,同指向myObject对象。

3.第三个this.foo输出undefined,因为这个IIFE(立即执行函数表达式)中的this指向window。

4.第四个self.foo输出bar,因为这个匿名函数所处的上下文中没有self,所以通过作用域链向上查找,从包含它的父函数中找到了指向myObject对象的self。

 

// 以下的任何一种方式都可以立即执行函数表达式,利用函数的执行环境
// 创建私有作用域

(function(){ /* code */ }()); // Crockford 推荐这个
(function(){ /* code */ })(); // 这个同样运行正常

 

六、
function Foo(){

var i=0;

return function(){

console.log(i++);

}

}

var f1=Foo(), f2=Foo();

f1();//return i=1 输出0

f1();//return i=2 输出1

f2();//return i=1 输出0

 

解析:

f1(),f2()分别创建了自己的执行环境,所以它们两个是相互独立的,执行之后都会返回一个匿名函数,这个匿名函数的作用域链被初始化为其包含函数的活动对象(这里也就是i)和全局变量对象,f1执行之后i并不会销毁,因为返回的匿名函数还要引用i,i仍然在内存中,所以执行两次之后i的值变成了1,而f2执行之后i为0

++运算符的使用,放在数字后表示后增,即先执行再+1,这里就是先执行console.log(i)之后i再加1,所以f1执行第二次的时候i已经变成了1,自然就输出1了。

 

七、

     2020.04.03 Javasrcipt专项练习错误总结

 

立即执行函数(IIFE)不是一种闭包,它只是函数的一种调用方式,和闭包没有必然的联系,两者经常结合着一起使用,但两者的本质并不同。

链式作用域是js本身自然存在的一种获取变量的方式。链式作用域外部可以访问内部,内部访问外部需要设置一个函数,由此产生闭包。


C:闭包可以访问其他函数内部变量的函数,而立即执行函数穿参,相当于父级变量;闭包需要手动执行,不能自主释放内存;而立即执行函数相当于做了一次函数执行,最后释放内存。逻辑上立即执行函数可以理解为:声明闭包函数-执行-释放内存

 

八、

     2020.04.03 Javasrcipt专项练习错误总结

先解释一下“同步模式”和“异步模式”:

(1)同步模式:就是后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的。

(2)异步模式:完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

JavaScript中实现异步编程模式的4种方法,回调函数、事件监听、发布/订阅、Promises对象:

(1)回调函数:这是异步编程最基本的方法,优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。 例:假定有两个函数f1和f2,后者等待前者的执行结果,如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。

(2)事件监听:任务的执行不取决于代码的顺序,而取决于某个事件是否发生。优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以”去耦合”(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。

例:为f1绑定一个事件,当f1发生done事件,就执行f2。

(3)发布/订阅:我们假定,存在一个”信号中心”,某个任务执行完成,就向信号中心”发布”(publish)一个信号,其他任务可以向信号中心”订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做”发布/订阅模式”(publish-subscribe pattern),又称”观察者模式”(observer pattern)。这种方法的性质与”事件监听”类似,但是明显优于后者。因为我们可以通过查看”消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

(4)Promises对象:是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。

例:f1的回调函数f2,f1().then(f2);

 

代码例子:

1.回调函数
f1();
f2();
function f1(callback){
setTimeout(function () {
// f1的任务代码
callback();
}, 1000);
}
f1(f2);

2.事件监听
f1.on('done', f2);
function f1(){
setTimeout(function () {
// f1的任务代码
f1.trigger('done');
}, 1000);
}

3.发布/订阅
jQuery.subscribe("done", f2);
function f1(){
setTimeout(function () {
// f1的任务代码
jQuery.publish("done");
}, 1000);
}
jQuery.unsubscribe("done", f2);

4.Promises对象
f1().then(f2);
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任务代码
dfd.resolve();
}, 500);
return dfd.promise;
}
指定多个回调函数:
f1().then(f2).then(f3);
指定发生错误时的回调函数:
f1().then(f2).fail(f3);

 

九、

     2020.04.03 Javasrcipt专项练习错误总结

d.setDate(n);

n表示一个月中的一天的一个数值(1 ~ 31):

0 为上一个月的最后一天
-1 为上一个月最后一天之前的一天
如果当月有 31 天:
32 为下个月的第一天
如果当月有 30 天:

32 为下一个月的第二天;

40 为下一个月的第9天;

 

setMonth(n),这里是0-11分别对应1-12月