this
call
apply

this

和其他语言不同,JavaScript的this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

this的指向

除去不常用的with和eval,this的指向大致可分为以下四种:

  • 作为对象的方法调用

  • 作为普通函数调用

  • 构造器调用

  • Function.prototype.call或Function.prototype.apply调用

作为对象的方法调用

当函数作为对象的方法被调用时,this指向该对象。

var obj={
a:1,
getA:function(){
alert(this===obj);//true
alert(this.a);//1
}
}; obj.getA();

作为普通函数调用

当函数不作为对象的属性被调用时,也就是普通函数方式,此时this总是指向全局对象。在浏览器中,这个全局对象是window。

window.name='globalName';

var getName1=function(){
return this.name;
}; var myObject={
name:'sven',
getName:function(){
return this.name;
}
}; var getName=myObject.getName; alert(getName1());//globalName
alert(getName());//globalName

构造器调用

当用new运算符调用函数时,该函数总会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象。

var MyClass=function(){
this.name='sven';
}; var obj=new MyClass();
alert(obj.name);//sven

但是如果构造器显式地返回了一个object类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的this:

var MyClass=function(){
this.name='sven';
return{
name:'anne';
}
}; var obj=new MyClass();
alert(obj.name);//anne

如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成上述问题:

var MyClass=function(){
this.name='sven';
return 'anne';
}; var obj=new MyClass();
alert(obj.name);//sven

call和apply调用

call和apply可以动态的地改变传入函数的this:

var obj1={
name:'sven',
getName:function(){
return this.name;
}
}; var obj2={
name:'anne'
}; console.log(obj1.getName());
console.log(obj1.getName.call(obj2));

call和apply

call和apply作用一模一样,区别在于传入参数的形式不同。apply接受两个参数,第一个参数指定了函数体内this对象的指向,第二个参数第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组。

JavaScript的参数在内部就是用一个数组来表示的,从这个意义上来说,apply比call的使用率更高。call是包装在apply上的一颗语法糖,如果我们明确知道函数接受多少个参数,而且想一目了然地表达形参和实参的对应关系,那么也可以用call来传送参数。

当使用call或者apply时,如果我们传入的第一个参数是null,函数体内的this会指向默认的宿主对象,在浏览器中就是window,但如果是在严格模式下,函数体内的this还是为null。

有时候我们使用call或者apply的目的并不在于指定this的指向,二十另有用途,比如借用其他对象的方法,那么我们就可以传入null来代替某个具体的对象。

call和apply的用途

改变this的指向

Function.prototype.bind

        Function.prototype.bind=function() {
var self=this,
context=[].shift.call(arguments),//需要绑定的this上下文
args=[].slice.call(arguments);//剩余的参数转成数组
return function(){
return self.apply(context,[].concat.call(args,[].slice.call(arguments)));//执行新的函数体的时候,会把之前传入的context当作新函数体内的this,并且组合两次分别传入的参数,作为新函数的参数
}
}; var obj={
name:'sven'
}; var func=function(a,b,c,d){
alert(this.name);
alert([a,b,c,d]);
}.bind(obj,1,2); func(3,4);

使用其他对象的方法

第一种场景是借用构造函数,可以实现一些类似继承的效果:

var A=function(name){
this.name=name;
}; var B=function(){
A.apply(this,arguments);
}; B.prototype.getName=function(){
return this.name;
}; var b=new B('sven');
console.log(b.getName());

第二种场景:函数的参数列表arguments是一个类数组对象,虽然它也有下标,但她并非真正的数组,所以不能进行排序操作或者往集合里添加一个新的元素。这种情况下我们常常会借用Array.prototype对象上的方法。比如想往arguments里插入一个元素,通常会借用Array.prototype.push:

(function(){Array.prototype.push.call(arguments,3)})(1,2);

在操作arguments时,我们经常非常频繁地找Array.prototype借用方法。

  • 转化为数组:Array.prototype.slice

  • 截去头元素:Array.prototype.shift

