摘要:為什么用能夠動(dòng)態(tài)的取值,實(shí)現(xiàn)了隱式傳遞一個(gè)對(duì)象的引用上面的例子中想在中取的值用就能簡單搞定一定程度上實(shí)現(xiàn)了動(dòng)態(tài)取值這個(gè)就是綁定了,這個(gè)就是上下文對(duì)象也就是調(diào)用棧是什么始終是一個(gè)對(duì)象,函數(shù)在被調(diào)用時(shí)發(fā)生綁定,具體綁定了什么看調(diào)用的位置,有一定
this 為什么用this
this能夠動(dòng)態(tài)的取值,實(shí)現(xiàn)了隱式傳遞一個(gè)對(duì)象的引用
var obj = { a : { b : 2, c : function () { console.log(this.b); } } }
上面的例子中想在c中取b的值用this就能簡單搞定,一定程度上實(shí)現(xiàn)了動(dòng)態(tài)取值;obj.a.c(),這個(gè)this就是綁定了obj.a,這個(gè)就是上下文對(duì)象也就是調(diào)用棧
this是什么this始終是一個(gè)對(duì)象,函數(shù)在被調(diào)用時(shí)發(fā)生綁定,具體綁定了什么看調(diào)用的位置,有一定的綁定規(guī)則
綁定規(guī)則
默認(rèn)綁定
當(dāng)函數(shù)不帶任何修飾被調(diào)用時(shí),運(yùn)用默認(rèn)綁定,this就是window全局對(duì)象;但要注意的是在嚴(yán)格模式下,則不行,this會(huì)綁定成undefined
function f() { //"use strict" console.log(this.a); } var a = 123; f(); //123
function f() { "use strict" console.log(this.a); } var a = 123; f(); //報(bào)錯(cuò),undefined不能夠添加屬性
隱式綁定
當(dāng)上下文對(duì)象(調(diào)用棧)調(diào)用函數(shù)時(shí),會(huì)隱式綁定this,哪個(gè)對(duì)象調(diào)用就綁定誰
function f() { console.log(this.a); } var obj = { a : 123, b : f, } obj.b();
上面例子實(shí)際上就是this = obj,而不是this = obj.a
這是最簡單的,但是這種綁定常常會(huì)發(fā)生隱式丟失,而采用默認(rèn)綁定
function f() { console.log(this.a); } var obj = { a : 123, b : f, } var a = 345 var f1 = obj.b; //采取函數(shù)別名而發(fā)生了隱式丟失 f1(); //345,這等同于直接執(zhí)行了f函數(shù)
我的理解是函數(shù)取別名是最好賦值上下文對(duì)象,也就是調(diào)用棧(var f1 = b)
例如下面例子也是隱式丟失
function f() { console.log(this.a); } var obj = { a : 123, b : f, } function fn(f) { //等同于setTimeout(obj.b, 100) f(); } fn(obj.b);
要注意這種別名:
function f() { console.log(this.a); } var obj = {a : 1}; obj.fn = f; obj.fn()
實(shí)際上就是:
function f() { console.log(this.a); } var obj = { a : 1, fn : f, }; obj.fn()
顯示綁定
javascript提供了3種call,apply,bind;作用都是改變this的指向
call
可以填入多個(gè)參數(shù)
func.call(thisValue, arg1, arg2, arg3,...)
第一個(gè)參數(shù)是this要綁定的對(duì)象,若參數(shù)為空,undefined,null,則默認(rèn)綁定window;若參數(shù)為原始值,則this綁定對(duì)應(yīng)的包裝類對(duì)象
后面參數(shù)則是傳入func的參數(shù)
function f(n, m) { console.log(n, m, this.a); } var obj = {a : 1}; f.call(obj, 3, 4); //3 4 1
function f() { console.log(this); } f.call("123"); //String?{"123"}
apply
apply與call類似只是參數(shù)不同,就是將傳入原函數(shù)的參數(shù)變成數(shù)組形式
func.call(thisValue, [arg1, arg2, arg3,...])
apply與call可以這樣理解:就是thisValue借用func函數(shù)功能來實(shí)現(xiàn)效果
類似于thisValue.fn(arg1, arg2, arg3...)
利用這一特點(diǎn)可以實(shí)現(xiàn)有趣的效果
找數(shù)組中最大的數(shù)
var arr = [11, 2, 3, 4, 5]; var nmax = Math.max.apply(null, arr); //11
null的作用是因?yàn)橛貌坏絫his,用null代替,僅用后面的參數(shù),有柯里化的感覺
建議我們一般定義一個(gè)比null還空的空對(duì)象:var ? = Object.create(null)
將數(shù)組中的空元素變成undefined,這個(gè)樣就可遍歷了,其屬性描述的enumerable:true
var arr = [11, , 3, 4, 5]; var arr1 = Array.apply(null, arr); //[11, undefined, 3, 4, 5]
轉(zhuǎn)換類數(shù)組對(duì)象,利用Array的實(shí)例方法slice,前提是必須有l(wèi)ength屬性
var arr = Array.prototype.slice.apply({0 :1, 1 : 2, length : 3}); //[1, 2, empty] var arr = Array.prototype.slice.apply({0 :1}); //[] var arr = Array.prototype.slice.apply({length : 1}); //[empty]
bind
bind函數(shù)參數(shù)形式和call類似
func.bind(thisValue, arg1, arg2, arg3,...)
我對(duì)他的理解是對(duì)原函數(shù)進(jìn)行改造,生成自己的新函數(shù),主要改造就是this綁定成thisValue,并且可以固定部分參數(shù),當(dāng)然后面arg選填
類似于thisValue.fn
我們可以自定義一個(gè)簡單bind函數(shù):
function myBind(fn, obj) { return function () { fn.apply(obj, arguments); } } function f(n) { console.log(n + this.a) } var obj = {a : 1}; var bind = myBind(f, obj); bind(4); //5
原生態(tài)bind用法也類似
function f(n,m) { console.log(this.a + n + m); } var obj = {a : 1}; var bar = f.bind(obj, 2); bar(3); //6
注意點(diǎn)bind每次返回一個(gè)新函數(shù),在監(jiān)聽事件時(shí)要注意,不然romove不掉
element.addEventListener("click", o.m.bind(o)); element.removeEventListener("click", o.m.bind(o));
因?yàn)閛.m.bind(o)返回的時(shí)新函數(shù),所以remove的也不是開啟時(shí)的函數(shù)了
正確做法:添加一個(gè)值,記錄開啟時(shí)的函數(shù)
var listener = o.m.bind(o) element.addEventListener("click", listener); element.removeEventListener("click", listener);
有趣的地方:
利用call與bind實(shí)現(xiàn)原始方法
var slice = Function.prototype.call.bind(Array.prototype.slice); slice([1, 2, 3], 1); //[2, 3]
可以拆分bind看
Array.prototype.slice.Function.prototype.call([1, 2, 3], 1)
其中Function.prototype.call 就是call方法
Array.prototype.slice.call([1, 2, 3], 1)
拆分call
[1, 2, 3].Array.prototype.slice(1)
而Array.prototype.slice就是slice
所以
[1, 2, 3].slice(1)
個(gè)人理解可以看成,Array.prototype.slice實(shí)現(xiàn)了slice功能,F(xiàn)unction.prototype.call實(shí)現(xiàn)了arguments中this的綁定以及參數(shù)的帶入。所以函數(shù)最總調(diào)用時(shí)顯示:slice([1, 2, 3], 1);
同理
var push = Function.prototype.call.bind(Array.prototype.push); var pop = Function.prototype.call.bind(Array.prototype.pop);
同時(shí)bind也能被改寫
function f() { console.log(this.a); } var obj = { a : 123 }; var bind = Function.prototype.call.bind(Function.prototype.bind); bind(f, obj)() // 123
new的this綁定
當(dāng)用new來指向函數(shù)F時(shí),函數(shù)變成構(gòu)造函數(shù)F,this也會(huì)發(fā)生變化
this = Object.create(F.prototype)
具體new的功能可看我的new篇
new綁定 > 顯示綁定 > 隱式綁定 > 默認(rèn)綁定
隱式綁定與默認(rèn)綁定比較
function f() { console.log(this.a); } var obj = { a : 123, f : f, } var a = 456; obj.f(); // 123
obj.f()覆蓋了f(),因此隱式大于默認(rèn)
隱式綁定與顯示綁定比較
function f() { console.log(this.a); } var obj = { a : 123, f : f, } var obj1 = { a : 1123 } obj.f.call(obj1); //1123
由輸出結(jié)果可以看出:call綁定的obj1覆蓋了obj,所以顯示大于隱式
顯示綁定與new綁定
function f(n) { this.a = n; console.log(this); } var obj = { b : 2}; var bar = f.bind(obj); console.log(bar(2)); console.log(new bar(2)); //{b:2,a:2} //undfined //{a: 2} //{a: 2}
由輸出結(jié)果可以看出:new bar(2),{a:2}說明是新生成的空對(duì)象,添加了a的屬性,其次輸出兩個(gè)說明函數(shù)返回了一個(gè)this對(duì)象也就是{a:2},而不是undefined
所以new大于顯示
注意多層this*
var obj = { f: function () { console.log(this); var f1 = function () { //console.log(this); }(); } } obj.f(); //{f:func} //winodw
因?yàn)閭鹘y(tǒng)的this沒有繼承機(jī)制,所以這個(gè)匿名函數(shù)的this沒有任何修飾,采取默認(rèn)綁定
有兩種方法解決
var obj = { f: function () { var self= this console.log(self); var f1 = function () { //console.log(self); }(); } } obj.f(); //{f:func} //{f:func}
var obj = { f: function () { console.log(this); return () => { console.log(this); }; } } obj.f()(); //{f:func} //{f:func}
注意處理數(shù)組時(shí)使用this
var obj = { a : 123, arr : [1, 2, 3], f : function () { this.arr.forEach(function (elem) { console.log(this.a, elem); }); } } var a = "this是window"; obj.f(); //this是window 1 //this是window 2 //this是window 3
forEach中的this指向的是window
解決辦法:
var obj = { a : 123, arr : [1, 2, 3], f : function () { this.arr.forEach(function (elem) { console.log(this.a, elem); },this); } } var a = "this是window"; obj.f(); //123 1 //123 2 //123 3
還有一種就是賦值給一個(gè)變量self暫時(shí)保存,給遍歷時(shí)用,如同上面的self
注意回調(diào)函數(shù)中的this
var obj = new Object(); obj.f = function () { console.log(this === obj); } $("#button").on("click", obj.f); //false
this指向的是DOM對(duì)象而不是obj,這個(gè)有點(diǎn)難以察覺,需要注意
解決辦法:硬綁定obj對(duì)象
var obj = new Object(); obj.f = function () { console.log(this === obj); } function fn(){ obj.f.apply(obj); } $("#button").on("click", fn); //true //$("#button").on("click", o.f.bind(obj)); //true
上面的硬綁定相當(dāng)于固定了this的對(duì)象,不會(huì)變了。
我們可以做個(gè)軟綁定
if(!Function.prototype.sorfBind) { Function.prototype.sorfBind = function (obj) { //這個(gè)this:執(zhí)行sorfBind時(shí)的調(diào)用位置綁定的this var fn = this; var arg1 = [].slice.call(arguments, 1); var bound = function() { //這個(gè)this:執(zhí)行bound時(shí)綁定的this return fn.apply( //arg1.concat.call(arg1, arguments 作用是整合兩次執(zhí)行傳入的參數(shù) //(!this || this === (window || global)) 猜測(cè)是為了在嚴(yán)格模式下也試用 (!this || this === (window || global)) ? obj : this, arg1.concat.call(arg1, arguments) //arguments是bound函數(shù)執(zhí)行時(shí)參數(shù)的參數(shù), ); }; bound.prototype = Object.create(fn.prototype); return bound; } } function f() { console.log("name: " + this.name); } var obj = {name : "obj"}, obj1 = {name : "obj1"}, obj2 = {name : "obj2"}; var fObj = f.sorfBind(obj); fObj(); //name : obj obj1.foo = f.sorfBind(obj); obj1.foo(); //name : obj1 fObj.call(obj2); //name : obj2 setTimeout(obj1.foo, 10); //name : obj簡單談?wù)劶^函數(shù)對(duì)this的影響
初次綁定this后,箭頭函數(shù)內(nèi)部的this就固定了
function f() { return (b) => { console.log(this.a); } } var obj = {a : 1}; var obj1 = {a : 2}; var fn = f.call(obj); fn(); //1 fn.call(obj1); //1
與第一點(diǎn)類似,初次綁定后內(nèi)部this固定了也就有了繼承
function f() { setTimeout(() => { console.log(this.a); },10); } var obj = {a : 1}; f.call(obj); //1還有一點(diǎn),不建議使用的屬性也會(huì)改變this的指向
arguments.callee 也有改變this指向
function f() { console.log(this); if(this ==window) { arguments.callee(); } } f(); //window對(duì)象 //arguments對(duì)象
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/98163.html
摘要:命令作用作用是執(zhí)行構(gòu)造函數(shù),返回實(shí)例對(duì)象上面例子是自定義一個(gè)構(gòu)造函數(shù),其最大的特點(diǎn)就是首字母大寫,用執(zhí)行構(gòu)造函數(shù)其中,在的執(zhí)行下,代表了實(shí)例化后的對(duì)象,這個(gè)也就有屬性注意點(diǎn)如果不用執(zhí)行構(gòu)造函數(shù),那么指向的是全局有兩種方式可以避免內(nèi)部定義嚴(yán)格 new命令 new作用 作用是執(zhí)行構(gòu)造函數(shù),返回實(shí)例對(duì)象 function F() { this.name = object } var ...
摘要:原型要掌握這三者之間的關(guān)系,通過代碼例子記錄一下自身屬性的這里就是通過代碼看一下做了什么默認(rèn)情況下,將的所有屬性包括繼承的賦值給有什么東西呢自己的原型鏈,添加一個(gè)屬性,用來指明對(duì)象的誰構(gòu)造的自身全部屬性,這邊構(gòu)建一個(gè)空對(duì)象原型,所以沒有自有 原型 要掌握這三者之間的關(guān)系prototype,constructor,__proto__通過代碼例子記錄一下 function F() { ...
摘要:對(duì)象拷貝可遍歷屬性淺拷貝簡單的淺拷貝可以用,對(duì)存取器定義的對(duì)象也試用深拷貝屬性描述對(duì)象的拷貝這是個(gè)淺拷貝深拷貝不可遍歷屬性對(duì)象的拷貝例如拷貝獲得共同的原型,與是兄弟關(guān)系說明也繼承了原型,同級(jí)別簡潔化版 對(duì)象拷貝 可遍歷屬性 淺拷貝 if(typeof Object.prototype.copy != function) { Object.prototype.copy = fun...
摘要:它不區(qū)分該屬性是對(duì)象自身的屬性,還是繼承的屬性。那么我們要遍歷對(duì)象所有屬性,包括繼承以及不可遍歷的屬性,用加原型遍歷實(shí)現(xiàn)類似的用遞歸 Object靜態(tài)方法 Object自身方法,必須由Object調(diào)用,實(shí)例對(duì)象并不能調(diào)用 Object.getPrototypeOf() 作用是獲取目標(biāo)對(duì)象的原型 function F() {}; var obj = new F(); console.lo...
摘要:繼承是面向?qū)ο缶幊陶Z言中的一個(gè)重要的概念,繼承可以使得子類具有父類的屬性和方法或者重新定義追加屬性和方法等。但是在中沒有類的概念,是基于原型的語言,所以這就意味著對(duì)象可以直接從其他對(duì)象繼承。 繼承是面向?qū)ο缶幊陶Z言中的一個(gè)重要的概念,繼承可以使得子類具有父類的屬性和方法或者重新定義、追加屬性和方法等。但是在Javascript中沒有類的概念,是基于原型的語言,所以這就意味著對(duì)象可以直接...
摘要:在中,除了幾種原始類型外,其余皆為對(duì)象,,既然對(duì)象如此重要,那就列舉一下在中如何創(chuàng)建對(duì)象通過構(gòu)造函數(shù)創(chuàng)建對(duì)象實(shí)例對(duì)象字面量對(duì)象字面量是對(duì)象定義的一種簡寫形式,目的在于簡化創(chuàng)建包含大量屬性的對(duì)象的過程。 在Javascript中,除了幾種原始類型外,其余皆為對(duì)象(Object,Array ...),既然對(duì)象如此重要,那就列舉一下在Javascript中如何創(chuàng)建對(duì)象: 通過Object構(gòu)造...
閱讀 877·2021-11-12 10:36
閱讀 3477·2021-09-08 10:44
閱讀 2804·2019-08-30 11:08
閱讀 1464·2019-08-29 16:12
閱讀 2738·2019-08-29 12:24
閱讀 980·2019-08-26 10:14
閱讀 760·2019-08-23 18:32
閱讀 1242·2019-08-23 17:52