本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
来自大一的学妹,刚进实验室,打算一步一步记录自己的学习总结。
“横看成岭侧成峰,远近高低各不同;不知庐山真面目,只缘身在此山中。” --不要以为看透了世界,我们身在世界,要不断探索知识,去无限接近构建出这个世界的模样
-
发现:同样的函数却不同的this
-
定义一个函数
-
function foo() { console.log(this); } -
调用函数三种方式
-
//1.直接调用/默认调用 foo(); //指向widows //2.通过对象调用 var obj = { name : "Hi" } obj.aaa = foo; obj.aaa(); //this指向obj对象 //3.通过call/apply调用 foo.call("abc"); //指向String{"abc"}对象
this指向
- 函数在调用时,JavaScript会默认给this绑定一个值
- this的绑定与定义的位置无关。
- this的绑定与调用方式以及调用的位置有关
- this是在运行时被绑定的。
this绑定规则(主要4则)
-
默认绑定
- 独立函数调用时,使用默认绑定。
- 独立函数调用:没有绑定到任何的对象上面.
-
//1.普通的函数独立调用 //2.函数定义在对象中,但是独立调用 foo(); //3.高阶函数 var obj = { bar: function() { console.log("bar:",this) } } function test(fn) { fn(); } test(obj.bar); //都是指向windows,因为只和调用位置有关 //3.严格模式下-- "use strict" //独立调用的函数this指向undefined
-
隐式绑定
- 它的调用位置中,是通过某个对象发起函数的调用(系统自动绑定对象)
- 在调用的对象内部有一个对函数的引用
-
//隐式绑定 function foo() { console.log("foo函数:",this) } var obj = { foo: foo } obj.foo()//this指向obj var bar = obj.foo;//只是引用了foo函数 bar(); //this指向windows对象,隐式绑定丢失
-
显式绑定
-
与隐式相对,执行函数,并且强制this指向obj对象
-
不希望对象内部包含该函数的引用&&又希望强制调用
-
var obj = { name: "why" } function foo() { console.log("foo函数:",this) } //call 明确地绑定 foo.call(obj) foo.call(123) foo.call("abc") /* {name: "why"} //如果传入基本类型,会返回包装类对象 Number{123} String{'abc'} */
-
-
使用call、apply(帮助绑定this对象)
-
//apply //第一行参数:绑定this【无区别】 //第二个参数:以数组形式传入额外的实参 foo.apply("apply".[30,"fish"]) //call //第一个参数:绑定this【无区别】 //参数列表:后续参数以多参数形式传递 foo.call("call",30,"fish")
-
-
使用bind【硬绑定】(调用某个函数总是绑定这个this对象)
- 使用bind方法,bind()方法创建一个绑定函数
-
var bar = foo.bind(obj)//新函数 bar()//this->obj //bind函数的其他参数 var bar = foo.bind(obj,arg1,arg2) bar(arg3)
-
-
new绑定
- JS中的函数可以当作一个构造函数来使用(使用new关键字)
- 创建新的空对象
- 将this指向这个空对象
- 执行函数体中的代码
- 没有显示返回其他对象时,默认返回这个新对象
-
function foo() { console.log(this) this.name = "why"//往空对象加东西 } new foo() /*this指向空对象 foo{name: 'why'} */
内置函数的调用绑定
- JS的内置函数,或者第三方库中的内置函数
- 这些函数会要求我们传入另外一个函数
- 我们不会显示的调用这些函数,而是JS内部或第三方库内部会帮助我们执行
this绑定规则优先级
-
默认绑定的优先级最低
-
显示绑定高于隐式绑定
-
var bar = foo.bind('aaa') var obj = { name: "why"; baz: bar } obj.baz()
-
-
new绑定优先级高于隐式绑定
-
var obj = { name: "why" foo: function() { console.log("foo:",this) console.log("foo:",this === obj) } } new obj.foo() /* foo{} false */
-
-
new绑定优先级高于bind
- new不可以和apply/call一起使用,可以和bind一起使用。
-
var bindFn = foo.bind("aaa") new bindFn() /* foo() */
-
bind优先级高于apply/call
-
var bindFn = foo.bind("aaa") bindFn.apply('bbb') //String{"aaa"}
-
new > bind > apply/call > 显式 > 隐式 > 默认
this规则之外
-
忽略显式绑定,使用默认规则
-
//特殊情况--没有包装类对象--指向windows foo.call(undefined) foo.apply(null) //指向windows //严格模式下-- //undefined /*严格模式下-- 显式绑定中的包装类型->基本数据类型 String{"abc"} abc */
-
-
隐式绑定丢失(解决方法)【用硬绑定】
-
function foo() { console.log(this.a); } var obj = { a:2 }; var bar = function(){ foo.call(obj); }; bar();//2 setTimeout(bar,100);//2 bar.call(window);//2 //硬绑定不能再修改它的this //因为硬绑定很常用,所以ES5提供了内置方法bind
-
-
间接函数引用,使用默认绑定规则
-
var obj1 = { name: 'obj1', foo: function() { console.log("foo:",this) } } var obj2 = { name: "obj2" };//{}紧接着(),要在之间加分号; (obj2.foo = obj1.foo)() //this指向windows
-
-
箭头函数arrow function
- 箭头函数不会绑定this、arguments属性
- 箭头函数不能作为构造函数来使用(不能和new一起使用)
-
//之前的方式 function foo1() {} var foo2 = function(name,age){ console.log("函数体代码") console.log(name, age) } //2.箭头函数 完整写法 var foo3 = (name,age) => { console.log("箭头函数的函数体") console.log(name,age) } //3.forEach和setTimeout //4.箭头函数简写 //-1.如果箭头函数只有一个参数,那么()可以省略 var newNums = nums.filter(item => { return item % 2 ===0 }) //-2.如果函数执行体只有一行代码,那么可以省略大括号 //并且这行代码的返回值会作为整个函数的返回值 names.forEach(item => console.log(item)) nums.filter(item => true) //-3.如果默认返回值是一个对象,那么这个对象必须加() //注意:在react中我会经常使用redux var arrFn = () => ({ name: "why"}) console.log(arrFn())
-
[练习]箭头函数实现nums的多有偶数平方和
-
var nums = [20, 30, 11, 15, 111] var result = nums.filter(item => item % 2 === 0) .map(item => item * item) .reduce((prevValue, item) => prevValue + item) //1300
-
-
箭头函数的this使用(没有绑定)
-
//1.普通函数中有this的标识符 //2.箭头函数中,没有this var bar = () => { var message = "hello" console.log("bar:",this) } bar.apply("aaa")//windows //3.this的查找原因 var obj = { name:"obj" foo:() => { var bar = ()=>{ console.log("bar",this) }//箭头函数没有this,于是去外层作用域找【是在定义的时候,的父级作用域】 return bar//作用域是代码块才有,不是对象 }//所以找到最后,找到全局作用域 } var fn = obj.foo() fn.apply("bbb")
-
-
箭头函数中this的应用