javascript设计模式学习之二——this
一、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的更多相关文章
- 设计模式学习(二十四):Spring 中使用到的设计模式
设计模式学习(二十四):Spring 中使用到的设计模式 作者:Grey 原文地址: 博客园:设计模式学习(二十四):Spring 中使用到的设计模式 CSDN:设计模式学习(二十四):Spring ...
- JavaScript设计模式学习之路——面向对象的思想
今天,我拿到了张容铭写的这本<JavaScript设计模式>这本书,开始了关于JavaScript更深一点的学习. 看到这本书开始的时候,虽然之前通过看书.一些比较好的视频的讲解,对Jav ...
- Javascript设计模式学习一
学习Javascript设计模式之前,需要先了解一些相关知识,面向对象的基础知识.this等重要概念,以及掌握一些函数式编程的技巧. Js多态 多态的思想:实际上是把“做什么”和“谁去做”分离开来.例 ...
- JavaScript正则表达式学习笔记(二) - 打怪升级
本文接上篇,基础部分相对薄弱的同学请移步<JavaScript正则表达式学习笔记(一) - 理论基础>.上文介绍了8种JavaScript正则表达式的属性,本文还会追加介绍几种JavaSc ...
- JavaScript设计模式学习笔记
1 JavaScript设计模式深入分析 私有属性和方法:函数有作用域,在函数内用var 关键字声明的变量在外部无法访问,私有属性和方法本质就是你希望在对象外部无法访问的变量. 特权属性和方法:创建属 ...
- Java设计模式学习笔记(二) 简单工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...
- JavaScript设计模式基础(二)
JavaScript 设计模式基础(一) 原型模式 在以类为中心的面向对象编程语言中,类和对象的关系就像铸模和铸件的关系,对象总是从类中创建.而原型编程中,类不是必须的,对象未必从类中创建而来,可以拷 ...
- JavaScript 基础学习(二)js 和 html 的结合方式
第一种 使用一个标签 <script type="text/javascript"> js代码; </script> 第二种 使用 script 标签,引入 ...
- JavaScript 基础 学习 (二)
JavaScript 基础 学习 节点属性 每一个节点都有自己的特点 这个节点属性就记录着属于自己节点的特点 1. nodeType(以一个数字来表示这个节点类型) 语法:节点.nodeT ...
随机推荐
- JavaScript系列:event.bubbles属性(并不是所有的事件都具有冒泡)
地址 https://www.w3.org/TR/DOM-Level-3-Events/#h3_interface-Event https://segmentfault.com/q/101000000 ...
- react 用value 直接赋值 必须用onchange的解决方式
render : function(){ return <input value={this.state.bankCardValue} type="text" onKeyUp ...
- Nginx 笔记与总结(10)Nginx 与 PHP 整合
Apache + PHP 的编译 和 Nginx + PHP 的编译,区别: Apache 一般把 PHP 当作自己的一个模块来启动: Nginx 则是把 HTTP 请求变量(如 get,user_a ...
- 郎科U208(主控 PS2251-50 HYNIX H27UCG8T2MYR)量产还原
6年前的一个U盘 记得还是参加某会议送的,当时做了量产 多做了一个光盘区,现在用不着了 想还原成普通U盘 忘了方法. 可见笔记的重要性 Chipgenius看了主控 PS2251-50 芯片是海力士 ...
- ADO 事务
Ado.Net事务处理.在ADO.NET 中,可以使用Connection 和Transaction 对象来控制事务.若要执行事务,请执行下列操作:• 调用Connection 对象的BeginTra ...
- LoadRunner系统架构简介
1.LoadRunner系统架构简介 LoadRunner是通过创建虚拟用户来代替真实实际用户来操作客户端软件比如Internet Explorer,来向IIS.Apache等Web服务器发送HTTP ...
- wdate-year-month-week-gategory-amount-coin
---2016-12-02 19:46:39 the whole table DISTINCT field SUM(field) COUNT(field) --- 888983 rows OK SEL ...
- 页面瀑布流布局的实现 javascript+css
先看所谓的瀑布流布局 在不使用瀑布流布局的情况下,当页面要显示不同高度的图片时,会如下面显示 下面的元素总是和最靠近它的元素对齐. 为了使元素能够在我们想要的位置上显示,我们使用绝对定位. 说一下大体 ...
- random circle
<!doctype html><meta charset="utf-8"><html><head><title>D3 t ...
- ManualResetEvent和AutoResetEvent的区别实例
ManualResetEvent和AutoResetEvent的作用可以理解为在线程执行中插入停顿点flag终止程序运行,然后通过设置flag的状态来使得程序继续运行. 两者的区别是:ManualRe ...