对js中一些变量操作的理解

xiaoxiao2021-02-28  10

这里主要是弄清楚函数声明和变量声明会提升(即声明提到最近作用域的开头);变量声明、形参声明和函数声明的先后关系;全局作用域和局部作用域等问题

在js中,对于函数操作变量的问题需要注意以下几点:

1、js中,函数就相当于一个作用域。

2、在js中,函数声明和变量声明都有提升的作用,即提升到离他们最近的作用域的头部。变量声明,只是将变量声明在离他最近的作用域的头部,赋值在它正真定义的地方.

3、函数需要传递参数时,参数都是值传递的形式(即在函数内部改变一般变量的值,在函数问访问该变量,变量的值还是函数外定义的值)

4、在js中,通过var声明并且连续赋值,相当于除了第一个变量外,其他变量都定义成全局变量,例如

var a=b=c=10;a为局部变量,b和c为全局变量

5、在js中,不通过var声明变量,直接给变量赋值,相当于将给变量定义成全局变量,如

a=10;

6、在一个作用域内,变量的声明顺序,变量声明 =》函数形参声明=》函数声明 ,声明是有先后顺序的

主要是理解全局变量和局部变量的区别,连续赋值的影响

代码1 var a = b = c = 10; //b和c是全局变量 (function(){ var a = b = c = 20; //重新定义变量,a局部变量,b和c全局变量,这里的b和c的值会覆盖外面b和c的值,a覆盖不了外面a的值 })(); console.log('a: '+a); //a: 10 ,访问的是外部的a的值 console.log('b: '+b); //b: 20 console.log('c: '+c); //c: 20 //代码2 var a = b = c = 10; //b和c全局变量 (function(){ a = b = c = 20; //这里相当于给a,b,c重新赋值 })(); console.log('a: '+a); //a: 20 console.log('b: '+b); //b: 20 console.log('c: '+c); //c: 20 代码3 (function(){ var a = b = c = 20; //a为局部变量,b和c为全局变量 })(); console.log('b: '+b); //b: 20 console.log('c: '+c); //c: 20 console.log('a: '+a); //ReferenceError: a is not defined 因为a为局部变量,在函数外没有声明a,所以报错 代码4 (function(){ a = b = c = 20; //a,b,c都是全局变量 })(); console.log('a: '+a); //a: 20 console.log('b: '+b); //b :20 console.log('c: '+c); //c: 20

变量声明会提升

// 代码1 var a = 10; (function(){ console.log(a); //undefined var a = 100; //变量声明会提升,即可写成代码2形式 })(); // 代码2 var a = 10; (function(){ var a; console.log(a); //undefined a = 100; })(); // 代码3 var a = 10; (function(){ console.log(a); //undefined var a =100; //a局部变量,覆盖不了外面a的值 })(); console.log(a); //10 // 代码4 var a = 10; (function(){ console.log(a); //10 a =100; //对变量a重新赋值,覆盖外面a的值 })(); console.log(a); //100

连续赋值、函数声明会提升、变量声明和函数参数声明的顺序

// 代码1 函数声明和变量声明之后的形式如代码2 a();           //1,函数声明提升 var a = c = function() { //函数表达式不会提升,在定义的地方开始执行,这里的a覆盖了函数声明中的a     console.log(2) } a();                //2   调用函数表达式中的a函数 function a() {     console.log(1) } a();                //2   调用函数表达式中的a函数 (function(b) {     b(), c();      // 2  2  b相当于a  c调用函数表达式中的c     var b = c = function a() { //函数表达式重新定义b,这里有连续赋值,这里的var预编译对c不起作用,相当于对最上面的c重新赋值         console.log(3)     }     b();        //3,调用行数表达式的b })(a); c()            //3  // 代码2 var a; function a() {     console.log(1) } a();           //1,函数声明提升 a = c = function() { //函数表达式不会提升,在定义的地方开始执行,这里的a覆盖了函数声明中的a     console.log(2) } a();                //2   调用函数表达式中的a函数 a();                //2   调用函数表达式中的a函数 (function(b) {     b(), c();      // 2  2  b相当于a  c调用函数表达式中的c     var b = c = function a() { //函数表达式重新定义b,这里有连续赋值,这里的var预编译对c不起作用,相当于对最上面的c重新赋值         console.log(3)     }     b();        //3,调用行数表达式的b })(a); c()            //3 