this、call和apply的更多相关文章

  1. JS核心系列:浅谈 call apply 与 bind

    在JavaScript 中,call.apply 和 bind 是 Function 对象自带的三个方法,这三个方法的主要作用是改变函数中的 this 指向,从而可以达到`接花移木`的效果.本文将对这 ...

  2. SQL Server-聚焦APPLY运算符(二十七)

    前言 其实有些新的特性在SQL Server早就已经出现过,但是若非系统的去学习数据库你会发现在实际项目中别人的SQL其实是比较复杂的,其实利用新的SQL Server语法会更加方便和简洁,从本节开始 ...

  3. 利用apply()或者rest参数来实现用数组传递函数参数

    关于call()和apply()的用法,MDN文档里写的非常清晰明白,在这里就不多做记录了. https://developer.mozilla.org/zh-CN/docs/Web/JavaScri ...

  4. 由js apply与call方法想到的js数据类型(原始类型和引用类型)

    原文地址:由js apply与call方法想到的js数据类型(原始类型和引用类型) js的call方法与apply方法的区别在于第二个参数的不同,他们都有2个参数,第一个为对象(即需要用对象a继承b, ...

  5. JavaScript学习笔记(二)——闭包、IIFE、apply、函数与对象

    一.闭包(Closure) 1.1.闭包相关的问题 请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9:方法:找到所有的div, ...

  6. 瞬间记住Javascript中apply与call的区别

    关于Javascript函数的apply与call方法的用法,网上的文章很多,我就不多话了.apply和call的作用很相似,但使用方式有区别 apply与call的第一个参数都是一个对象,这个对象就 ...

  7. scope.$apply是干嘛的

    开始用angular做项目的时候,一定碰到过$scope.$apply()方法,表面上看,这像是一个帮助你进行数据更新的方法,那么,它为何存在,我们又该如何使用它呢. JavaScript执行顺序 J ...

  8. JavaScript中的apply,call与this的纠缠

    1.apply定义 apply:调用函数,并用指定对象替换函数的 this 值,同时用指定数组替换函数的参数. 语法:apply([thisObj[,argArray]]) thisObj 可选.要用 ...

  9. jQuery之常用且重要方法梳理(siblings,nextAll,end,wrap,apply,call,each)-(二)

    1.siblings() siblings() 获得匹配集合中每个元素的同胞,通过选择器进行筛选是可选的. <body> <div><span>Hello</ ...

  10. JS中 call() 与apply 方法

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

随机推荐

  1. centos 7 下modelsim10.2c安装教程

    step1: chmod +x ./install.linux(但是没有任何反应,原因是install.linux是32位程序,系统是64位的,所以要安装相应的库){ yum install glib ...

  2. JQuery 性能优化

    一.合适的选择器 JQuery 选择器提供丰富的选择器来定位DOM元素, 基本选择器 #id..class.element.*等:那他们哪个更高效呢? 第一选择: $("#id") ...

  3. 之前做web性能优化的一些个人心得

    一个web项目后期的维护主要在于性能方面.数据吞吐量一旦增大各种bug都出来了.那些通过硬件<数据库分表,数据库主从分离,读写分离>等的一些手段此处就不多说了.本文主要在编码方面做一个性能 ...

  4. 使用asp.net上传图片并且裁剪的方法

    工欲善其事,必先利其器,坚持才能更好 这篇文章主要是强调怎么使用asp.net上传图片并且能够裁剪,这个功能主要使用在注册信息的时候需要上传头像并且图片格式很大的时候能够把图片裁剪成更小的图片.下面来 ...

  5. WebClient.UploadValues Post中文乱码的解决方法

    //using (System.Net.WebClient wc = new System.Net.WebClient()) //{ // wc.Encoding = Encoding.GetEnco ...

  6. JAVA操作LDAP总结

    一.LDAP概念 LDAP的全称为Lightweight Directory Access Protocol(轻量级目录访问协议), 基于X.500标准, 支持 TCP/IP. LDAP目录为数据库, ...

  7. 12天学好C语言——记录我的C语言学习之路(Day 9)

    12天学好C语言--记录我的C语言学习之路 Day 9: 函数部分告一段落,但是我们并不是把函数完全放下,因为函数无处不在,我们今后的程序仍然会大量运用到函数 //转入指针部分的学习,了解指针是什么 ...

  8. .Net规则引擎Biztalk,Workflow和CKRule的比较

    微软的规则引擎   很多朋友会问,.Net平台有没有规则引擎?像Java就有很多的规则引擎,Drools,ILog都做得非常好,但.Net好像还没有哦.很多知道规则引擎,但不知道.Net的朋友都烦这个 ...

  9. CSU-ACM2016暑期集训训练4-BFS(F - Oil Deposits)

    F - Oil Deposits Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u De ...

  10. c++ primer (5)2

    第三章 1.头文件不应包含using声明,因为头文件的内容会拷贝到所有引用它的文件中去. 2.初始化string对象的方式: string s1; //默认初始化,s1是一个空串 string s2( ...