例一
var name = '小王',
age = 17;
var obj = {
name: "小张",
objAge: this.age,//this指向obj
myFun: function() {
//console.log("obj-this", this) //this指向obj
console.log(this.name + "年龄" + this.age)
}
}
console.log(obj.objAge) //17
obj.myFun(); //小张年龄 undefined
例2
var fav = "盲僧"
function shows() {
// console.log("shows-this", this) //this指向window
console.log(this.fav)
}
shows() //盲僧
比较一下这两者 this 的差别,第一个打印里面的 this 指向 obj,第二个全局声明的 shows() 函数 this 是指向window ;
1,call()、apply()、bind() 都是用来重定义 this 这个对象的!
var name = '小王',
age = 17;
var obj = {
name: "小张",
objAge: this.age,
myFun: function() {
console.log("obj-this", this) //this指向obj
console.log(this.name + "年龄" + this.age)
}
}
var db = {
name: "德玛",
age: "89"
}
obj.myFun();//小张年龄underfind myFun的this指向obj
var myFunA= obj.myFun;
//myFunA在外部调用,此时的this指向了全局对象
myFunA();//小王年龄17
//为了保证this指向不变,我们可以通过bind方法绑定this指向
//如:
var myFunA2= obj.myFun.bind(obj);
console.log(myFunA2()); //小张年龄underfind 需要调用才执行
//此时可以看到this的指向保持指向了obj这个对象。
var myFunA3 = obj.myFun.call(obj);
console.log(myFunA3 ); //小张年龄underfind 不需要调用就执行
var myFunA4 = obj.myFun.apply(obj);
console.log(myFunA4); //小张年龄underfind 不需要调用就执行
//此时你会发现当我们用call或者apply方法来保证this指向的时候,
//call和apply方法会直接执行掉myFun这个方法,不需要调用。
//obj.myFun方法里的this由obj指向db
obj.myFun.call(db) // 德玛年龄 89
obj.myFun.apply(db) // 德玛年龄 89
console.log(obj.myFun.bind(db)) //bind 返回的是一个新的函数,你必须调用它才会被执行。
obj.myFun.bind(db)() //调用bind返回的函数 // 德玛年龄 89
以上出了 bind 方法后面多了个 () 外 ,结果返回都一致!
由此得出结论,bind和call,apply的区别,bind 返回的是一个新的函数,.只会改变函数this指向不会执行函数,你必须调用它才会被执行,call和apply会改变this指向并且直接执行了函数
2,对比call 、bind 、 apply 传参情况下
var name = '小王',
age = 17;
var obj = {
name: "小张",
objAge: this.age,
myFun: function(fm, ft) {
console.log("obj-this", this) //this指向obj
console.log(this.name + "年龄" + this.age, " 来自 " + fm + " 去往 " + ft)
}
}
var db = {
name: "德玛",
age: "89"
}
obj.myFun.call(db, "广州", "深圳") //德玛年龄89 来自 广州 去往 深圳
obj.myFun.apply(db, ["广州", "深圳"]) // 德玛年龄89 来自 广州 去往 深圳
obj.myFun.bind(db, "广州", "深圳")() //德玛年龄89 来自 广州 去往 深圳
obj.myFun.bind(db, ["广州", "深圳"])() //德玛年龄89 来自 广州,深圳 去往 undefined
//例2
var obj = {
a:2,
sum:function(b,c){
return this.a + b + c;
}
}
var sum0 = obj.sum;
//分别用bind,call,apply方法来调用sum0方法。
var sum1 = sum0.bind(obj,2,3);
console.log(sum1()); // 7
var sum2 = sum0.call(obj,2,3);
console.log(sum2); // 7
var sum3 = sum0.apply(obj,[2,3]);
console.log(sum3); // 7
从这里我们可以看出bind和call方法传入参数方式和apply方式不一样。
// 微妙的差距!
//
// 从上面四个结果不难看出:
//
// call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数差别就来了:
//
// call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面 obj.myFun.call(db,'成都', ... ,'string' )。
//
// apply 的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(db,['成都', ..., 'string' ])。
//
// bind 除了返回是函数以外,它 的参数和 call 一样。
//
// 当然,三者的参数不限定是 string 类型,允许是各种类型,包括函数 、 object 等等!
总结:
call和bind方法可以传入多个参数,第二个参数后的所有参数都传入调用的函数中,apply方法只能传入两个参数,且第二参数为数组,数组里面的元素传入到调用的函数中。
最后,我们考虑一下,如果使用apply方法时,传入的第一个参数是null时,调用函数时,会发生什么情况,会不会报错呢!
不多说,直接上例子
var A={
name:"我是小A",
fun:function(num,money){
console.log("大家好! "+this.name+" 我有"+num+"张"+money+"块")
}
}
var B = {
name:"我是小B"
}
var monies = [10,20];
name="我是小C"
A.fun.apply(null,monies); //大家好! 我是小C 我有10张20块
可以看到 如果第一传入的参数是null的话,在函数提内的this会指向全局对象,在浏览器中就是window。
所以可以总结出两点:
1.如果函数中有明确使用this,那么this就会指向传入的第一个参数的作用域。
2.如果传入的第一参数为null时,this就会指向全局的作用域。
fn.apply(this, arguments)将函数的属性与方法进行拷贝,bai主要是实现类的继承。
function Person(name){
this.name=name;
this.sayname=function (){
console.log(this.name)//小明
}
}
function Student(name){
console.log(this)//这里的this指向xiaoming这个实例
//apply将Person方法里的this指向由window指向xiaoming这个实例,并且直接执行
Person.apply(this,arguments);//arguments作为Person()函数的实参,是一个数组来的
}
var xiaoming = new Student("小明");
xiaoming.sayname();
//这样Student类拷贝了Person的属性和方法,实现了类的继承
//忘记加上new命令,结果是this指向了全局作用域
部分转自:https://www.runoob.com/w3cnote/js-call-apply-bind.html
js中arguments详解
一、简介
了解arguments这个对象之前先来认识一下javascript的一些功能:
其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数都会有一个Arguments对象实例arguments,它引用着函数的实参,可以用数组下标的方式"[]"引用arguments的元素。arguments.length为函数实参个数,arguments.callee引用函数自身。
三、使用方法
虽然arguments对象并不是一个数组(类数组),但是访问单个参数的方式与访问数组元素的方式相同
例如:
arguments[0],arguments[1],。。。arguments[n]; 在js中 不需要明确指出参数名,就能访问它们
例如:
function test() {
var s = "";
for (var i = 0; i < arguments.length; i++) {
alert(arguments[i]);
s += arguments[i] + ",";
}
return s;
}
test("name", "age");
输出结果:
name,age
我们知道每一个对象都有自己的属性,arguments对象也不例外,首先arguments的访问犹如Array对象一样,用0到arguments.length-1来枚举每一个元素。下面我们来看看callee属性,返回正被执行的** Function** 对象,guments.callee就是函数自身。,实现匿名的递归函数。代码如下:
var sum = function (n) {
if (1 == n) {
return 1;
} else {
return n + arguments.callee(n - 1); //6 5 4 3 2 1
}
}
alert(sum(6));
输出结果:21
传多个参数事可以直接用argument,比如求最大值:
function max() {
var max = arguments[0];
console.log(arguments)
for (val of arguments) {
if (val >= max) {
max = val;
}
}
return max;
}
var maxValue = max('9', 1, 2, 4)
console.log(maxValue)
//apply的另一种用法就是用于将数组分割为一个个元素。
//例如想在数组中a[1,2,3,4]中寻找出最大的袁术出来。
//利用apply求最大值:
var a = [1, 2, 3, 4];
console.log(Math.max(a))
console.log(Math.max.apply(null, a)); //输出4)