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

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

在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>

你可能感兴趣的:(JavaScript,javascript)