赞
踩
js 的闭包与 this的指向可以说是js 进阶的必经之路;
this引用的是函数据以执行的环境对象
==================================
随意编了三个函数(匿名函数调用时, 指向全局对象)
大家凑合着看吧
let name='hello world' const obj={ name:'obj', fn1:function sayHello(){ let name='有名函数' console.log(this.name) }, fn2:function (){ let name='匿名函数' console.log(this.name) }, fn3:()=>{ let name='箭头函数' console.log(this.name) } } obj.fn1() //obj obj.fn2() //obj obj.fn3() //hello world 或者undefined
可以用来改变this的指向
;但是 使用apply() ,第二个是必须接收一个数组的参数形式
this的指向, 经常与匿名函数, 箭头的函数的使用有关, 当然有名函数也不例外,
一般可以先在函数声明前, let that =this , let _this=this, 先去改变this 的指向
详解: https://www.cnblogs.com/phoebeyue/p/9216514.html
/**1.匿名函数具有全局性,故匿名函数的this 指向window的对象;即是没有名字的函数
* 2.箭头函数:与匿名函数还是有点区别,
* 箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。
由于JavaScript函数对this绑定的错误处理,下面的例子无法得到预期结果:
* 3.函数表达式:属于匿名函数,并将匿名函数赋值给了一个变量;
*
*
* */
由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定
var obj = {
birth: 1990,
getAge: function (year) {
var b = this.birth; // 1990
var fn = (y) => y - this.birth; // this.birth仍是1990
return fn.call({birth:2000}, year);
}
};
obj.getAge(2015); // 25
两者的使用实例
// this 与call(); apply)();arguments的用法 function test(test1, test2) { console.log(test1 + test2); } function applyTest1(test1, test2) { // return test.apply(this,[test1,test2]); // 传入数组 //return test.apply(this,arguments); //arguments 为一个伪数组; //return test.call(this,test1,test2);// apply与call用法的差别就在这里 return test.call(this,arguments);//会出现问题;需要使用, ...arguments //先解构 } applyTest1(4,6); var name = "hello"; var person = {name: "小明"}; function sayHello () { console.log(this.name )// hello } var personSay = sayHello.bind(person); //bind的用法, 调用时,需要(), 进行使用 personSay();
在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢。
在说区别之前还是先总结一下三者的相似之处:
1、都是用来改变函数的this对象的指向的。
2、第一个参数都是this要指向的对象。
3、都可以利用后续参数传参。
那么他们的区别在哪里的,先看一个例子。
var xw = {
name : "小王",
gender : "男",
age : 20,
say : function() {
alert(this.name + " , " + this.gender + " ,今年" + this.age);
}
}
var xh = {
name : "小红",
gender : "女",
age : 18
}
xw.say();
那么如何用xw的say方法来显示xh的数据呢。
对于call可以这样:
xw.say.call(xh);
xw.say.apply(xh);
而对于bind来说需要这样:
xw.say.bind(xh)();
如果直接写xw.say.bind(xh)是不会有任何结果的,看到区别了吗?
call和apply都是对函数的直接调用,
而bind方法返回的仍然是一个函数,因此后面还需要()来进行调用才可以。
那么call和apply有什么区别呢?我们把例子稍微改写一下。(体现在传参的时候)
注意写在函数内部的时候,可以使用arguments
来代替参数,达到传参的目的,
但是有值得注意的是, arguements, 默认是以数组的形式传入的, 对于apply, 没啥问题,但是对于call , 可能就需要先解构了
var xw = {
name : "小王",
gender : "男",
age : 24,
say : function(school,grade) {
alert(this.name + " , " + this.gender + " ,今年" + this.age + " ,在" + school + "上" + grade);
}
}
var xh = {
name : "小红",
gender : "女",
age : 18
}
复制代码
可以看到say方法多了两个参数,我们通过call/apply的参数进行传参。
对于call来说是这样的
xw.say.call(xh,"实验小学","六年级");
复制代码
而对于apply来说是这样的
xw.say.apply(xh,["实验小学","六年级大学"]);
复制代码
看到区别了吗,call后面的参数与say方法中是一一对应的,而apply的第二个参数是一个数组,数组中的元素是和say方法中一一对应的,这就是两者最大的区别。
那么bind怎么传参呢?它可以像call那样传参。
xw.say.bind(xh,"实验小学","六年级")();
但是由于bind返回的仍然是一个函数,所以我们还可以在调用的时候再进行传参。
xw.say.bind(xh)("实验小学","六年级");
当然我们也可以使用apply的特性,达到意向不到的amaze效果;
apply
与 ...
的互用
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6的写法
function f(x, y, z) {
// ...
}
let args = [0, 1, 2];
f(...args);
扩展运算符的具体使用:
https://blog.csdn.net/ZHXT__/article/details/100764870
ES6原理详解
caller 与 callee
caller 属性
返回一个对函数的引用,即调用了当前函数的函数体。
functionName.caller :functionName 对象是所执行函数的名称。
对 于函数来说,caller 属性只有在函数执行时才有定义。 如果函数是由 JS 程序的顶层调用的,那么 caller 包含的就是 null 。
如果在字符串上下文中使用 caller 属性,那么结果和 functionName.toString 一样,也就是说,显示的是函数的反编译文本。
var a = function() {
alert(a.caller);
}
var b = function() {
a();
}
b(); // ƒ () { a();}
///
var a = function() {
alert(a.caller);
} ;
a() //null
caller返回一个函数的引用,这个函数调用了当前的函数。
使用这个属性要注意:
1 这个属性只有当函数在执行时才有用
2 如果在javascript程序中,函数是由顶层调用的,则返回null
说明
callee 属性的初始值就是正被执行的 Function 对象。
callee 属性是 arguments
对象的一个成员,它表示对函数对象本身的引用,
这有利于匿名 函数的递归或者保证函数的封装性,
例如下边示例的递归计算1到n的自然数之和。而该属性仅当相关函数正在执行时才可用。
还有需要注意的是callee拥有length属性,这个属性有时用于验证还是比较好的。arguments.length
是实参长度,arguments.callee.length
是形参长度,
由此可以判断调用时形参长度是否和实参长度一致
function factorial(num){
if(num<=1){
return 1;
}else{
return num*factorial(num-1);
}
}
//递归更加具有说明性
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
另一个具有迷惑性的例子
var a = function() {
console.log(arguments.callee);
}
var b = function() {
a();
}
b(); //ƒ () { console.log(arguments.callee); }
总之,
callee, 是 arguments的一个属性, arguments.callee 指向的是函数的本身,
caller ,是ES5中的, 返回一个函数的引用
这篇文章对caller与 callee讲解的更加透彻:
https://www.jianshu.com/p/e1542e09869a
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。