`

javascript的动态this与动态绑定

阅读更多
javascript是一门动态语言,最明显就是那个dynamic this。它一般都是作为函数调用者存在。在javascript,所有关系都可以作为对象的一个关联数组元素而存在。那么函数就是被掰成两部分储存于对象,一是其函数名(键),一是函数体(值),那么函数中的this一般都指向函数所在的对象。但这是一般而已,在全局调用函数时,我们并没有看到调用者,或者这时就是window。不过,函数声明后,其实并没有绑定到任何对象,因此我们可以用call apply这些方法设置调用者。
一个简单的例子:
window.name = "window";
var run = function() {
  alert("My name is " + this.name);
}
run();

运行代码
这里你不能说run是作为window的一个属性而存在,但它的确是被window属性调用了。实质上大多数暴露在最上层的东西都则window接管了。在它们需要调用时被拷贝到window这个对象上(不过在IE中window并不继承对象),于是有了window['xxx']与window.xxx性能上的差异。这是内部实现,不深究了。
另一个例子,绑定到一个明确的对象上
window.name = "window";
object = {
  name: "object",
  run: function() {
    alert("My name is " + this.name);
  }
};
object.run();

运行代码
答案显然易见,this总是为它的调用者。但如果复杂一点呢?
window.name = "window";
object = {
   name: "object",
   run: function() {
     var inner = function(){
       alert("My name is " + this.name);
     }
     inner();
   }
};
object.run();

运行代码
尽管它是定义在object内部,尽管它是定义run函数内部,但它弹出的既不是object也不是run,因为它既不是object的属性也不是run的属性。它松散在存在于run的作用域用,不能被前两者调用,就只有被window拯救。window等原生对象浸透于在所有脚本的内部,无孔不入,只要哪里需要到它做贡献的地方,它都义不容辞。但通常我们不需要它来帮倒忙,这就需要奠出call与apply两大利器了。
window.name = "window";
var object = {
  name: "object",
  run: function() {
    inner = function() {
     alert( this.name);
    }
    inner.call(this);
  }
}

object.run();

运行代码
call与apply的区别在于第一个参数以后的参数的形式,call是一个个,aplly则都放到一个数组上,在参数不明确的情况,我们可以借助arguments与Array.slice轻松搞定。
window.name = "Window";

var cat = {
  name: "Cat"
};
var dog = {
  name: "Dog",
  sound: function(word) {
    alert(this.name + word);
  }
};

dog.sound(" is pooping");
dog.sound.call(window, " is banking");
dog.sound.call(dog, " is banking");
dog.sound.apply(cat, [" miaowing"]);

运行代码
由此Prototype开发者搞了一个非常有名的函数出来,bind!以下是它的一个最简单的版本:
var bind = function(context, fn) {
  return function() {
    return fn.apply(context, arguments);
  }
}

运行代码
不过为了面对更复杂的情况建议用以下版本。
function bind(context,fn) {
  var args = Array.prototype.slice.call(arguments, 2);
  return args.length == 0 ? function() {
    return fn.apply(context, arguments);
  } : function() {
    return fn.apply(context, args.concat.apply(args, arguments));
  };
};
它还有一个孪生兄弟叫bindAsEventListener ,绑定事件对象,没什么好说的。
var bindAsEventListener = function(context, fn) {
    return function(e) {
        return fn.call(context, (e|| window.event));
    }
}
Prototype的版本
Function.prototype.bind = function() {
   if (arguments.length < 2 && (typeof arguments[0]==='undefined'))
     return this;
   var _slice = Array.prototype.slice
   var __method = this, args = _slice.call(arguments,0), context = args.shift();
   return function() {
     return __method.apply(context, args.concat(_slice.call(arguments,0)));
   }
}

运行代码
bind函数是如此有用,google早早已把它加入到Function的原型中了(此外还有inherits,mixin与partial)。

运行代码
有绑定就有反绑定,或者叫剥离更好!例如原生对象的泛化方法我们是无法通过遍历取出它们的。
for(var i in Array){
  alert(i + " : "+ Array[i])
}
for(var i in Array.prototype){
  alert(i + " : "+ Array.prototype[i])
}

运行代码
要取出它们就需要这个东西:
var _slice = Array.prototype.slice;
function unbind(fn) {//第一步取得泛化方法
  return function(context) {//第二部用对应原生对象去重新调用!
    return fn.apply(context, _slice.call(arguments, 1));
  };
};
示例以前也给过了,请见这里
总结:
this 的值取决于 function 被调用的方式,一共有四种,
如果一个 function 是一个对象的属性,该 funtion 被调用的时候,this 的值是这个对象。如果 function 调用的表达式包含句点(.)或是 [],this 的值是句点(.)或是 [] 之前的对象。如myObj.func 和myObj["func"] 中,func 被调用时的 this 是myObj。
如果一个 function 不是作为一个对象的属性,那么该 function 被调用的时候,this 的值是全局对象。当一个 function 中包含内部 function 的时候,如果不理解 this 的正确含义,很容易造成错误。这是由于内部 function 的 this 值与它外部的 function 的 this 值是不一样的。解决办法是将外部 function 的 this 值保存在一个变量中,在内部 function 中使用它来查找变量。
如果在一个 function 之前使用 new 的话,会创建一个新的对象,该 funtion 也会被调用,而 this 的值是新创建的那个对象。如function User(name) {this.name = name}; var user1 = new User("Alex"); 中,通过调用new User("Alex") ,会创建一个新的对象,以user1 来引用,User 这个 function 也会被调用,会在user1 这个对象中设置名为name 的属性,其值是Alex 。
可以通过 function 的 apply 和 call 方法来指定它被调用的时候的 this 的值。 apply 和 call 的第一个参数都是要指定的 this 的值。由于它们存在,我们得以创建各种有用的函数。
分享到:
评论

相关推荐

    复习JavaScript中this指向及绑定

    复习JavaScript中this指向及绑定

    javascript下动态this与动态绑定实例代码

    不过,函数声明后,其实并没有绑定到任何对象,因此我们可以用call apply这些方法设置调用者。 一个简单的例子: [script] [removed] window.name = “window”; var run = function() { alert&#40;“My name is ” ...

    JavaScript高级-this绑定规则+箭头函数

    JavaScriptthis绑定规则以及箭头函数相关知识,以便于讨论学习

    【JavaScript源代码】vue 中this.$set 动态绑定数据的案例讲解.docx

    vue 中this.$set 动态绑定数据的案例讲解  感觉网上对this.$set的讲解乱糟糟的,我来总结一下对它单个数据、对象、数组、json数据的绑定. 话不多说直接上代码: &lt;template&gt; &lt;div&gt; &lt;!-- 单个数据 --&gt; ...

    Javascript中this绑定的3种方法与比较

    大家都知道JS是一门动态语言,与传统的c和c++最大的区别就是js是在运行时动态检测值的类型和变化。this是js中的一个关键字,它代表当前作用域的...这篇文章我们将详细介绍Javascript中绑定this的三种方法与简单的比较。

    【JavaScript源代码】JavaScript函数this指向问题详解.docx

    JavaScript函数this指向问题详解  目录 一、 函数内 this 的指向1、普通函数2、构造函数3、对象方法4、事件绑定方法5、定时器函数6、立即执行函数二、改变函数内部 this 指向1、call 方法2、apply 方法3、bind ...

    简单谈谈javascript中this的隐式绑定

    在JavaScript中,this 的概念比较复杂。除了在面向对象编程中,this 还是随处可用的。这篇文章介绍了this的隐式绑定,希望大家能够喜欢。

    JavaScript中this的四个绑定规则总结

    独立函数调用时,this 指向全局对象,如果使用严格模式,那么全局对象无法使用默认绑定, this绑定至 undefined。 function foo() { console.log(this.a); } var a = 2; foo(); // 2 严格模式时: function foo()...

    JavaScript给按钮绑定点击事件(onclick)的方法

    本文实例讲述了JavaScript给按钮绑定点击事件(onclick)的方法。分享给大家供大家参考。具体分析如下: 我们可以通过设定按钮的onclick属性来给按钮绑定onclick事件 ...&lt;p id=demo&gt;This is a paragraph.&lt;/

    Javascript的this详解

    在理解javascript的this之前,首先先了解一下作用域。 作用域分为两种: 1、词法作用域:引擎在当前作用域或者嵌套的子作用域查找具有名称标识符的变量。(引擎如何查找和在哪查找。定义过程发生在代码书写阶段) ...

    JavaScript this绑定过程深入详解

    主要介绍了JavaScript this绑定过程,结合实例形式深入分析了JavaScript中this关键字的功能、原理、绑定方式及相关操作注意事项,需要的朋友可以参考下

    JavaScript调用模式与this关键字绑定的关系

    实参与形参不一致不会导致运行时错误,多的被忽略,少的补为undefined 每个方法都会收到两个附加参数:this和arguments。this的值取决于调用的模式,调用模式:方法,函数,构造器和apply调用模式 this被赋值发生在...

    JavaScript Dom 绑定事件操作实例详解

    本文实例讲述了JavaScript Dom 绑定事件操作JavaScript Dom 绑定事件操作。分享给大家供大家参考,具体如下: JavaScript Dom 绑定事件 // 先获取Dom对象,然后进行绑定 document.getElementById('xx').onclick ...

    Javascript中的this绑定介绍

    * 函数调用模式:this被绑定到全局对象,网页的情况下绑定到window * 构造器调用模式:this被绑定到新生成的对象。 * 事件处理调用模式分两种情况:参照 * this被绑定到全局对象 代码如下: [removed] function ...

    javascript中的this绑定

    1. 默认绑定:没有明确被隶属对象执行的函数,this指向window function fn(){ console.log(this); //window console.log(typeof this); //object } fn(); – 严格模式下,this指向undefiend use strict; ...

    详细讲解JavaScript中的this绑定

    this 可以说是 javascript 中最耐人寻味的一个特性,就像高中英语里各种时态,比如被动时态,过去时,现在时,过去进行时一样,无论弄错过多少次,下一次依然可能弄错。本文启发于《你不知道的JavaScript上卷》,对 ...

Global site tag (gtag.js) - Google Analytics