一、this指向问题

1)默认绑定,即作为独立的普通函数调用

  此时this指向全局对象window,如果是严格模式下,则指向undefined;  

2)隐式绑定,即具有调用上下文(一种场景就是作为对象的属性调用)

  隐式绑定会将this绑定到这个上下文对象,如obj.getA();this就指向.之前的函数调用者;对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。如obj1.obj2.foo(),调用时this指向obj2;

  隐式绑定常见的问题就是隐式绑定的函数会丢失绑定对象。这点在第二部分会详细介绍。

3)显式绑定,

  通过call/apply指定上下文对象。事实上ES5提供了内置方法Function.prototype.bind,也可以达到类似的效果。  

4)new构造调用

  事实上javascript中并不存在所谓的“构造函数”,只有对函数的“构造调用”。在javascript中,构造函数只是一些使用new操作符时被调用的普通函数,它们不会属于某个类,也不会实例化一个类。当使用new运算符调用函数时,该函数会返回一个对象,构造器中的this就指向返回的这个对象;需要注意的是,如果构造器显式返回了一个object类型的对象,那么此次运算结果最终会返回这个对象,构造器中的this也会指向这个对象,而非我们期望的this;

下面是自己实现的new(没有考虑构造函数待参数的情况,如果需要考虑,加一个参数即可)

    var myNew = function(func) {
var o = Object.create(func.prototype);
var k = func.call(o);
if (typeof k === 'object') {
return k;
} else {
return o;
}
}

5)this绑定的优先级:

  a:函数是否在new中调用?如果是的话this绑定的是新创建的对象;

  b:函数是否通过call,apply显示绑定?如果是的话,this绑定的是指定的对象;

  c:函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是指定的对象;

  d:如果都不是得花,使用默认绑定,在非严格模式下,绑定到全局对象window;在严格模式下绑定到undefined.

  

二、隐式绑定中的this丢失问题

思考下面一个问题,在prototype.js等框架中,做过这样的事情:

        var getId=function(id){
return document.getElementById(id);
}
var oDiv=getId('div1');

思考为什么不用下面更简单的方式:

        var getId=document.getElementById;
var oDiv=getId('div1');

后者会抛出一个异常,这是因为许多引擎的document.getElementById方法的内部会用到this;这个this被期望指向document,当getElementById被作为方法调用的时候,this指向没有问题;但是当用getId来引用documant.lgetElementById的时候,就成了普通函数的调用,因为getId引用的只是getElementById函数本身,其函数内部的this指向了window,而不是期望的doucment;

可以尝试利用下面的方法进行this修正(显式绑定)

        document.getElementById=(function(func){
return function(){
func.apply(document,arguments);
}
})(document.getElementById);
var getId=document.getElementById;
var div=getId('div1');

三、显示绑定:call和apply

1.这两个函数可以指定this的指向,apply使用数组或者类数组作为参数,call则参数数量不固定,从这个意义来说,apply比call使用的频率更高;如果传入的首个参数是null,则代表作为普通函数调用,this此时指向window;

2.这两个函数在某些场合下使用的目的不在于指向this,而是用于借用其他对象的方法;比如类数组如arguments添加数据可以借用[].prototype.push.call;转换为真正的数组可以采用[].prototype.slice.call;截取收元素可以借用[].prototype.shift.call;能够借用的关键在于这些函数内部实现原理同样也可适用于类数组的对象;只要满足以下条件:

  1)对象本身可以通过数字下标存取属性;

  2)对象的length属性可以读写;

jQuery框架中的$对象设计成类数组,其思想大概也是由此而来的吧。

3 值得注意的是,如果把null或者undefined作为this的绑定对象传入call,apply或者bind,这些值在调用的时候回被忽略,实际应用的是默认绑定规则。

这在借用其他对象的方法时,会时常碰到这种用法。

此时可能产生一些副作用,如果某个函数确实应用了this,就有可能修改全局对象,带来不可预料的后果。一种“更安全”的方法时,创建一个DMZ对象来替代null/undefined,在javascript创建一个空对象最简单的方法是object.create(null),object.create(null)和{}很像,但是不会创建prototype这个委托,因此比{}更空。

  