var A = function() {} A.prototype.n = 1; var b = new A() A.prototype = { n: 2, //重新定义A的原型链,A的原型链已经改变了,所以b和c所对应的原型对象不是一样的 m: 3 } var c = new A() console.log(b.n, b.m, c.n, c.m) //1 undefined 2 3

对比下面这个例子

var A = function() {} A.prototype.n = 1; var b = new A() A.prototype.n=2 A.prototype.m=3 var c = new A() console.log(b.n, b.m, c.n, c.m) //2 3 2 3

函数声明提升,同名时,后面覆盖前面的定义

// 代码1 (function f() {     function f() {         return 1;     }     console.log(f());  //2     function f() {         return 2;     } })(); // 代码2 (function f() {     function f() {         return 1;     }     function f() { //这里的函数会覆盖前面定义的f函数         return 2;     }     console.log(f());  //2 })();

变量声明提升,相当于在if的前面写上var a;,而整个html文档的对象是window对象,所以a是在window对象里面的一个属性,所以输出为undefined

// 代码1 变量声明提升后的形式如代码2 if (!(a in window)) {     var a = 1; } console.log(a)   //undefined // 代码2 var a; if (!(a in window)) {      a = 1; } console.log(a)   //undefined

var声明的变量名和函数名一样,函数声明和变量声明会有提升,并且有顺序:变量声明 =》 函数声明

// 代码1 函数声明和变量声明提升之后的形式如代码2 function a() {} var a; console.log(typeof a) //function 声明顺序:变量声明=》函数声明 a =10; console.log(a); //10 ,这里的a是对函数a重新赋值,最后面a的类型为number // 代码2 var a; function a() {} console.log(typeof a) //function 声明顺序:变量声明=》函数声明 a =10; console.log(a); //10 ,这里的a是对函数a重新赋值,最后面a的类型为number // 代码3 var a; function a() {} console.log(typeof a) //function 声明顺序:变量声明=》函数声明 a =10; console.log(a); //10 ,这里的a是对函数a重新赋值,最后面a的类型为number

var声明的变量和函数参数名一样,声明顺序:变量声明 =》 函数参数

// 代码1 函数声明之后的代码如2所示 (function(b) {     console.log(b)  //1     var b = c = 2     console.log(b)  //2 })(1) // 代码1 (function(b) { var b;     console.log(b)  //1     b = c = 2     console.log(b)  //2 })(1)

var声明的变量、函数参数名、函数名一样,声明顺序:变量声明 =》参数声明 =》函数声明

// 代码1 提升后的形式如2 (function(b) { console.log(b) //[Function: b] var b = c = 2 console.log(b) // 2 function b() { console.log('thie is b function'); } console.log(b) //2 })(1) // 代码2 (function(b) { var b; b = b; //右边的b相当于1,左边的b=1 function b() { console.log('thie is b function'); } console.log(b) //[Function: b] b = c = 2; console.log(b) // 2 console.log(b) //2 })(1)

传参和不传参的区别

// 代码1 var a = 1 function c(a, b) {     console.log(a)      //undefined,因为c()执行的时候,并没有传参,函数中的形参值为undefined     a = 2     console.log(a)     //2 } c() //代码2 var a = 1 function c(a, b) {     console.log(a)      //undefined,因为c()执行的时候,并没有传参,函数中的形参值为undefined     a = 2     console.log(a)     //2,这里的a是局部变量,不能影响到全局的同名的变量的值 } c() console.log(a)   //1 // 代码3 var a = 1 function c(a, b) {     console.log(a)    //1 //c(1)传进来一个参数1,作为a的值     a = 2     console.log(a)    //2 } c(1)

函数声明提升,同名,则后面的覆盖前面的

// 代码1 函数声明提升后的形式如代码2 function fn(){     function a(){console.log(1)}     return a;     function a(){console.log(2)} } fn()();//2 // 代码2 function fn(){     function a(){console.log(1)}     function a(){console.log(2)}     return a; } fn()();//2

变量声明提升

// 代码1 提升后的形式如代码2 var a=10; function fn(){     //变量声明提升,a 赋值undefined,内部作用域存在a这个变量,所以这里 !a 就是  !undefined,就是true,进入函数a=20;     //但是后面的a怎么就是20呢,js没有块级作用域!! 不要小看js各种细节,够折腾的     if (!a) {         var a=20     }     console.log(a)//  这里是20 , } fn() //20 // 代码2 var a=10; function fn(){     //变量声明提升,a 赋值undefined,内部作用域存在a这个变量,所以这里 !a 就是  !undefined,就是true,进入函数a=20;     //但是后面的a怎么就是20呢,js没有块级作用域!! 不要小看js各种细节,够折腾的     var a;     if (!a) {         a=20;     }     console.log(a)//  这里是20 , } fn() //20

如果将上面的改成

var a=10; function fn(){ if (!a) { a=20 } console.log(a)// 这里是10 , } fn() //10

理解逗号运算符,从左到右计算,返回最右边的结果

// 1 function count(){ return 1,2,3; } console.log(count()); //3 // 2 function count(){ return (1,2,3); } console.log(count()); //3 // 3 function count(){ return (1+1,2+3,3+1); } console.log(count()); //4

理解this的作用域;this始终指向程序当前正在使用的对象,this仅用于函数内

全局函数中的this:始终指向window对象

对象中的this:始终指向调用该方法的对象、

构造函数中的this:指向刚创建的新对象

全局函数中的this:始终指向window对象

// 代码1 // 全局方法中的this指向window var a=100; function fun(){ console.log(this.a);//window.a 100 } fun(); // 代码2 var n=100; function fun1(n){ // 函数传递的参数都是值传递的方式 n=10; //这里的赋值,只是对传递进来的参数进行赋值,并不影响外面的n的值 console.log(this.n);// this.n=window.n 100 } fun1(n); // 代码3 var n=100; function fun1(n){ n++; // 同上解释 console.log(this.n); // this.n=window.n 100 } fun1(n); //100 // 代码4 var n=100; function fun1(n){ this.n++; // this.n=window.n console.log(this.n);//this.n=window.n 101 } fun1(n); 对象中的this:始终指向调用该方法的对象 // 代码1 var name="li ming"; var hmm ={ name:"zhang san", show:function(){ console.log(this);//this=hmm这个对象,输出{name: "zhang san", show: ƒ} } }; hmm.show(); //{name: "zhang san", show: ƒ} // 代码2 var name="li ming"; var hmm={ name:"zhang san", show:function(){ console.log(this.name);//this.name = hmm.name,zhang san } }; hmm.show();//zhang san // 代码3 var a=10; var foo={ a:20, bar:function(){ var a=30; return this.a; //this.a=foo.a,20 } } console.log(foo.bar()); //20 构造函数中的this:指向刚创建的新对象 function Student(name){ this.name=name; console.log(this); //this指向 new正在创建的对象 Student } var name1 = new Student("zhang san"); //Student {name: "zhang san"} var name2 = new Student("li si"); //Student {name: "li si"} var name="liming"; function Student(name){ this.name = name; console.log(this.name); //this指向 new正在创建的对象 Student } var name1 = new Student("zhang san"); //zhang san var name2 = new Student("li si"); //li si

理解下面这栗子

var a=10; var foo = { a: 20, //全局属性 bar: function () { var a = 30; //局部变量,覆盖不了外面的a的值 return this.a; //this指向调用该方法的对象 } }; console.log( foo.bar(), // 20,foo调用bar函数,this指向foo,foo有一 //个对象a,所以this.a = foo.a (foo.bar)(), // 20,foo.bar是匿名函数,用()调用该匿名函数 //,this指向这个匿名函数,但这个匿名函数仅限 //于foo里面的全局变量使用,此时this.a就是foo.a (foo.bar = foo.bar)(), // 10 这里有'='赋值符号,赋值符号会改变this的指向,把右边的匿名函数重新赋值给左边的foo.bar,此时foo.bar整体相当于一个全局 变量,在用()调用,this指向全局的a,可以理解成var b= foo.bar;b() (foo.bar, foo.bar)() // 10,逗号运算符,从左往右执行,返回最右边结果,同'=',会改变this的作用域,不太明白 );

代码1和代码2的区别,只是1中多了个与变量名同名的函数,由于函数声明会提升,所以函数a()的声明会在函数b()的最前面,然后才是给这个函数,重新赋值为10,在函数b()外面是访问不到b()里面定义的a

// 代码1 var a = 1; function b(){ a = 10; return; function a(){ //函数声明会提升到b()的开头,提升后的代码形式如代码2 console.log(a); } } b(); console.log(a); // 1 // 代码2 var a = 1; function b(){ function a(){ console.log(a); } a = 10; //这里对a的赋值,其实是对b()函数里面声明的a赋值, //因为,在执行赋值语句的时候,会由里向外查找,在 //函数b()里面找到a,所以就停止向函数b()外查找a,这里的a就相当于一个局部变量,函数b()外不能访问到该a return; } b(); console.log(a); // 1,这里只能访问到函数b()外的a // 代码3 var a = 1; function b(){ a = 10; //在执行b()的时候,会由里向外查找a,结果在b()外找到a //,所以这里是对函数b()外的a重新赋值 return; // function a(){ //去掉函数a // console.log(a); // } } b(); console.log(a); //10

还是理解全局变量和局部变量

// 代码1 var a=b = 10; //b全局变量 (function(){ var b = 20; //重新定义一个b,b为局部变量,覆盖不了外面的b的值 })(); console.log(a); //10 console.log(b); //10 访问外部的b的值 // 代码2 var a=b = 10; //b全局变量 (function(){ b = 20; //对b重新赋值 })(); console.log(a); //10 console.log(b); //20 // 代码3 var b = 10; (function(){ var a=b = 20; //a局部变量,b全局变量,这个b的值会覆盖外面b的值 })(); console.log(b); //20 console.log(a); //报错 ReferenceError: a is not defined // 代码4 var a = 10; var b =10; (function(){ var a=20 //a b为局部变量,覆盖不了外面的a,b的值 var b = 20; })(); console.log(b); //10 这里a和b都访问外部定义的值 console.log(a); //10

连续执行

function fun(n,o){ console.log(o); return { fun:function(m){ return fun(m,n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3); var b = fun(0).fun(1).fun(2).fun(3); var c = fun(0).fun(1); c.fun(2); c.fun(3); //问:三行a,b,c的输出分别是什么? var a = fun(0); a.fun(1); a.fun(2); a.fun(3); //undefined 0 0 0 var b = fun(0).fun(1).fun(2).fun(3); //undefined 0 1 2 var c = fun(0).fun(1); c.fun(2); c.fun(3); //undefined 0 1 1

理解js对象中的私有属性、公有属性、静态属性,this指向,函数声明和变量声明提升,运算符优先级

<!DOCTYPE html> <html lang="en"> <body> <script type="text/javascript"> var getName; function Foo (){       getName = function (){        console.log(1);       };       return this;   }   function getName (){   console.log(5);   };     Foo.getName = function (){   console.log(2);   };      Foo.prototype.getName = function () {   console.log(3);   };      getName = function (){   console.log(4);   };        Foo.getName();   //2 getName();   //4 Foo().getName();   //1 getName();   //1 new Foo.getName();  //2 new Foo().getName();  //3 new new Foo().getName(); //3 </script> </body> </html> 详细解答链接 仅供参考

更多题型

转载请注明原文地址: https://www.6miu.com/read-1900003.html

最新回复(0)