javascript中apply,call和bind的区别

JavaScript020

javascript中apply,call和bind的区别,第1张

在JavaScript 中,this的指向是动态变化的,很可能在写程序的过程中,无意中破坏掉this的指向,所以需要一种可以把this的含义固定的技术,于是就有了call,apply 和bind这三个方法,来改变函数体内部 this 的指向,因为函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。

一、apply、call

apply:应用某一对象的一个方法,用另一个对象替换当前对象。

call:调用一个对象的一个方法,以另一个对象替换当前对象。

共同之处:

都可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。

不同之处:

1、apply:最多只能有两个参数——新this对象和一个数组 argArray。如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里面。如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj,并且无法被传递任何参数。

2、call:则是直接的参数列表,主要用在js对象各方法互相调用的时候,使当前this实例指针保持一致,或在特殊情况下需要改变this指针。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

apply和call功能一样,只是传入的参数列表形式不同,其中 thisArg 是你想指定的上下文,他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。

如果某个函数的参数数量是不固定的,当参数是明确知道数量时用 call ,而不确定的时候用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。

二、bind

与上面不同的是,bind会返回一个改变this指向的新函数 ,注意这里强调的是新函数,其与之前的使用的不是同一块内存地址,所以当需要重复使用这个函数的时候,就不得不把其保存到一个变量,方便下次调用。上面的两个函数都是返回的执行结果,即调用即执行,此外,另外需要注意的地方是,bind函数中的首个参数,会自动成为返回新函数中参数的默认值,那么正式调用的时候,只需要给出除首个参数外,剩余参数即可。

当希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。

三、三者的联系:

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的

apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文

apply 、 call 、bind 三者都可以利用后续参数传参

bind是返回对应函数,便于稍后调用apply、call则是立即调用。

java中对象包含属性和方法, 方法即函数, 只有对象可以调用方法

但是js中一切皆对象, 函数是对象, 函数也可以调用方法

Function.prototype.call

Function.prototype.apply

Function.prototype.bind

Function.prototype.toString

为什么js语言会在function原型上挂上这四个函数?

因为好处太多了, 现在我就说一说call的应用

再深入思考一下, call语法是基于什么形成的呢 ?

了解底层语法有助于我们理解高级的语法

因为在底层的语法眼中, 高级语法只不过是工具, 根本不算语法, 不过是由我定义构建处理来的

理解call函数, 核心必要知识

哈哈哈, v8内部的不知道, 反正js基于现有语法就有这个能力 (还有解法, 基于 proto ,原型链的方式, var temp = Object.create(null)), 利用干净的地方, 防止覆盖原对象的函数

显然, 我们自己的上面的mycall还要很多问题

这里我们就实现了自己的call, 以后看见call就知道都不过是些雕虫小技了(当然真实的实现方式肯定需要考虑更多因素和性能, 而且在v8更大的环境下, 可能还不止一种实现方式,保持谦虚)

代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

<head>

<meta http-equiv="Content-type" content="text/htmlcharset=utf-8">

<title>远程网页源代码读取</title>

<style type="text/css">

/* 页面字体样式 */

body, td, input, textarea {

font-family:Arial

font-size:12px

}

</style>

<script type="text/javascript">

//用于创建XMLHttpRequest对象

function createXmlHttp() {

//根据window.XMLHttpRequest对象是否存在使用不同的创建方式

if (window.XMLHttpRequest) {

xmlHttp = new XMLHttpRequest()//FireFox、Opera等浏览器支持的创建方式

} else {

xmlHttp = new ActiveXObject("Microsoft.XMLHTTP")//IE浏览器支持的创建方式

}

}

//直接通过XMLHttpRequest对象获取远程网页源代码

function getSource() {

var url = document.getElementById("url").value//获取目标地址信息

//地址为空时提示用户输入

if (url == "") {

alert("请输入网页地址 。")

return

}

document.getElementById("source").value = "正在加载……"//提示正在加载

createXmlHttp()//创建XMLHttpRequest对象

xmlHttp.onreadystatechange = writeSource//设置回调函数

xmlHttp.open("GET", url, true)

xmlHttp.send(null)

}

//将远程网页源代码写入页面文字区域

function writeSource() {

if (xmlHttp.readyState == 4) {

document.getElementById("source").value = xmlHttp.responseText

}

}

</script>

</head>

<body>

<h1>远程网页源代码读取</h1>

<div>

地址:<input type="text" id="url">

<input type="button" onclick="getSource()" value="获取源码">

</div>

<textarea rows="10" cols="80" id="source"></textarea>

</body>

</html>