js中目前我遇见的改变作用域的5中方法:call, apply, eval, with, bind。

var obj = {
color: 'green'
}
function demo () {
console.log(arguments)
console.log(this.color)
}
var newFn = demo.bind(obj,1,1,1)
newFn(2,2,2)

bind改变函数作用域的方式和call和apply的不同点在于,call和apply是改变作用域的同时也会执行函数。而bind改变作用域会生成一个新函数,是否执行可以根据具体需求设置。

模拟这个bind方法的代码如下:

var obj = {
color: 'green'
}
function demo () {
console.log(arguments)
console.log(this.color)
}
/*
* bind1 模拟bind方法
* @fn 需要执行的函数
* @obj 传入的作用域
*/
var bind1 = function (fn, obj){
//取从索引值为2开始的后边的所有参数,生成数组
var paramArr = [].slice.call(arguments,2);
return function(){
//拼接两次传入的除了fn和作用域之后的参数
fn.apply(obj, paramArr.concat([].slice.call(arguments,0)))
}
}
var curFn = bind1(demo, obj, 3,3,3)
curFn(4,4,4)

另外一种给函数添加方法的代码为:

var obj = {
color: 'green'
}
function demo () {
console.log(arguments)
console.log(this.color)
} if(Function.prototype.bind === undefined){
Function.prototype.bind = function (obj) {
var paramArr = [].slice.call(arguments, 1);
var that = this;
return function () {
that.apply(obj, paramArr.concat([].slice.call(arguments, 0)))
}
}
}
var curFn = demo.bind1(obj,1,1,1)
curFn(2,2)

作者:mm_hello11
来源:CSDN
原文:https://blog.csdn.net/mm_hello11/article/details/83002111

==========================================================================================================================

Function.prototype.bind()方法
bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,例如,f.bind(obj),实际上可以理解为obj.f(),这时,f函数体内的this自然指向的是obj
例子

    var a = {
b : function(){
var func = function(){
console.log(this.c);
}
func();
},
c : 'Hello!'
}
a.b();
//undefined

注意:这里的this指向的是全局作用域,所以会返回undefined

    var a = {
b : function(){
var that = this;
var func = function(){
console.log(that.c);
}
func();
},
c : 'Hello!'
}
a.b();
//Hello! 注意:可以通过赋值的方式将this赋值给that var a = {
b : function(){
var func = function(){
console.log(this.c);
}.bind(this);
func();
},
c : 'Hello!'
}
a.b();
//Hello! var a = {
b : function(){
var func = function(){
console.log(this.c);
}
func.bind(this)();
},
c : 'Hello!'
}
a.b();
//Hello!

注意:当然,也可以通过bind的方式绑定this,上述两种bind绑定的方式都可以

再看另外一种用法
例子

    function f(y, z){
return this.x + y + z;
}
var m = f.bind({x : 1}, 2);
console.log(m(3));
//

注意:这里bind方法会把它的第一个实参绑定给f函数体内的this,所以这里的this即指向{x : 1}对象,从第二个参数起,会依次传递给原始函数,这里的第二个参数2,即是f函数的y参数,最后调用m(3)的时候,这里的3便是最后一个参数z了,所以执行结果为1 + 2 + 3 = 6

分步处理参数的过程其实是一个典型的函数柯里化的过程(Curry)
我们再来看一道题目

    var a = document.write;
a('hello');
//Error a.bind(document)('hello');
//hello a.call(document, 'hello');
//hello

注意:这里直接调用a的话,this指向的是global或window对象,所以会报错,通过bind或者call的方式绑定this至document对象,即可正常调用

可以用bind的方式预定义参数,例子

 function list(){
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3);
//[1, 2, 3] //预定义参数
var a = list.bind(undefined, 10); var list2 = a();
//[10] var list3 = a(1, 2, 3);
//[10, 1, 2, 3]

注意:这里的Array.prototype.slice.call(arguments)是用来将参数由类数组转换为真正的数组,a的第一个参数undefined表示this的指向,第二个参数10即表示list中真正的第一个参数,依次类推

如何自己实现bind方法?
因为bind()函数发布在ES5中,因此并不能很好的在所有浏览器中运行,需要Polyfill,当然现在几乎所有现代浏览器都支持ES5

    //my_bind方法支持绑定对象
Function.prototype.my_bind = function(context){
var self = this;
return function(){
return self.apply(context, arguments);
}
} //测试
function a(){
return this.name;
}
a(); //'' var b = {name : 'kong'};
a.bind(b)(); //kong a.my_bind(b)(); //kong

