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. oracle wm_concat函数用法

    在Oracle中使用wm_concat(column)可以实现字段的分组合并,逗号分隔.

  2. android项目笔记整理(3)

    61.AlphabetIndexer字母索引辅助类       实现对链表类型的数据进行快速索引. 应用于类似联系人列表右侧的导航栏 注意:       1.链表里的元素必须是Object类型,并实现 ...

  3. c# MVC方式文件上传

    MVC控制器中代码 index.cshtml <form action="/Home/Upload" method="post" enctype=&quo ...

  4. Spark的Shuffle

    0. Shuffle概述 要理解什么是Shuffle,首先介绍大数据与分布式.我们知道大数据的存储是分布式存储,大数据的计算框架是分布式的计算框架.分布式必然存在数据的交互传输,简言之Shuffle就 ...

  5. GOLANG利用断言调用结构体内特有的方法-

    package main import( "fmt" _"sort" _"math/rand" ) //多态的特征是通过接口来实现的 //多 ...

  6. PMM 监控 MySQL

    Percona Monitoring and Management (PMM)是一款开源的用于监控 MySQL 和 MongoDB 性能的开源平台,通过 PMM 客户端收集到的 DB 监控数据用第三方 ...

  7. Educational Codeforces Round 37 (Rated for Div. 2)C. Swap Adjacent Elements (思维,前缀和)

    Educational Codeforces Round 37 (Rated for Div. 2)C. Swap Adjacent Elements time limit per test 1 se ...

  8. Linux下批量修改文件编码

    假设需要将所有afish目录下的php文件,编码从gb2312转到utf8 cd afish find ./ -type f -name “*.php”|while read line;do echo ...

  9. SQL查询CASE遇上NULL怎么办?

    原SQL: case userName when  null THEN '空' else '有值' end, 这种写法不好使: 换一种:case when userName is null THEN ...

  10. SQL 归纳

    查询父节点的所有子节点: SELECT * FROM menu m START WITH m.ID_ = '402882836068695f0160688eebf70006' CONNECT BY m ...