js-this作用域

js-this作用域

2014-5-7

this作用域以前专门学习研究过,但发现依然不够全面和完整。现在继续学习

先列出之前看过的结论:

函数在被调用的时候会意外接受两个参数:this和argument,其中this的值跟取决于函数的调用模式

1,方法调用模式 o.a() //this指的o

2,函数调用模式 a() //this指的windows

3,构造器调用模式 new a() //this为a的实例对象

4,apply(call)的间接调用模式 a.apply(xx,[yy]) //this指的xx

但是,上面的描述并没有指出背后的联系,换一种描述方式:

在这里列出this在ECMAScript中的不同含义:

(1) 在全局执行环境中使用this,表示Global对象,在浏览器中就是window对象。

(2)
当在函数执行环境中使用this时,情况就有些复杂了。如果函数没有明显的作为非window对象的属性,而只是定义了函数,不管这个函数是不是定义在另
一个函数中,这个函数中的this仍然表示window对象。如果函数显示地作为一个非window对象的属性,那么函数中的this就代表这个对象。
(当然可以使用apply或者call函数来取代默认this的引用,详见[P88])

(3) 当通过new运算符来调用函数时,函数被当做一个构造函数,this指向构造函数创建出来的对象。

参考:

《JavaScript基础与案例开发详解》清华大学出版社

定义一个函数,在不同的作用域中调用时this指代不同

当this使用在函数代码中事情就变得有趣多了。这种情况是最难的也会引发很多的问题。在函数代码中,this值的第一(可能也是最重要的)特性
就是不能
静态的绑定到一个函数上。正如上面已经提到的,this值在进入上下文时就已经被决定了,在函数代码的情形下,每次this值可以是完全不一样的。

然而,在代码运行时,this值是不可改变的。例如,不能给this赋一个新值,因为this不是变量(相反,python编程语言中,可以显式的定义self对象,在运行的时候self对象可重复改变)

Js代码  

  1. var foo={x:10};
  2. var bar={
  3. x:20,
  4. test:function(){
  5. console.log(this===bar);//true
  6. console.log(this.x);//20
  7. //this=foo;//error,不能改变this值
  8. }
  9. };
  10. //当进入上下文时,this值由"bar"对象决定的。为什么这样-将在下面详细讨论
  11. bar.test();//true,20
  12. foo.test=bar.test;
  13. //然而,此时在这里的this将指向"foo"-即使我们调用同一个函数
  14. foo.test();//false,10

(当我们在一些关于javascript
的文章和书本中会看到“this值由函数如何定义来决定:如果是全局函数,this值被设置为全局对象,如果函数时一个对象的方法,this值设置为这个
对象”-这是一个错误的描述)。从下面我们可以看出即使是一般的全局函数,也能够被产生不同this值的调用表达式所触发。

Js代码  

  1. function foo(){
  2. console.log(this);
  3. }
  4. foo();//打印this为Window
  5. console.log(foo===foo.prototype.constructor);//true
  6. //但是对于同一函数的另一种调用表达式形式,this值是不同的
  7. foo.prototype.constructor();//打印this为foo
  8. 调用一个被定义为对象方法的函数,但是this值不会被设置为这个对象也是同样可能的:
  9. var foo={
  10. bar:function(){
  11. console.log(this);
  12. console.log(this===foo);
  13. }
  14. };
  15. foo.bar();//foo,true
  16. var exampleFunc=foo.bar;
  17. console.log(exampleFunc===foo.bar);//true
  18. //同一函数的另一种调用表达式形式,得到不同的this值
  19. exampleFunc();//global,false

2013-09-10

最近看到一句话说,js中的对象其实就是一些hash映射。简单说就是名值对,只不过这些名字对同用一个上下文(context)this。

Js代码  

  1. var obj = {
  2. fun1 : function(){
  3. },
  4. fun2 : function(){
  5. //在使用fun1时,像使用自己的变量一样
  6. var local = this.fun1();//如果有参数,还可以传递参数
  7. },
  8. fun3 : function(){
  9. },
  10. };

2013-8-27

this关键字

每一个方法或函数都会有一个this对象,this对象是方法(或函数)在执行时的那个环境,也可以说是这个函数在那个作用域下运行的。

说的更通俗一点:this就相当于咱们平时说话时候说的“我”,“我家”的概念。就是说当一个方法在运行的时候,它是属于谁的。它在运行的时候它的家是谁家。

this的概念比较抽象,是讲课的时候的难点也是重点。

关于this的具体表示那个对象,和函数的运行方式(或调用方式)有关。

在JavaScript中一共有四种调用模式:

方法调用模式(对象属性模式)、

函数调用模式(就是普通的函数执行)、

构造调用模式(应该叫实例上的方法模式更好)

和apply调用模式。

一、当它为一个对象上的方法的时候,this是当前这个对象

方法调用模式(或称:对象属性模式)

先了解一个概念:方法和函数的区别。方法和函数本质一样,形式不同而已。看下例:

Js代码  

  1. function fn(){
  2. alert(this)
  3. }

这样就是定义了一个函数,当:fn()的时候,叫这个函数运行。同样是上面这个fn函数,如果把它赋值给一个对象的属性,就成了方法了,看下面的例子。

Js代码  

  1. var obj=new Object();//先定义一个对象obj
  2. obj.objFn=fn;

那现在的obj.objFn就是方法了,但其实objFn和fn指向的是同一个内存地址。但fn是直接定义的,就是函数,而objFn是obj这个对象上的一个属性,则objFn就是方法了。方法和函数本质上是一样的,只是在不同的情况下的叫法不同。

但当fn运行的时候,弹出的是window(任何函数被调用,this都表示window);而objFn运行的时候,弹出的是object,因
为当它做为一个方法运行的时候,this关键字表示的是objFn这个属性所属的这个对象obj。也就是说,在这种情况下,this表示obj。

再啰嗦一遍:当函数成为一个对象的属性的值的时候,这个函数里的this指向当前这个对象(这时候函数就变成了方法)

再啰嗦第三遍:当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。方法可以使用this去访问对
象,所以它能从对象中取值或修改对象。this到对象的绑定发生在调用的时候。这个“超级”迟绑定使得函数可以对this高度复用。通过this可取得它
们所属对象的上下文的方法称为公共方法。

二、函数调用模式

当函数并非一个对象的属性时,那么它被当做一个函数来调用。此模式下this绑定到全局对象。通过在对象内将this赋值给that,可以使函数模式下调用that来访问指定对象。

(就是上面解释的函数方式)

三、类的实例上的方法中的this指向当前的实例

例如:

Js代码  

  1. function Person(){
  2. }
  3. Person.prototype.cry=function (){alert(this)}
  4. var rose=new Person();
  5. rose.cry();//现在这个cry就被称做方法,这个方法里的this就表示rose这个实例。

详细的讲解,请见《面向对象和设计模式》的课堂讲解和视频

四、使用call和apply方法强制改变this关键字

(附在面向对象一章的讲解里)

测试题:

题目一:

Js代码  

  1. var name = "The Window";
  2.   var object = {
  3.     name : "My Object",
  4.     getNameFunc : function(){
  5.       return function(){
  6.         return this.name;
  7.      };
  8.     }
  9. };
  10. alert(object.getNameFunc()()); //The Window

解析:object.getNameFunc后面跟了两对括号。先运行object.getNameFunc(),这个方法运行后返回了一个函数,就是这个方法里面定义的那个匿名函数,然后再让这个匿名函数运行。

可以分解成以下步骤:

Js代码  

  1. var fn= object.getNameFunc();//object.getNameFunc这个方法里的this是表示object这个对象,但它返回的是一个函数,返回的这个函数里的这个this则表示window了
  2. fn();//当返回的这个函数运行的时候,this表示是window这个对象

和上一题目类似的题:

Js代码  

  1. function a(){
  2. alert(this);
  3. }
  4. var arr = [1,2,3];
  5. arr.f = a;
  6. arr.f();//会输出什么

解析:把a函数赋给arr的属性f,则f就成为arr这个对象上的方法了,它运行的时候就表示arr这个数组对象。

如果直接这样:a();  则这时候的this表示的是window这个对象

时间: 2024-10-26 14:26:01

js-this作用域的相关文章

js 的作用域

js的作用域 一. 方式1.常用方式: function test (参数) { ………….方法的实现……………….. }这种方式的函数声明的先后位置与调用无关,可以在调用的前面声明,也可以在调用的后面声明;2.匿名函数: 把方法赋给一个变量,此时这个变量是一种方法类的变量;Var a = function (参数) {………..方法的实现……………………}这种方式的函数声明必须放在调用的前面;匿名函数直接调用的方式,例如: alert(function () {} 二. 参数的管理:每一个函数

浅谈 js eval作用域

就简单聊下如何全局 eval 一个代码. var x = 1; (function () { eval('var x = 123;'); })(); console.log(x); 这个代码得到的是 1 而不是 123如果想让 eval 执行的代码是全局的,那么有几种方法. var x = 1; (function () { window.eval('var x = 123;'); })(); console.log(x); 这个方法标准浏览器都可以得到 123 而IE6-8则依然是 1 相同的

js变量作用域--变量提升

1.JS作用域 在ES5中,js只有两种形式的作用域:全局作用域和函数作用域,在ES6中,新增了一个块级作用域(最近的大括号涵盖的范围),但是仅限于let方式申明的变量. 2.变量声明 1 var x; //变量声明 2 var x=1; //变量声明并赋值 3 x = 1; // 定义全局变量并赋值 3.函数声明 function fn(){}; //函数声明并定义 var fn = function(){}; // 实际上是定义了一个局部变量fn和一个匿名函数,然后把这个匿名函数赋值给了fn

js变量作用域

? 1 2 3 4 5 6 7 8 9 10 for(var i =0;i<100;i++)   {        } alert(i);//100 if(true){     var i="91d";   } alert(i);//91d ? 1 2 3 4 5 6 function add(ad1,ad2){   sum=ad1+ad2;   return sum;//如果没有用var声明局部变量,会提升为全局的变量 } alert(add(3,5)); alert(&quo

简述JS的作用域和闭包

作用域:它是指对某一变量和方法具有访问权限的代码空间, 在JS中, 作用域是在函数中维护的.表示变量或函数起作用的区域,指代了它们在什么样的上下文中执行,亦即上下文执行环境.Javascript的作用域只有两种:全局作用域和本地作用域,本地作用域是按照函数来区分的. 闭包:在js中的我的理解就是函数嵌套函数,当内部函数在定义它的作用域的外部被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们. 作用域的嵌套

js私有作用域(function(){})(); 模仿块级作用域

摘自:http://outofmemory.cn/wr/?u=http%3A%2F%2Fwww.phpvar.com%2Farchives%2F3033.html js没有块级作用域,简单的例子: for(var i=0;i<10;i++){ alert(i); } alert(i); for循环后的i,在其它语言像c.Java中,会在for结束后被销毁,但js在后续的操作中仍然能访问到i值,即for循环后的alert(i);会弹出数值i=10; js模仿块级作用域: (function(){

JS 之作用域链和闭包

1.JS无块级作用域 <script> function Main(){ if (1==1){ var name = "alex"; } console.log(name); } Main(); </script>执行结果:{}即块级作用域. alex 2.JS采用函数作为作用域链 <script> function Main(){ var innerValue = "alex"; } Main(); console.log(in

js静态作用域与this绑定

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title></head><body> <h1>js静态作用域与this绑定</h1> </body><script type="text/javascript&qu

JS中作用域和变量提升(hoisting)的深入理解

作用域(Scoping) javascript作用域之所以迷惑,是因为它程序语法本身长的像C家族的语言.我对作用域的理解是只会对某个范围产生作用,而不会对外产生影响的封闭空间.在这样的一些空间里,外部不能访问内部变量,但内部可以访问外部变量. c语言的变量分为全局变量和局部变量,全局变量的作用范围是任何文件和函数访问(当然,对于非变量定义的其他c文件,需要使用extern关键字进行申明,使用static关键字也可以将作用范围限定在当前文件中),局部变量的作用范围就是从申明到最近的大括号涵盖的块级

js中作用域链的问题

为什么没有var声明的变量是全局的? 是因为,在js中,如果某个变量没有var声明,会自动到上一层作用域中去找这个变量的声明语句,如果找到,就使用,如果没有找到,继续向上查找,一直查找到全局作用域为止,如果全局中仍然没有这个变量的声明语句,那么会自动在全局作用域进行声明,这个就是js中的作用域链 <script> var i = 10; function f1() { //第一层 i = 20; function f2() { //第二层 i = 30; function f3() { //第