上述是最简单的一种实现方式,仅可用来绑定,不可传参

更加健壮的方式:

    //my_bind方法不仅可以绑定对象,还可以传参
Function.prototype.my_bind = function(context){
var args = Array.prototype.slice.call(arguments, 1);
//args [7, 8]
var self = this;
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
//innerArgs [9]
var finalArgs = args.concat(innerArgs);
//finalArgs [7, 8, 9]
return self.apply(context, finalArgs);
}
} //测试
function a(m, n, o){
return this.name + ' ' + m + ' ' + n + ' ' + o;
} var b = {name : 'kong'}; a.my_bind(b, 7, 8)(9); //kong 7 8 9

注意:这里my_bind函数中args表示的是在bind时传入的预定义参数,这里即为7和8,分别表示m和n,return中的innerArgs表示的是调用a的时候传入的参数,这里表示9,即o,最后用concat连接两个数组,即为finalArgs,所以最后执行的是a(7, 8, 9),this指向b,实现了一个完善点的bind方法
处理bind返回的函数如果作为构造函数,搭配new关键字出现的话,我们绑定的this就需要被忽略的兼容性问题
更加完美的方式

    //bind返回的函数如果作为构造函数,搭配new关键字出现的话,我们绑定的this就需要被忽略
//处理构造函数场景下的兼容
Function.prototype.bind = Function.prototype.bind || function(context){
//确保调用bind方法的一定要是一个函数
if(typeof this !== "function"){
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var args = Array.prototype.slice.call(arguments, 1);
var self = this;
var F = function(){};
F.prototype = this.prototype;
var bound = function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return self.apply(this instanceof F ? this : context || this, finalArgs);
}
bound.prototype = new F();
return bound;
}

---------------------
作者:kongjunchao159
来源:CSDN
原文:https://blog.csdn.net/kongjunchao159/article/details/59113129
===================================================================================================================

JS中的bind()方法使用实例讲解


bind() 函数会创建一个新函数(称为绑定函数),当新函数被调用时 this 值绑定到 bind() 的第一个参数。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。

创建绑定函数

bind() 最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的 this 值。例如

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
this.x = 9;
var module = {
  x: 81,
  getX: function() { return this.x; }
};
 
module.getX(); // 返回 81
 
var retrieveX = module.getX;
retrieveX(); // 返回 9, 在这种情况下,"this"指向全局作用域
 
// 创建一个新函数,将"this"绑定到module对象
// 新手可能会被全局的x变量和module里的属性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81

偏函数(Partial Functions)

bind()的另一个最简单的用法是使一个函数拥有预设的初始参数。它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function list() {
  return Array.prototype.slice.call(arguments);
}
 
var list1 = list(1, 2, 3); // [1, 2, 3]
 
// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);
var leadingThirtysevenListss = list.bind(undefined, 37,32,31,22);
 
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
var list4 =leadingThirtysevenListss(); //[37,32,31,22]
var list5 = leadingThirtysevenListss(1, 2, 3); // [37,32,31,22, 1, 2, 3]

在定时器中使用

使用 window.setTimeout() 时,this 关键字会指向 window (或全局)对象。当使用类的方法时,需要 this 引用类的实例,你可能需要显式地把 this 绑定到回调函数以便继续使用实例。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
 
// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);//this指向LateBloomer对象
};
 
LateBloomer.prototype.declare = function() {
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
};
 
var flower = new LateBloomer();
flower.bloom();  // 一秒钟后, 调用'declare'方法
//I am a beautiful flower with 8 petals!
//如果不使用bind(this) 则 返回 I am a beautiful flower with undefined petals!

原文 https://www.2cto.com/kf/201801/714822.html

======================================================================================================================

JS中的bind的实现以及使用

在讨论bind()方法之前我们先来看一道题目:

var altwrite = document.write;
altwrite("hello");//报错,因为altwrite方法是在window上进行调用的,而window上是没有该方法的
//1.以上代码有什么问题
//2.正确操作是怎样的
//3.bind()方法怎么实现

对于上面这道题目,答案并不是太难,主要考点就是this指向的问题,altwrite()函数改变this的指向global或window对象,导致执行时提示非法调用异常,正确的方案就是使用bind()方法:

altwrite.bind(document)("hello")

当然也可以使用call()方法:

altwrite.call(document, "hello")

本文的重点在于讨论第三个问题bind()方法的实现,在开始讨论bind()的实现之前,我们先来看看bind()方法的使用:

