JavaScript作用域
其他语言:以{}代码块作为作用域
python:以函数作为作用域
JavaScript:以函数作为作用域
函数的作用域在函数未被调用之前,已经创建
函数的作用域存在作用域链(一层包一层的函数形成作用域链),并且也是在被调用之前创建。
- 作用域相关
1. function func(){ if(1==1){ var v= 123; } console.log(v); } func()
运行结果为:123
2. xo = 'root1'; function func(){ var xo = 'root2'; function inner(){ console.log(xo); } inner(); } func(); // 作用域链 // root2
运行结果:root2
3. xo = 'root1'; function func(){ var xo = 'root2'; function inner(){ console.log(xo); } return inner; } result = func(); result(); // 作用域链在函数调用之前已经创建,当寻找变量时,根据最开始创建的作用域查找 // root2
运行结果:root2
4. xo = 'root1'; function func(){ var xo = 'root2'; function inner(){ console.log(xo); } xo = 'root3' // 编译函数时,xo最后的值为'root3',调用inner函数时,找到xo的值为'root3' return inner; } result = func(); result();
运行结果:root3
5. var xxxx; console.log(xxxx); function func(){ console.log(xo); var xo = '123'; console.log(xo); } func() // 函数内局部变量提前声明(预编译),JavaScript 1. 预编译: var xo 这里的xo是undefined; 2. 执行
运行结果:undefined;123
6. function func(num){ console.log(num); num = 18; console.log(num); function num(){ } console.log(num); } func(666); a. 预编译 AO(活动对象) 先编译参数: AO.num = undefined //编译形参 AO.num = 666 //编译实参 再编译变量: 如果AO中有num,则不做任何操作 否则 AO.num = undefined 最后编译函数: AO.num = function num(){ } b. 执行
以上代码执行结果:
666 18 function num(){ }
7. function func(num){ console.log(num); function num(){ } console.log(num); num = 18; console.log(num); } func(666); 先编译参数: AO.num = undefined AO.num = 666 再编译变量: 如果AO中有num,则不做任何操作 否则 AO.num = undefined 最后编译函数: AO.num = function num(){ }
以上代码执行结果:
function num(){ } function num(){ } 18
8. function func(){ console.log(xo); var xo = 123; } func() 编译: 参数: AO 变量: AO.xo = undefined 执行:
- 函数和面向对象相关
1. function func(arg){ console.log(this,arg); } func(18); // func.call(window,20); // func.apply(window,[30]); (function(arg){ console.log(this,arg); })(123) 在函数被执行时,默认this是代指window对象 function func(){ window.nn = 'root'; //nn = 'root'; this.nn = 'root'; } func() console.log(nn); =====> a. 在函数内部,默认都有this变量。默认情况下,执行函数时 this=window b. 使用 函数名.call 或者 函数名.apply 可以对函数中的this主动设置值 document.getElementById('id').onclick = function(){ // this } document.getElementById('id').onclick.call(DOM对象)
2. 在JS中没有字典类型
只有对象伪造成字典形式 var dict = { name: 'alex', age: 18 } 等价于 var dict = new Object(); # 表示创建空字典 dict.name = 'alex'; dict.age = 18; function Foo(name){ this.Name = name } Foo('root') # 当做函数时,this默认是window var dict1 = new Foo('root1') # 当做类时,this是 dict1 同pyself // Foo.call(dict1,'root1') var dict2 = new Foo('root2') # 当做类时,this是 dict2 ==== function Foo(name){ this.Name = name; this.Func = function(){ console.log(this.Name); } } # 当做函数 Foo('root1') window.Name window.Func() # 当做类 obj = new Foo('root2') obj.Name obj.Func() # 直接对象 dict = { Name: 'root3', Func: function(){ console.log(this.Name); } } # dict = new Object(); # dict.Name = 'root3'; # dict.Func = function(){ console.log(this.Name); } dict.Func() ==========================》 谁调用函数,this就是谁。 函数()执行时候默认window.函数() 谁调用函数,this就是谁。 函数()执行时候默认window.函数() 每一个函数里都有一个this Name = '666'; var dict = { Name: 'root', Age: 18, Func: function(){ // this等于dict console.log(this.Name); // root function inner(){ console.log(this.Name); // 666 } window.inner(); } } dict.Func(); ============================ 谁调用函数,this就是谁。 函数()执行时候默认window.函数() 每一个函数里都有一个this 变量查找顺序,作用域链 Name = '666'; var dict = { Name: 'root', Age: 18, Func: function(){ // this等于dict console.log(this.Name); // root // that 等于dict var that = this; function inner(){ // this=window console.log(that.Name); // root } window.inner(); } } dict.Func();
3. 原型
方式一:创建多个对象时,创建了多个this.Func,浪费了内存。
function Foo() { this.name = name; this.Func = function () { console.log(this.name); } }
方式二:原型,创建多个对象时,只会创建一个this.Func
function Foo(name){ this.Name = name; } // 原型 Foo.prototype = { Func: function(){ console.log(this.Name); } } obj1 = new Foo(1)
obj1.Func() obj2 = new Foo(2) obj3 = new Foo(3)