摘要:是的幾乎是全部。語法和區別在里面的指向的不是事件的調用者,而是奇葩,而指向的事件調用者。舉例來說使用作為來調用面試題四明確綁定的優先權要高于隱含綁定綁定的優先級高于隱含綁定和不能同時使用,所以是不允許的,也就是不能直接對比測試綁定和明確綁定
ES5中this的指針
按照this指針的優先級,列出下面常會遇到的四種情況,從上到下依次是優先級從高到低(后面會詳細比較優先級)。
函數是和new一起被調用的嗎(new綁定)?如果是,this就是新構建的對象。
var bar = new foo()
函數是用call或apply被調用(明確綁定),甚至是隱藏在bind 硬綁定 之中嗎?如果是,this就是明確指定的對象。
var bar = foo.call( obj2 )
函數是用環境對象(也稱為擁有者或容器對象)被調用的嗎(隱含綁定)?如果是,this就是那個環境對象。
var bar = obj1.foo()
否則,使用默認的this(默認綁定)。如果在strict mode下,就是undefined,否則是global對象。 var bar = foo()
以上,就是理解對于普通的函數調用來說的this綁定規則所需的全部。是的···幾乎是全部。
apply、call、bind因為apply、call存在于Function.prototype中,所以每個方法都有這兩個屬性。
call
函數名.call(對象,arg1....argn) //功能: //1.調用函數 //2.將函數內部的this指向第一個參數的對象 //3.將第二個及以后所有的參數,作為實參傳遞給函數
apply
主要用途是直接用數組傳參
函數名.apply(對象, 數組/偽數組); //功能: //1.調用函數 //2.將函數內部的this指向第一個參數的對象 //3.將第二個參數中的數組(偽數組)中的元素,拆解開依次的傳遞給函數作為實參 //案例求數組中最大值 var a=Math.max.apply( null, [ 1, 2, 5, 3, 4 ] ); console.log(a);// 輸出:5
bind
是創建一個新的函數,我們必須要手動去調用:
var a ={ name : "Cherry", fn : function (a,b) { console.log( a + b) } } var b = a.fn; b.bind(a,1,2)() // 3
注意事項
call和apply功能幾乎一致,唯一的區別就是傳參的方式!!
2.call和apply的第一個參數如果為null或者undefined,那么this指向window
3.call和apply的第一個參數如果為值類型的數據,那么會將這個值類型的數據,轉換成其對應的引用類型的數據,然后再將this指向這個引用類型的數據
4.call和apply立即執行這個函數,bind方法可以讓對應的函數想什么時候調就什么時候調用,并且可以將參數在執行的時候添加,這是它們的區別,根據自己的實際情況來選擇使用。
5.當參數的個數確定的情況下可以使用call;當參數的個數不確定的情況下可以使用apply
JavaScript var array1 = [12 , "foo" , {name "Joe"} , -2458]; var array2 = ["Doe" , 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1 值為 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */call應用(將偽數組轉為數組)
var arrayLike = {0: "name", 1: "age", 2: "sex", length: 3 } Array.prototype.join.call(arrayLike, "&"); // name&age&sex Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"] // slice可以做到類數組轉數組 Array.prototype.map.call(arrayLike, function(item){ return item.toUpperCase(); }); // ["NAME", "AGE", "SEX"]call應用(判斷復雜數據類型)
console.log( Object.prototype.toString.call(num), Object.prototype.toString.call(str), Object.prototype.toString.call(bool), Object.prototype.toString.call(arr), Object.prototype.toString.call(json), Object.prototype.toString.call(func), Object.prototype.toString.call(und), Object.prototype.toString.call(nul), Object.prototype.toString.call(date), Object.prototype.toString.call(reg), Object.prototype.toString.call(error) ); // "[object Number]" "[object String]" "[object Boolean]" "[object Array]" "[object Object]" // "[object Function]" "[object Undefined]" "[object Null]" "[object Date]" "[object RegExp]" "[object Error]"bind在react中應用
下面的例子是來自react官網的案例
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; // This binding is necessary to make `this` work in the callback this.handleClick = this.handleClick.bind(this); } handleClick() { console.log(this); this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( ); } } ReactDOM.render(, document.getElementById("root") );
ES6中this的指向 箭頭函數this指向注意事項If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
箭頭函數體內的this對象,如果包裹在函數中就是函數調用時所在的對象,如果放在全局中就是指全局對象window。并且固定不會更改。換句話說內部的this就是外層代碼塊的this
下面是對比分析普通函數和箭頭函數中this區別
// 普通函數 function foo() { setTimeout(function() { console.log("id:", this.id); }); } var id = 21; foo.call({ id: 42 }); //21
// 箭頭函數 function foo() { setTimeout(() => { console.log("id:", this.id); }, 100); } var id = 21; foo.call({ id: 42 }); //42 // 上面的匿名函數定義時所在的執行環境就是foo函數,所以匿名函數內部的this執向始終會和foo函數的this執向保持一致,不會更改,如同下面的這個案例 function foo() { setTimeout(() => { console.log("id:", this.id); }, 100); } var id = 21; foo(); //21(沒有用call)
// ES5普通函數模擬上面es6函數的執行過程 function foo() { var _this = this; setTimeout(function () { console.log("id:", _this.id); }, 100); }
call的作用就是將foo函數的執行環境從window改成對象{id: 42}
定時器的作用就是延遲執行當前函數的外部執行環境,無論有沒有設置延遲時間
普通函數解釋:定義時this指向函數foo作用域,但是在定時器100毫秒之后執行函數時,此時this指向window對象
箭頭函數解釋:this始終指向定義時所在對象,也就是始終指向foo作用域
進一步分析this
var handler = { id: "123456", init: function() { document.addEventListener("click", event => this.doSomething(event.type), false); }, doSomething: function(type) { console.log("Handling " + type + " for " + this.id); } }; handler.init()// Handlingclickfor123456
箭頭函數的this始終指向handler,如果是普通函數,this指向document
this指向的固定化,并不是因為箭頭函數內部有綁定this的機制,實際原因是箭頭函數根本沒有自己的this,導致內部的this就是外層代碼塊的this。正是因為它沒有this,所以也就不能用作構造函數。
注意事項(綁定事件)在IE678里面不支持addEventListener和removeEventListener,而是支持attchEvent和detachEvent兩個方法。
語法:target.attachEvent(“on”+type, listener);
attachEvent和addEventListener區別:
在attchEvent里面的this指向的不是事件的調用者,而是window(奇葩),而addEventListener指向的事件調用者。
attachEvent的type一定要加上on,不然沒效果
面試題下面的面試題一、二、四都設計到引用問題,如果不是很好理解還可以理解成在 es5 中,永遠是this 永遠指向最后調用它的那個對象。摘錄鏈接
面試題一下面涉及指針應用還有綁定之類的概念來自You Dont Konw JS鏈接
this.x = 9; // this refers to global "window" object here in the browser var module = { x: 81, getX: function() { return this.x; } }; module.getX(); // 81 var retrieveX = module.getX; retrieveX(); // returns 9 - The function gets invoked at the global scope // Create a new function with "this" bound to module // New programmers might confuse the // global var x with module"s property x var boundGetX = retrieveX.bind(module); boundGetX(); // 81
retrieveX只是getX函數的引用,也就是只是getX的一個指針(getX的另一個指針是module.getX),所以retrieveX還是指向getX函數本身的
和上面類似的案例,下面的func只是函數引用,所以即使在函數內部,還是執行的函數本身,不受詞法作用域限制(箭頭函數則受限制)
document.getElementById( "div1" ).onclick = function(){ console.log( this.id );// 輸出: div1 var func = function(){ console.log ( this.id );// 輸出: undefined } func(); }; //修正后 document.getElementById( "div1" ).onclick = function(){ var func = function(){ console.log ( this.id );// 輸出: div1 } func.call(this); };
function foo() { console.log( this.a ); } var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3 (p.foo = o.foo)(); // 2面試題二
var A = function( name ){ this.name = name; }; var B = function(){ A.apply(this,arguments); }; B.prototype.getName = function(){ return this.name; }; var b=new B("sven"); console.log( b.getName() ); // 輸出: "sven"面試題三
確實,許多包中的函數,和許多在JavaScript語言以及宿主環境中的內建函數,都提供一個可選參數,通常稱為“環境(context)”,這種設計作為一種替代方案來確保你的回調函數使用特定的this而不必非得使用bind(..)。
舉例來說:
function foo(el) { console.log( el, this.id ); } var obj = { id: "awesome" }; // 使用`obj`作為`this`來調用`foo(..)` [1, 2, 3].forEach( foo, obj ); // 1 awesome 2 awesome 3 awesome面試題四
明確綁定 的優先權要高于 隱含綁定
function foo() { console.log( this.a ); } var obj1 = { a: 2, foo: foo }; var obj2 = { a: 3, foo: foo }; obj1.foo(); // 2 obj2.foo(); // 3 obj1.foo.call( obj2 ); // 3 obj2.foo.call( obj1 ); // 2
new綁定的優先級高于隱含綁定(new和call/apply不能同時使用,所以new foo.call(obj1)是不允許的,也就是不能直接對比測試 new綁定 和 明確綁定)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89426.html
摘要:獲取的對象范圍方法獲取的是最終應用在元素上的所有屬性對象即使沒有代碼,也會把默認的祖宗八代都顯示出來而只能獲取元素屬性中的樣式。因此對于一個光禿禿的元素,方法返回對象中屬性值如果有就是據我測試不同環境結果可能有差異而就是。 花了很長時間整理的前端面試資源,喜歡請大家不要吝嗇star~ 別只收藏,點個贊,點個star再走哈~ 持續更新中……,可以關注下github 項目地址 https:...
摘要:返回的綁定函數也能使用操作符創建對象這種行為就像把原函數當成構造器。同時,將第一個參數以外的其他參數,作為提供給原函數的預設參數,這也是基本的顆粒化基礎。 今天想談談一道前端面試題,我做面試官的時候經常喜歡用它來考察面試者的基礎是否扎實,以及邏輯、思維能力和臨場表現,題目是:模擬實現ES5中原生bind函數。也許這道題目已經不再新鮮,部分讀者也會有思路來解答。社區上關于原生bind的研...
摘要:返回的綁定函數也能使用操作符創建對象這種行為就像把原函數當成構造器。同時,將第一個參數以外的其他參數,作為提供給原函數的預設參數,這也是基本的顆粒化基礎。 今天想談談一道前端面試題,我做面試官的時候經常喜歡用它來考察面試者的基礎是否扎實,以及邏輯、思維能力和臨場表現,題目是:模擬實現ES5中原生bind函數。也許這道題目已經不再新鮮,部分讀者也會有思路來解答。社區上關于原生bind的研...
摘要:返回的綁定函數也能使用操作符創建對象這種行為就像把原函數當成構造器。同時,將第一個參數以外的其他參數,作為提供給原函數的預設參數,這也是基本的顆粒化基礎。 今天想談談一道前端面試題,我做面試官的時候經常喜歡用它來考察面試者的基礎是否扎實,以及邏輯、思維能力和臨場表現,題目是:模擬實現ES5中原生bind函數。也許這道題目已經不再新鮮,部分讀者也會有思路來解答。社區上關于原生bind的研...
摘要:事件中屬性等于。響應的狀態為或者。同步在上會產生頁面假死的問題。表示聲明的變量未初始化,轉換為數值時為。但并非所有瀏覽器都支持事件捕獲。它由兩部分構成函數,以及創建該函數的環境。 1 介紹JavaScript的基本數據類型Number、String 、Boolean 、Null、Undefined Object 是 JavaScript 中所有對象的父對象數據封裝類對象:Object、...
閱讀 1438·2021-09-22 15:43
閱讀 2154·2019-08-30 15:54
閱讀 1154·2019-08-30 10:51
閱讀 2082·2019-08-29 18:35
閱讀 426·2019-08-26 11:58
閱讀 2476·2019-08-26 11:38
閱讀 2432·2019-08-23 18:35
閱讀 3627·2019-08-23 18:33