绑定函数

bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值。常见的错误就像上面的例子一样,将方法从对象中拿出来,然后调用,并且希望this指向原来的对象。如果不做特殊处理,一般会丢失原来的对象。使用bind()方法能够很漂亮的解决这个问题:

this.num = 9;
var mymodule = {
num: 81,
getNum: function() { return this.num; }
}; module.getNum(); // 81 var getNum = module.getNum;
getNum(); // 9, 因为在这个例子中,"this"指向全局对象 // 创建一个'this'绑定到module的函数
var boundGetNum = getNum.bind(module);
boundGetNum(); //

偏函数(Partial Functions)

Partial Functions也叫Partial Applications,这里截取一段关于偏函数的定义:

Partial application can be described as taking a function that accepts some number of arguments, binding values to one or more of those arguments, and returning a new function that only accepts the remaining, un-bound arguments.

这是一个很好的特性,使用bind()我们设定函数的预定义参数,然后调用的时候传入其他参数即可:

function list() {
return Array.prototype.slice.call(arguments);
} var list1 = list(1, 2, 3); // [1, 2, 3] // 预定义参数37
var leadingThirtysevenList = list.bind(undefined, 37); var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

和setTimeout一起使用

一般情况下setTimeout()的this指向window或global对象。当使用类的方法时需要this指向类实例,就可以使用bind()将this绑定到回调函数来管理实例。

function Bloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
} // 1秒后调用declare函数
Bloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
}; Bloomer.prototype.declare = function() {
console.log('我有 ' + this.petalCount + ' 朵花瓣!');
};

注意:对于事件处理函数和setInterval方法也可以使用上面的方法

绑定函数作为构造函数

绑定函数也适用于使用new操作符来构造目标函数的实例。当使用绑定函数来构造实例,注意:this会被忽略,但是传入的参数仍然可用。

function Point(x, y) {
this.x = x;
this.y = y;
} Point.prototype.toString = function() {
return this.x + ',' + this.y;
}; var p = new Point(1, 2);
p.toString(); // '1,2' var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// 实现中的例子不支持,
// 原生bind支持:
var YAxisPoint = Point.bind(null, 0/*x*/); var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5' axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true

上面例子中Point和YAxisPoint共享原型,因此使用instanceof运算符判断时为true。

捷径

bind()也可以为需要特定this值的函数创造捷径。

例如要将一个类数组对象转换为真正的数组,可能的例子如下:

var slice = Array.prototype.slice;

// ...

slice.call(arguments);

如果使用bind()的话,情况变得更简单:

var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice); // ... slice(arguments);

实现

上面的几个小节可以看出bind()有很多的使用场景,但是bind()函数是在 ECMA-262 第五版才被加入;它可能无法在所有浏览器上运行。这就需要我们自己实现bind()函数了。

首先我们可以通过给目标函数指定作用域来简单实现bind()方法:

Function.prototype.bind = function(context){
self = this; //保存this,即调用bind方法的目标函数
return function(){
return self.apply(context,arguments);
};
};

考虑到函数柯里化的情况,我们可以构建一个更加健壮的bind()

Function.prototype.bind = function(context){
var args = Array.prototype.slice.call(arguments, 1),
self = this;
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return self.apply(context,finalArgs);
};
};

这次的bind()方法可以绑定对象,也支持在绑定的时候传参。

继续,Javascript的函数还可以作为构造函数,那么绑定后的函数用这种方式调用时,情况就比较微妙了,需要涉及到原型链的传递:

Function.prototype.bind = function(context){
var args = Array.prototype.slice(arguments, 1),
F = function(){},
self = this,
bound = function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return self.apply((this instanceof F ? this : context), finalArgs);
}; F.prototype = self.prototype;
bound.prototype = new F();
retrun bound;
};

这是《JavaScript Web Application》一书中对bind()的实现:通过设置一个中转构造函数F,使绑定后的函数与调用bind()的函数处于同一原型链上,用new操作符调用绑定后的函数,返回的对象也能正常使用instanceof,因此这是最严谨的bind()实现。

对于为了在浏览器中能支持bind()函数,只需要对上述函数稍微修改即可:

Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
} var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(
this instanceof fNOP && oThis ? this : oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments))
);
}; fNOP.prototype = this.prototype;
fBound.prototype = new fNOP(); return fBound;
};

原文:http://www.cnblogs.com/heshan1992/p/6667596.html