javascript设计模式学习之二——this的更多相关文章

  1. 设计模式学习(二十四):Spring 中使用到的设计模式

    设计模式学习(二十四):Spring 中使用到的设计模式 作者:Grey 原文地址: 博客园:设计模式学习(二十四):Spring 中使用到的设计模式 CSDN:设计模式学习(二十四):Spring ...

  2. JavaScript设计模式学习之路——面向对象的思想

    今天,我拿到了张容铭写的这本<JavaScript设计模式>这本书,开始了关于JavaScript更深一点的学习. 看到这本书开始的时候,虽然之前通过看书.一些比较好的视频的讲解,对Jav ...

  3. Javascript设计模式学习一

    学习Javascript设计模式之前,需要先了解一些相关知识,面向对象的基础知识.this等重要概念,以及掌握一些函数式编程的技巧. Js多态 多态的思想:实际上是把“做什么”和“谁去做”分离开来.例 ...

  4. JavaScript正则表达式学习笔记(二) - 打怪升级

    本文接上篇,基础部分相对薄弱的同学请移步<JavaScript正则表达式学习笔记(一) - 理论基础>.上文介绍了8种JavaScript正则表达式的属性,本文还会追加介绍几种JavaSc ...

  5. JavaScript设计模式学习笔记

    1 JavaScript设计模式深入分析 私有属性和方法:函数有作用域,在函数内用var 关键字声明的变量在外部无法访问,私有属性和方法本质就是你希望在对象外部无法访问的变量. 特权属性和方法:创建属 ...

  6. Java设计模式学习笔记(二) 简单工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...

  7. JavaScript设计模式基础(二)

    JavaScript 设计模式基础(一) 原型模式 在以类为中心的面向对象编程语言中,类和对象的关系就像铸模和铸件的关系,对象总是从类中创建.而原型编程中,类不是必须的,对象未必从类中创建而来,可以拷 ...

  8. JavaScript 基础学习(二)js 和 html 的结合方式

    第一种 使用一个标签 <script type="text/javascript"> js代码; </script> 第二种 使用 script 标签,引入 ...

  9. JavaScript 基础 学习 (二)

    JavaScript 基础 学习 节点属性 ​ 每一个节点都有自己的特点 ​ 这个节点属性就记录着属于自己节点的特点 1. nodeType(以一个数字来表示这个节点类型) ​ 语法:节点.nodeT ...

随机推荐

  1. NBUT 1457 Sona(莫队算法+离散化)

    [1457] Sona 时间限制: 5000 ms 内存限制: 65535 K 问题描述 Sona, Maven of the Strings. Of cause, she can play the ...

  2. CSS3系列:魔法系列

    一.三角形 #wrap div{ margin: 0 auto; } .triangle_three { height:0px; width:0px; border-bottom:50px solid ...

  3. git命令常见问题总结

    1.git如何放弃所有本地修改 git checkout . #本地所有修改的.没有的提交的,都返回到原来的状态 git stash #把所有没有提交的修改暂存到stash里面.可用git stash ...

  4. Memcached 笔记与总结(3)安装 php-memcache(windows 系统下)

    在 windows 下安装 php-memcache,需要下载编译好的 memcached.dll. 要找到可用的 dll 文件,需要根据 php.ini 中的 3 个参数来选择 dll 文件: ① ...

  5. Note: RewriteCond规则

    如果文件存在,就直接访问文件,不进行下面的RewriteRule:RewriteCond %{REQUEST_FILENAME} !-f 如果目录存在,就直接访问目录,不进行下面的RewriteRul ...

  6. Java管道流

    管道流的主要作用可以用于两个线程之间的通信,有管道输出流 PipeOutputStream和管道输入流 PipeInputStream.然后通过connect将两个管道连接起来. import jav ...

  7. JVM内存配置

    JVM内存主要分为两个部分,分别是PermanentSapce和HeapSpace. PermantSpace主要负责存放加载的Class类级对象如class本身,method,field等反射对象, ...

  8. Python之if语句

    计算机之所以能做很多自动化的任务,因为它可以自己做条件判断. 比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,可以用if语句实现: age = 20 if age >= 18: ...

  9. 实例讲述PHP面向对象的特性;;;php中const与define的使用区别

    php中const与define的使用区别 1.const:类成员变量定义,一旦定义且不能改变其值. define:定义全局常量,在任何地方都可以访问.2.define:不能在类中定义,而const可 ...

  10. sql CRUD 增删改查复习汇总

    1.创建数据库create database 数据库名称删除数据库drop database 数据库名称2.创建表create table 表名(    列名 类型(长度) 自增长 主键 非空,)自增 ...