视频链接:Web前端JavaScript权威课堂
本视频对于初入JavaScript特别友好,成哥讲的很通透~~~
本文为视频笔记,感谢阅读~~~
jquary(javascriptt封装版本,jquary是一个工具
未知(这个未知也是一个工具是CSS3的简化工具)
css3 html5.0 es6.0
bootstrap
node.js(后端元素) 等等
引擎:类似汽车中发动机能让汽车动起来的物件
主流浏览器(在市场上有份额 大于百分之三 有独立研发的内核)
浏览器及其内核
浏览器 | 内核 |
---|---|
IE | trident |
Chrome | webkit/blink |
firefox | Gecko |
Opera | presto |
Safari | webkit |
注意浏览器和内核的区别!!!
js引入方式两种(页面级js文件(可以放在head中或者body中) 外部js文件)
正常开发要求标准:结构(html) 行为(js) 样式(css) 相分离(每个要求都是单独的文件)
var a ; //声明变量(向系统中申请内存 名字叫做a 类似酒店开房)
a = 100 ; //将100赋值给a
var a = [1,3];
var b = a;
a.push(2);//新添入值,地址不变。
a = [1,2,4,5]; 堆中开辟新的空间,a中存放新的地址,和原来地址不一样
document.write(b);
var arr = [1,2];
var x = arr.length;
arr.push(3);
console.log(x);//得到的x还是2,而不是3。
function text(){}
if(){}后也不用加分号
for(){}后也不用加分号
任何符号两侧 都要留有空格 例如var arr = [1,2];
var a;
document.write(b)
"-" "*" "%" "=" "()"
1/0 //显示infinity
-1/0 //显示-infinity
1/0 //Infinity Number
0/0 //Not a number --> NaN(数字类型)
"++" "--" "+=" "-=" "*=" "/=" "%="
var a = 10;
var b = ++a - 1 + a ++; 先+1 执行完语句后a再+1;
结果:b = 21 a = 12
var a += 10 + 1; 后两个先算
赋值的顺序 自右向左,计算的顺序,自左向右
a = a + b;
b = a - b;
a = a - b;
">" "<" "=" ">=" "<=" "==" "!="
比较运算符返回true或者false
例1:var a = "10" > "8" -->false
逻辑运算符
"&&" "||" "!"
(返回的是表达式的值不是对应的boolean的值,但比较时,是比较的boolean的值)
var c = 1 + 1 && 1 - 1;
1+1=2
1-1=0
2&&0=0;
var a = (window.foo || (window.foo = 'bar'));//a = bar;(bar为表达式的值)
首先:或运算符的优先级高于赋值运算符,要是不加括号就会报错的
然后:这题在后面加了个括号,所以就先执行一下window.foo = 'bar'
最后:执行前面时,window.foo等于bar了,所以是对的了,最后返回的就是bar
var c = parseInt(window.prompt('input'));
/*系统提示输出框,输入,网页就会显示输入的信息*/
for (var i = 0 ; i < 100; i++){ //从0 到100执行里面,执行了100遍
if(i % 2 == 0 && i % 5 == 0 && i % 7 == 0){
document.write(i + " ");
}
}
var i = 100;
for (; i --; ){
if(i % 2 == 0 && i % 5 == 0 && i % 7 == 0){
document.write(i + " ");
}
}
var i = 1;
var count = 0;
for(;i;){
document.write('a');
count++;
if(count == 10){
i = 0;
}
}
var i = 0;
if(i < 100){.....}
i++;
if(i < 100){......}
.....
var i = 0;
while(i < 10){
document.write(i + " ");
i ++;
}
var i = 1;
while(i){
document.write(i);
}
var i = 0;
do{
document.write('a');//十个a
i ++;
}while(i < 10)
var first = 1,
second = 1,
third;
switch(n){//n可以为任何东西:字符串、数字、布尔类型、都可以。
case 1:
console.log('a');
break;//执行完后这句后跳出,不执行下面的语句
case 2:
console.log('b');
break;
case 3:
console.log('c');
break;
}
switch(n){
case "monday":
case "wednesday":
case "周三":
case"thursday"://将坏处变为好处
case"friday":
console.log('working');
break;
case "周六":
case "周天":
console.log('relaxing');
break;
}
var sum = 0;
for(var i = 1;i < 100;i ++){
sum += i;
console.log(i);
if(sum > 100){
break;//根据某些条件跳出循环
}
}
for(var i = 0; i < 100;i ++){
if(i % 7 == 0 || i % 10 == 7){
continue;//终止本次循环,不执行下面的语句,直接执行下次即i++
}
console.log(i);
}
var arr = [1,2,3,4,5,6];//定义数组
for(var i = 0; i < arr.length;i ++){//arr.length是数组的长度
arr[i] += 1;//修改数组中数的值
console.log(arr[i]);
}
var deng = {
//key value(可以为字符串,数字等都可以)
lastName:"Deng", //lastName:属性名 "Deng":属性值(重点)
age:40,
son:"xiaodeng",
wife:undefined,
}
console.log(deng.lastName); -->Deng
deng.lastName = "old Deng";//改变变量值
console.log(deng.lastName); -->Old Deng
能帮我们区分数据类型:可以typeof(a)或者typeof a两种形式都行`
var num = {};
console.log(typeof(num));//type正确用法
var str = "jfakl"
console.log(typeof str);//typeof后可以跟空格但是最好不要这样用
number string undefined boolean function object
object(泛泛的引用值都返回object)
function(自己查各种类型的返回条件)
有个历史遗留性问题,虽然null是原始值,原因是最早时null是代替空对象,出现的,给空对象占位的,直到现在也没有改回来。`
var num = Number(true);//将布尔类型转换为数字类型
console.log(typeof(num) + " " + num);
var demo = "124.333";
var num = parseInt(demo);
console.log(typeof(num));//结果为124(直接去掉小数部分)
var demo = "10";
var num = parseInt(demo,16);//以目标进制为基底转化为十进制,所以输出结果是16。
console.log(typeof(num));
console.log(parseFloat("124.2wg")); 得到结果:124.2
var demo = 123;
var num = demo.toString();
console.log(typeof(num) + " " + num);
var demo = 32;
var num = demo.toString(16);//将radix转换为16进制,与前面parseInt中的radix不同
console.log(typeof(num) + " " + num);
var num = 10101010;
var num1 = parseInt(num,2);
var num2 = num1.toString(16);
var a = "123";
a ++;
console.log(a);//a为124且为数字类型
var x = + "abd";
console.log( x + " : " + typeof(x));
//结果为NaN,虽然不是个数,但类型为数字类型。
var "a" * 1 -->NaN
var a = 1 > "2";//是将字符串转换为数字2再进行比较,结果为false
console.log(a);
var a = "3"> "2";//是将字符串3与2的ASCII码进行比较,结果为true
console.log(a);
2 > 3 < 1 true
//一个一个算,先算前面的boolean值,然后将boolean值转化为数字和1再比较
2 > 1 > 3 false
3 > 2 > 1 false
== != ===
1 == true成立
1 == "1"成立
undefined > 0 //false
undefined < 0 //false
undefined == 0 //false
null > 0 false
null < 0 false
null == 0 false
undefined == null // true
NaN == NaN //false
/* 唯一一个原始值,任何一种情况都不等于自身,而且什么啥也不等于
但是如果需要判断得到的结果是不是NaN的话,可以利用变量加上空串的方式
例如NaN+"" == "NaN"
*/
{} == {} //false
/*对象是引用值,引用值比较的是地址
这两个空对象指向两个不同的房间,看着再一样也是两个房间,不相等。
*/
var obj = {};
var obj1 = obj;
obj1 === obj;
//返回true,因为引用值赋值赋的是地址。所以一个房间那肯定相等。
字符串
"a" + -->加啥都等于字符串
"a" * -->转换为Number类型
"a" > -->两个字符串比较ASCII码
=== !==
console.log(typeof(typeof(a))); 返回string
console.log(typeof(a)); 未定义就是使用a,返回字符串类型的undefined
console.log(a); 报错 not defined
var x = 123123.4232332;
alert(x.toFixed(5));//科学记数法四舍五入,保留几位有效数字。alert是弹出框
函数其实本质上和变量一样,都是一个筐,只不过这个筐装了很多条语句。它也是引用值,存的是地址,输出时永远不能输出地址,输出地址指向的房间
function theFirstName(){
document.write("hello world");
}
theFirsrName();//命名:小驼峰原则
var test1 = function test(){
从function开始到大括号结束,这些都叫做表达式
表达式是可以忽略它的名字的,调用时只有调用test1才执行,调用test报错,但是test1.name为test,但是要是函数声明方式中test1.name为自己"test1"
document.write("hello world");
}
var testN = function(){//b1与b2之间的区别在于b1函数的名字为test1,调用时应调用test1,而不是test,而b2函数的名字为默认本身testN,直接调用就可以。
document.write("hello world1");
}
function sum(a){//形参
for(var i = 0; i < arguments.length ;i++){
console.log(arguments[i]);//系统可以打印出来 ,arguments:实参列表,是个数组,sum.length形参的长度
}
}
sum(1 , 2 , 3)//1 ,2 , 3 实参,都存放在arguments中[1,2,3] 对arguments求和可以将所有实参求和
function sum(a,b,c,d){ //等价于在函数中var a,b,c,d;
if(sum.length > arguments.length){
console.log('形参多了');
}else if(sum.length < arguments.length){
console.log('实参多了');
}else{
console.log('相等');
}
}
sum(1 , 2 , 3 ,undefined)//结果为相等
function sum(){
//arguments 1 2 3 4 5 6
var result = 0;
for(var i = 0; i < arguments.length; i ++){
result += arguments [i];
}
console.log(result);
}
sum(1,2,3,4,5,6);
function sum(a,b){
//arguments 1 6
a = 10;
console.log(arguments[0]);//结果为10 因为arguments与形参存在映射关系,但不是同一个东西,所以一个变另一个也变,只有形参实参相等的时才会有映射的规则,不相等不对应实参了,相等的地方保持映射,它俩不等的地方就不映射了
}
sum(1,6);
function sum(a,b){
//arguments 1
b = 10;
console.log(arguments[1]);//结果为undefined,因为只有形参实参相等的时才会有映射的规则,不相等不对应实参了,相等的地方保持映射,它俩不等的地方就不映射了,arguments中不会有其他形参,例题中的b只当作变量用,不用作参数。
}
sum(1);
function sum(a,b){
return 245;//有两个含义既返回 值,又终止函数。
console.log('a');//因为上面有return 所以这行不执行,因为return终止函数了
}
var num = sum();
function myNumber(target){
return + target;
}
var num = myNumber(123);//
console.log(typeof(num)+ " " + num);
//函数结果为数字 类型123
function scream(animal){
switch(animal){
case"dog":
document.write('wang');
return;
case"cat":
document.write('miao!');
return;
case"fish":
document.write('oooo');
return;
}
}
function hanzi(){
var str1 = "";
var str = window.prompt('input');
for(var i = str.length - 1 ;i >= 0 ; i --){
if(str [i] == '1' ){
str1 += '壹';
}
else if( str [i] == '2'){
str1 += '贰';
}
else{
str1 += '叁';
}
}
console.log(str1);
}
hanzi();
function jiecheng(n){
if( n == 1 ){
return 1 ;
}
return n * jiecheng(n - 1);
}
var x = parseInt(window.prompt('input'));
console.log(jiecheng(x));
读规则:千分位有零必须读,没有零不用读 101000:十萬壹
//找规律:n! = n * (n - 1)!;
function mul(n){
return n * mul(n - 1);
}
//mul(3) ==> 3 * mul(2);
//mul(2) ==> 2 * mul(1);
//mul(1) ==> 1 * mul(0);
//找出口,必须找已知条件当出口
if(n == 1 || n == 0){
return 1;
}
//找规律 :fb(n) == fb(n - 1) + fb(n - 2);
// fb(5) ==> fb(4) + fb(3);
// fb(4) ==> fb(3) + fb(2);
// fb(3) ==> fb(2) + fb(1);
function fb(n){
if( n == 1 || n == 2){
return 1;
}
return fb(n - 1) + fb( n - 2);
}
整体提升
:将函数声明(不管写在哪里)永远提升到逻辑的最前面声明提升
:当声明并赋值变量时,会将变量声明提到最前面。
function aa(){
console.log('a');
}
aa();//能执行
aa();
function aa(){
console.log('a');
}//能执行
var a = 1234;
console.log(a);//正确输出 1234
console.log(a);
var a = 1234;
//输出undefined,因为,系统会将语句分解为两部分 var a; a = 1234; 然后将var a提到最前面
1 ==>window {
a : 123
}
2 ==>var a = 123;
1 == 2 //系统下次再访问a时,访问的就是window.a
//var a = b = 123; 会先将123的值付给b,然后声明a,然后再把b的值赋给a。因为赋值是从右向左的,将b的值赋给a是发生在执行过程中,不是预编译
function test(){
var a = b = 134;//执行window.a结果为undefined,执行window.b时结果为123,因为a在函数中声明了,而b只赋值了
}
test();
var x = 123;
==>window.x == 123;
==> window{x:123}
console.log(x)
==> console.log(window.x);
function fn(a){
console.log(a);//function a (){}
var a = 121;//就只执行 a = 123; 因为var a已经预编译执行了,
console.log(a);//a = 121;
function a (){}//预编译已经执行过了,预编译看过的就不会再看了
console.log(a);//a = 121;
var b = function (){};//b= function (){};
console.log(b);//b= function (){};
function d(){};
}
fn(1);
(1)第一步:AO{
}
(2)第二步:AO{
a:undefined,
b:undefined,
}
(3)第三步:AO{
a:1,
b:undefined,
}
(4)第四步:AO{
a:function a(){},
b:undefined,
d:function d(){};
}
var a = 134;//执行 a = 123,
function a(){
}
1.生成GO对象
GO{
a:undefined,
}
2.GO{
a:function a(){},
}
function text(){
var a = b = 123;
console.log(window.a);
}
因为a声明了,所以在AO中。但是b没有,b未声明直接赋值了,就发生了暗示全局变量的过程,b就归GO所有(b = 123),所以window中没有a的值,访问window只有undefined
/*GO{
a:undefined,
text:function (){},
}*/
function text(){
console.log(b);
if(a){ //if不管会不会执行,if中的什么东西都会被拿出来。所以上一句语句是b为undefined。
var b = 134;//因为a为undefined,所以此句不会执行,b还为undefined
}
}
var a ;
text();
/*AO{
b:undefined,
}*/
a = 10;
console.log(a);
a = 100;
function demo(e){
function e(){}
arguments[0] = 2;
console.log(e); //2
if(a){
//备注:这个if中声明function,Google之前是允许的,但是现在不允许了。
var b = 123;
function c(){}
}
var c;
a = 10;
var a;
console.log(b); //undefined
f = 123;
console.log(c); //undefined
console.log(a); //10
}
var a;
demo(1);
console.log(a); //100
console.log(f); //123
解:函数拆解执行
第一步:
/*GO{
a:undefined,
demo:function(){},
}*/
第二步:
a = 100;
/*GO{
a:100,
demo:function(){},
}
*/
function demo(e) {
第四步:
/*var AO = {
e:1,
b:undefined,
c:undefined,
a:undefined,
}*/
function e() {
}
第五步:
/*var AO = {
e:function e(){},
b:undefined,
c:undefined,
a:undefined,
}*/
arguments[0] = 2;
第六步:
/*var AO = {
e:2,
b:undefined,
c:undefined,
a:undefined,
}*/
console.log(e); //e = 2;
if(a){
var b = 123;
function c(){};//不执行
}
var c;
a = 10;
第七步:
/*var AO = {
e:2,
b:undefined,
c:undefined,
a:10,
}*/
var a;
console.log(b); //b = undefined
f = 123;
第八步:
/*GO{
a:100,
demo:function(){},
f:123,
}*/
console.log(c); //c = undefined
console.log(a); //a = 10
}
var a;
demo(1);
第三步:
/*var AO = {
e:undefined,
b:undefined,
c:undefined,
a:undefined,
}*/
console.log(a); // a = 100
console.log(f); // f = 123
console.log(bar());
function bar (){
foo = 10;
function foo(){
//body...
}
var foo = 11;
return foo; //返回11,只要这个名在最下面被赋过值,那么直接输出那个值就好了。
}
function bar(){
return foo; //返回function(){},若是第一句为return,那么就等价于console.log,而且第一句为return,若是下面有函数,那么直接返回函数。
foo = 10;
function foo(){
//body ...
}
var foo = 11;
}
console.log(bar());
test.[[scope]]
//存放由这个函数产生而产生的作用域,存放的是一个作用域,隐式的属性
系统会定期的调用这个属性,但是不会让我们用
function a() {
function b() { //b得到的a的劳动成果,就是a的aAO,拿到的是引用,注意:所有的aAO都是一个人,或者GO也都是一个人。
var b = 123;
}
var a = 123;
b();
}
var glob = 100;
a();
//a刚被定义时,即a刚出生时(就有a.name 和a.[[scope]]等),存放的是它所在环境的执行期上下文,要是在全局环境下,存放的就是GO。
具体解释:
a函数被定义时,发生如下过程:
1.当a定义时,a.[[scope]]中存放GO(a刚定义时a.[[scpoe]]存的是a所在环境的执行期上下文),
2.然后a执行,产生一个执行期上下文并放在自己作用域链的最顶端,然后将最初创建的GO往下串一格,然后形成了自己的作用域链,有第0位,有第1位,一旦我们在a中查找变量的话,会在a的作用域链的顶端即第0位,依次向下查找。
b函数被定义时,发生如下过程:
1.当b定义时,继承a的scope(使用a的劳动成果)
2.当b函数执行时,会创建属于自己的bAO,放在b.[[scope]]最顶端即第0位,依次第1位,第2位存放a[[scope]]的东西,找变量时,先从自己作用域链的最顶端依次向下寻找。
注意:b从a运行后a.[[scope]]中得到的AO与a中的AO是一个AO,指向同一个东西,即b可以更改了a中属性的值
最后
当b执行完后,b只是删除了自己执行时创建bAO但是死死地攥着a的aAO,一直拴在自己身上,恢复最初被创建的状态,
当a执行完后,就将a执行时创建的AO(包括b函数)删掉,不包括GO,GO还在,然后等待下一次执行,再重新创建一个独一无二的a.[[scope]]。
function a(){
function b(){
function c(){
}
c(); //c最先被执行完 ,c.[[scope]]最先被销毁。
}
b(); //c被执行完,才标志着b()执行完,然后b.[[scope]]被销毁。
}
a(); //b被执行完,才标志着a最后一条语句被执行完,a.[[scope]]最后被销毁,可以说销毁和执行完是一个概念。
执行步骤:
a defined a.[[scope]] --> 0 : GO
a doing a.[[scope]] --> 0 : aAO//只有a执行时,a中的语句(像函数b等等)才会被读,b才会被定义,系统中才会有b.[[scope]],a执行才能导致b被执行。
1 : GO
b defined b.[[scope]] --> 0 : aAO
1 : GO
b doing b.[[scope]] --> 0 : bAO
1 : aAO
2 : GO//所以站在b的窗口访问不到c中的内容,没法看到c窗口中的内容
c defined c.[[scope]] --> 0 :bAO
1 : aAO
2 : GO
c doing c.[[scope]] --> 0 : cAO//c被执行完就删除了,再执行时就会产生新的c.[[scope]],除了cAO被删除,剩下的都不变,一样,只是会产生新的cAO。
1 : bAO
2 : aAO
3 : GO
// 在任何一个函数里面想访问变量的话就找函数的作用域链就可以了
function a(){
/* 不管a还是b,各自的作用域链中摆脱不掉的是被定义时的状态,
就像a,a.[[scope]]中始终存着GO,像b.[[scope]]始终存着aAO,
第0位:aAO;
第1位:GO;
*/
function b(){ //内部的函数
var bbb = 234;
document.write(aaa);
}
var aaa = 123;
return b;
//被保存到了外部,所以生成了闭包。
备注:这里是a先被销毁,但是a销毁前,b虽然没被执行,
但是已经拿到了a的执行期上下文了。
}
var glob = 100;
var demo = a();
//a执行完了,a将指向自己AO的线删掉。b定义时得到的是a执行的劳动成果,
虽然a删掉了指向自己AO的那个线,但是b被引用到外部,b依旧保存与那个房间(aAO)之间的关系,
a想删掉那个房间(aAO)都没有办法。
demo(); //结果输出123
function a(){
var num = 100;
function b(){
num ++;
console.log(num);
//函数只有在被调用时才会执行里面的语句,虽然声明完b,
但是可以运行出结果并显示的原因,是后面demo也就是b被调用了。
}
return b;
}
var demo = a();
//自己理解:a执行后删除线,但是b.[[scope]]中保存着aAO,
执行完a将函数的引用(也就是b引用)抛出去赋给demo,
a执行结束,所以demo()指的是b();
demo();
//执行输出101 ,
原因:b执行未产生新的bAO。继续执行b函数中的num++,
num从b.[[scope]]第0位找,虽然a执行完了删掉了,但是b还是保存着aAO。
demo();
//执行输出102 ,
原因:b继续从b.[[scope]]第0位找num ,执行num++。
但此时的num因为被b执行一遍了更改为101了,所以再执行一遍就为102了。
function add(){
var count = 0;
function demo(){
count ++;
console.log(count);
}
return demo;
}
var counter = add();
counter();//执行结果1
counter();// 2
counter();// 3
function test(){
var num = 100;
function a(){
num ++;
//aAO中的num,a函数中的num与b函数中修改的num是一个num,都来自于aAO中。
console.log(num);
}
function b(){
num --; //aAO中的num
console.log(num);
}
return [a,b]
//返回了一个数组,myArr[0],代表执行a,myArr[1]代表执行b。
}
var myArr = test();
myArr[0](); //101
myArr[1](); //100
function eater(){
var food = "";
//类似存储结构
var obj = {
eat : function (){
console.log("i am eating " + food);
//先执行push,push改变了food的值,再执行eat的时候输出food部分为apple
food = "";
},
push : function (myFood){
food = myFood;
}
}
return obj;
}
var eater1 = eater();
eater1.push("apple");
eater1.eat();
function Deng(name,wife){
var prepareWife = 'xiaozhang';
//在外部访问时deng.prepareWife显示是undefined,实现了私有化。
this.name = name;
this.wife = wife;
this.divorce = function (){
this.wife = prepareWife;
}
this.changePrepareWife = function (target){
prepareWife = target;
}
this.sayPreparewife = function (){
console.log(prepareWife);
}
}
var deng = new Deng('Deng','xiaoliu');
这个Deng执行完就被销毁了,但是Deng里面的方法被保存到了外部,手里还攥着Deng的
执行期上下文,所以就是我可以用prepareWife这个变量,但是别人访问不到,
也就实现了变量私有化
补充:对象里是可以有函数的,一个对象里是可以有方法的,一个方法也是种函数,只不过定义方法不同
Person();
(function () { //只执行一次,执行后就被立即销毁
var a = 123;
var b = 234;
console.log(a + b);
}())
(function (a,b,c) { //传递参数
console.log(a + b + c);
}(1,3,5)) //传递参数
var num = (function (a,b,c) {
var d = a + b + c + 2;
return d;
}(1,3,5))
var test = function (){
//函数表达式。test是变量名,这个函数执行完后。就被永久的放弃了,就没了
再执行test结果就是undefined,test()就是报错。
console.log('a');
}()
// 执行符号就是(),()之前的只有是表达式才能被执行符号执行,
这个例子是函数表达式,所以能被执行符号执行。还有()后面加不加;都行。
+ function test() {
//加上+(正号)号或者-(负)号或者"!"或者"与或非"或者"()"都行
不过前面得加东西符合"与或非"使用规则,加上以上就是表达式,
所以能被执行符号执行。
console.log('a');
}();
(function test(){}) //函数声明被括号包起来了,是表达式。
(function test(){
//因为test是执行完然后就被释放了,再执行就会报错,
所以函数名就可以不写了(立即执行函数的演变过程)
console.log('a');
}())
//这些括号先识别外边的,只有最外层的是数学运算小括号,
剩下的所有括号都是有语法意义的。所以最外面的括号会将里面的东西变成表达式,
表达式正好被执行符号执行。这个函数执行位置不在它定义位置。
function test(a,b,c,d){
console.log(a + b + c + d);
}(1,2,3,4);
//系统不报错也不执行,它会将前面的函数声明与后面的 (1,2,3,4)当作两个语句分开,再执行。
必须记住这个,怎么触发,怎么解决等
function test(){
//test函数中一共有两个变量,arr与i
var arr = [];
for(var i = 0; i < 10; i ++){ //不管中间怎么执行的,最后i的值就为10(i = 10才能结束循环,执行完函数)
arr[i] = function(){ //只是将函数赋给arr[i],函数中内容什么的不管,只有执行时才会考虑,所以函数中的i并不是1,2,3,4等等,不随着arr[i]变化,函数定义时不用看里面的东西,没有意义,当函数执行时再找里面的东西。
document.write(i + " "); //系统只是将一个引用抛进去了,其中内容是什么不知道,只有当执行时才会考虑i到底是什么,系统执行时就是将一个函数抛进去了,但是函数内容是什么并不知道
}
}
return arr; // arr中存放的是十个不同的相互独立的,但是长得一样的函数。
}
var myArr = test(); //这时才会真正执行那个arr[i](一共10个函数)
for(var j = 0;j < 10;j ++){
myArr[j](); //才会真正访问test作用域,并且因为所有函数都是访问一个作用域,所以访问的都是一个i值所以输出结果为10个10
}
function test (){
var arr = [];
for(var i = 0 ; i < 10; i ++){
(function (j){ //立即执行函数立即被执行,里面的语句一条一条被执行
arr[j] = function (){ //这只是赋值语句,但并不代表这个函数就要执行,就像1中一样。这个函数保存function(j)函数的成果,每个j不一样,所以各自产生的作用域不同。当执行时,arr中存的每个函数都会各自的上层的函数(即每个不同的立即执行函数)的劳动成果,每个function(j)(立即执行函数)在执行完后都会销毁(线断了),但是由于arr中函数引用
document.write( j + " "); 这个执行过程是这样的,立即执行函数执行,j=0/1/2........,然后每次执行时,找的j是每个立即执行函数中的j,一对一,每个都不一样。
}
}(i))
}
return arr;
}
var myArr = test();
for( var j = 0; j < 10; j ++){
myArr[j]();
}
for(var a = 0; a < 10; a ++){
}
console.log(a); //可以打印出a = 10;
备注:课堂中闭包精细版不是新的知识,是闭包精讲。
习题1:
frame
- a
- a
- a
- a
习题2:
frame
最终结果: 2 undefined undefined 10 100 123
习题3:题目在闭包精细版里的1小时52分钟处(就是求字节数)
frame
习题4:
var a = (1 - 1, 1 + 1); // a = 2
例1:
var f = (
function f(){
return "1";
},
function g(){
return 2;
}
)();
console.log(typeof f); //结果为number
习题5:
//所有变量未经声明就使用肯定报错,唯一一个 不报错的就是放在typeof中 并且返回undefined
var x = 1;
if(function f(){}){ //首先 function不是那六个中的,所以这个if语句判断条件是true,里面的内容肯定会执行,其次括号在这里不但判断条件时有用,括号还有自己的用途就是将里面的东西变为表达式,所以就不再有f函数了,所以函数再访问f时就已经消失了,返回字符串类型的undefined。
x += typeof f; //未经声明的变量只有放在typeof操作符中才不报错,返回undefined(字符串类型)
}
console.log(x); //若是1加上非字符串类型的undefined得到的结果为非数NaN,此题结果为1undefined