js中的bind方法的实现方法的更多相关文章

  1. 理解 backbone.js 中的 bind 和 bindAll 方法,关于如何在方法中指定其中的 this,包含apply方法的说明[转载]

    转载自:http://gxxsite.com/content/view/id/132.html 在backbone.js的学习过程中,被bind和bindAll弄得有点晕,这里包括underscore ...

  2. js中的splice方法和slice方法简单总结

    slice:是截取用的 splice:是做删除 插入 替换用的 slice(start,end): 参数: start:开始位置的索引 end:结束位置的索引(但不包含该索引位置的元素) 例如: va ...

  3. JS中的bind的实现以及使用

    在讨论bind()方法之前我们先来看一道题目: var altwrite = document.write; altwrite("hello"); //1.以上代码有什么问题 // ...

  4. JS中的五种去重方法

    JS中的五种去重方法 第一种方法: 第二种方法:  第三种方法: 第四种方法: 第五种方法:优化遍历数组法 思路:获取没重复的最右一值放入新数组 * 方法的实现代码相当酷炫,* 实现思路:获取没重复的 ...

  5. 判断js中各种数据的类型方法之typeof与0bject.prototype.toString讲解

    提醒大家,Object.prototype.toString().call(param)返回的[object class]中class首字母是大写,像JSON这种甚至都是大写,所以,大家判断的时候可以 ...

  6. JavaScript -- 时光流逝(五):js中的 Date 对象的方法

    JavaScript -- 知识点回顾篇(五):js中的 Date 对象的方法 Date 对象: 用于处理日期和时间. 1. Date对象的方法 <script type="text/ ...

  7. JavaScript -- 时光流逝(三):js中的 String 对象的方法

    JavaScript -- 知识点回顾篇(三):js中的 String 对象的方法 (1) anchor(): 创建 HTML 锚. <script type="text/javasc ...

  8. 在JS中调用CS里的方法(PageMethods)

    在JS中调用CS里的方法(PageMethods) 2014年04月28日 11:18:18 被动 阅读数:2998   最近一直在看别人写好的一个项目的源代码,感觉好多东西都是之前没有接触过的.今天 ...

  9. Angular.js中处理页面闪烁的方法详解

    Angular.js中处理页面闪烁的方法详解 前言 大家在使用{{}}绑定数据的时候,页面加载会出现满屏尽是{{xxx}}的情况.数据还没响应,但页面已经渲染了.这是因为浏览器和angularjs渲染 ...

随机推荐

  1. springsecurity学习

    首先讲一下,没有用到数据库,然后觉得重要的就是security的配置securityConfig.class,不太会说(好像也不太会用),上图吧,也是学习狂神过来的 项目结构 大致效果 pom.xml ...

  2. 使用 pdb 进行调试

    使用 pdb 进行调试 pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点.单步调试.进入函数调试.查看当前代码.查看栈片段.动态改变变 ...

  3. Linux I2C核心、总线和设备驱动

    目录 更新记录 一.Linux I2C 体系结构 1.1 Linux I2C 体系结构的组成部分 1.2 内核源码文件 1.3 重要的数据结构 二.Linux I2C 核心 2.1 流程 2.2 主要 ...

  4. mysql 按月统计但是有几个月没有数据,需要变成0

    创建现在倒过去的12个月的视图 CREATE VIEW `past_12_month_view` AS SELECT DATE_FORMAT(CURDATE(), '%Y-%m') AS `month ...

  5. 使用nodejs对Marketing Cloud的contact主数据进行修改操作

    假设在Marketing Cloud有这样一个contact主数据: 现在需求是使用编程语言比如nodejs修改这个contact实例的高亮属性. 代码如下: var config = require ...

  6. CHD-5.3.6集群上Flume的文件监控

    收集hive的log     hive的运行日志:    /home/hadoop/CDH5.3.6/hive-0.13.1-cdh5.3.6/log/hive.log * memory *hdfs  ...

  7. 在DjangoAdmin中使用KindEditor(上传图片)

    一.下载 http://kindeditor.net/down.php 删除asp.asp.net.php.jsp.examples文件夹 拷贝到static目录下 二.配置 kindeditor目录 ...

  8. PAT Advanced 1152 Google Recruitment (20 分)

    In July 2004, Google posted on a giant billboard along Highway 101 in Silicon Valley (shown in the p ...

  9. Elasticsearch下载安装

    本文链接:https://blog.csdn.net/yjclsx/article/details/81302041注:Elasticsearch 需要 Java 8 环境,在安装Elasticsea ...

  10. RNN基础

    RNN之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关.具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅 ...