springboot實戰電商項目mall4j (https://gitee.com/gz-yami/mall4j)
java商城系統源碼
JavaScript中的this綁定
在日常的開發中,我們會經常使用JavaScript中的一個關鍵字:this,在常見的編程語言中,幾乎都有this這個關鍵字,但是JavaScript中的this和常見的變成語言中的this不太一樣,
在常見的變成語言(java,c++等)中,this通常只會出現在類的方法中,而this指向它當前調用的對象,但是在JavaScript中,this是更加靈活的,無論是它出現的位置還是它代表的含義。
this全局作用下的指向
這個問題非常容易回答,在瀏覽器中,this的指向為全局對象window
console.log(this) // window 對象
var name = "hhf"
console.log(this.name) // hhf
console.log(window.name) // hhf
但是,開發中很少直接在全局作用於下去使用this,通常都是在函數中使用的
this到底指向什麼呢?
下面我們通過一段代碼,代碼中,我們定義一個函數,對他進行三種不同的方式進行調用,它產生了不同的結果
function foo() {
console.log(this)
}
foo() // window對象
const obj = {
name: "hhf",
foo: foo
}
obj.foo() // obj1
const obj2 = {}
foo.call(obj2) // obj2
從上面代碼運行的結果我們得出:
1.函數在調用時,JavaScript會默認給this綁定一個值;
2.this的綁定和定義的位置(編寫的位置)沒有關係;
3.this的綁定和調用方式以及調用的位置有關係;
4.this是在運行時被綁定的
在JavaScript中,this有四種綁定規則,分別是:
1.默認綁定
2.隱式綁定
3.顯式綁定
4.new綁定
下面我們分別對這四種綁定規則進行學習
默認綁定
默認綁定通常是在獨立函數進行調用時進行綁定,獨立函數調用我們可以理解成沒有被綁定到某個對象進行調用,默認綁定在瀏覽器中指向的是window,當為嚴格模式(use strict)的時候指向的是undefined
// 案例一
function foo() {
console.log(this)
}
foo() // window對象
// 案例二
function foo(fn) {
fn()
}
const obj = {
name: "hhf",
bar: function() {
console.log(this)
}
}
foo(obj.bar) // window
顯示綁定
顯示綁定通常是某個對象對它進行調用,通俗來講:誰調用就指向誰
function foo() {
console.log(this.name);
}
const obj = {
name: "hhf",
bar: foo
}
obj.bar() // hhf
隱示綁定的另一種情況:
當有多層對象嵌套調用某個函數的時候,如 對象.對象.函數 ,this 指向的是最後一層對象。
function foo() {
console.log(this.name);
}
const person = {
name: "person"
}
person.foo = foo
const obj = {
name: "hhf",
bar: foo,
person: person
}
obj.person.foo() // person
顯式綁定
在JavaScript中,所有的函數都可以使用call、apply、bind三個方法對函數的this進行綁定
使用方式的不同:call、apply在函數調用時對它進行調用,bind會返回一個新的函數
顯示綁定的用途: 防抖、節流等
call函數的使用
call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。
它接收的參數為:第一個為綁定的this,後面接上的為所調用的函數的參數
具體使用方法如下
// 基本使用
function foo() {
console.log(this.name);
}
const obj = {
name: "hhf"
}
foo.call(obj) // hhf
// 傳入參數
function foo(n, m) {
console.log(this.name);
console.log(n, m)
}
const obj = {
name: "hhf"
}
foo.call(obj, "n", "m") // hhf n m
apply函數的使用
apply方法的語法和作用與 call() 方法類似,只有一個區別,就是 call() 方法接受的是一個參數列表,而 apply() 方法接受的是一個包含多個參數的數組。
具體使用方法如下
function foo(n, m) {
console.log(this.name);
console.log(n, m)
}
const obj = {
name: "hhf"
}
foo.call(obj, ["n", "m"]) // hhf, n m
bind函數的使用
bind函數它所接收的參數和call函數一樣,但是它會返回一個新的函數,新的函數的this會指向傳入的對象
function foo(n, m) {
console.log(this.name);
console.log(n, m)
}
const obj = {
name: "hhf"
}
const newFoo = foo.bind(obj, "n", "m")
newFoo() // hhf n m
new 綁定
new是JavaScript中的一個關鍵字,當進行new操作調用函數時,會執行如下的操作
1.函數內部會創建一個新的對象
2.創建的對象的原型(__proto__)會指向函數的prototype
3.所創建的對象會綁定到該函數的this上
4.如果函數沒有其他返回值,會默認返回該對象
function Persion() {
console.log(this)
}
new Persion(); // Persion {}
規則優先級
上面我們學習了四種綁定規則,那麼我們可能會思考,如果一個函數在調用的時候使用了多種綁定規則,誰的優先級最高呢?
結果如下
1.默認規則的優先級最低p毫無疑問,默認規則的優先級是最低的,因為存在其他規則時,就會通過其他規則的方式來綁定this
2.顯示綁定優先級高於隱式綁定
function foo() {
console.log(this.name)
}
const obj1 = {
name: 'obj1',
foo: foo
}
const obj2 = {
name: 'obj2',
}
obj1.foo.call(obj2) // obj2
3.new綁定優先級高於隱式綁定
function foo() {
console.log(this)
}
const obj1 = {
name: 'obj1',
foo: foo
}
const obj2 = {
name: 'obj2',
}
new obj1.foo() // foo {}
4.new綁定優先級高於bind
new綁定和call、apply是不允許同時使用的,所以不存在誰的優先級更高
new綁定可以和bind一起使用,new綁定優先級更高p代碼測試
function foo() {
console.log(this)
}
const obj1 = {
name: 'obj1',
foo: foo
}
const newFoo = foo.bind(obj1)
new newFoo() // foo {}
箭頭函數的this
箭頭函數是ES6中新增的一種函數的寫法,但是箭頭函數是不綁定this的,當在箭頭函數中使用this時,它會隨着它的作用域網上找,使用最近的作用域的this來使用
// 使用普通函數
const obj1 = {
name: 'obj1',
foo: function() {
console.log(this)
}
}
obj1.foo() // obj1
// 使用箭頭函數
const obj1 = {
name: 'obj1',
foo: ()=> {
console.log(this)
}
}
obj1.foo() // window foo的上層作用域為window
// setTimeout所傳入的函數如果是普通函數,那麼它綁定的是全局對象window,如果傳入的是一個箭頭函數,那麼它的this執行是它的上層作用域的this指向
const obj1 = {
name: 'obj1',
bar: function() {
setTimeout(()=> {
console.log(this)
})
}
}
obj1.bar() // obj1
下面我們通過一道題,對剛剛所學的進行一個小練習
var name = "window"
function Person(name) {
this.name = name
this.obj = {
name: "obj",
foo1: function() {
return function() {
console.log(this.name)
}
},
foo2: function() {
return ()=>{
console.log(this.name)
}
}
}
}
var person1 = new Person("person1")
var person2 = new Person("person2")
person1.obj.foo1()()
person1.obj.foo1.call(person2)()
person1.obj.foo1().call(person2)
person1.obj.foo2()()
person1.obj.foo2.call(person2)()
person1.obj.foo2().call(person2)
輸出結果為
/*
window
window
person2
obj
person2
obj
*/
springboot實戰電商項目mall4j (https://gitee.com/gz-yami/mall4j)
java商城系統源碼