在學習this的時候,看到了幾個方法call,apply和bind還有一個new 運算子,就學習了一下它們的概念和原理
Function.prototype.call()
function.call(thisArg,arg1,arg2…)
使用一個指定的this值 和單獨給出的一個或多個引數來呼叫函式,回傳值是呼叫有指定this值和引數的函式的結果
注意:
1.非嚴格模式下如果thisArg是null 或者是 undefined 則自動替換為全域物件
2.thisArg可以是基本資料型別,call會自動轉換為原始資料型別
// call的演示
var animals = [
{ species: 'Lion', name: 'King' },
{ species: 'Whale', name: 'Fail' }
];
for (var i = 0; i < animals.length;i++){
(function (i) {
this.point = function () {
console.log(`#${i}:${this.species}+${this.name}`)
}
}).call(animals[i],i)
}
//給陣列的每一項物件添加一個方法
原理
Function.prototype.myCall = function (context) {
/** 如果第一個引數傳入的是 null 或者是 undefined, 那么指向this指向 window/global */
/** 如果第一個引數傳入的不是null或者是undefined, 那么必須是一個物件 */
if (!context) {
//檢測一下全域物件是window還是global
context = typeof window === 'undefined' ? global : window;
}else{
context = Object(context)
}
context.fn = this; //this指向的是當前的函式(Function的實體)
let rest = [...arguments].slice(1);//獲取除了this指向物件以外的引數, 空陣列slice后回傳的仍然是空陣列
let result = context.fn(...rest); //隱式系結,當前函式的this指向了context.
delete context.fn; //消除副作用
return result; //回傳這個函式的回傳值
}
測驗
var foo = {
name: 'Selina'
}
var name = 'Chirs';
function bar(job, age) {
console.log(this.name);
console.log(job, age);
}
bar.myCall(foo, 'programmer', 20); //Selina, programmer , 20
bar.myCall(null, 'programmer', 20); //Chirs, programmer , 20
Function.prototype.apply()
function.apply(thisArg,[argsArray])
使用一個指定的this值 和一個陣列物件(或者是類陣列物件)來呼叫函式,非嚴格模式下如果thisArg是null 或者是 undefined 則自動替換為全域物件,回傳值是呼叫有指定this值和引數的函式的結果
// 使用apply將一個陣列的所有項 添加到另一個陣列中
let charArr = ['a','b','c']
let numArr = [1,2,3]
numArr.push.apply(numArr,charArr)
console.log(numArr) //[1 , 2 , 3 , 'a' , 'b' ,'c']
原理 跟call相似
Function.prototype.myApply = function(context,rest){
//接收兩個引數 一個是指定的呼叫物件 一個是陣列引數
if(!context){
//跟call一樣,如果第一個引數是null或者是undefined的情況,檢測一下全域物件
context = typeof window === undefined ? global : window
}else{
context = Object(context)
}
context.fn= this
let result;
if(rest === undefined || rest === null){
//第二個引數是undefined或者是null的話不能被...
result = context.fn(rest)
} else if (rest instanceof Object ){
result = context.fn(...rest)
}
delete context.fn //消除副作用
return result
}
測驗
//測驗代碼
var foo = {
name: 'Selina'
}
var name = 'Chirs';
function bar(job, age) {
console.log(this.name);
console.log(job, age);
}
bar.myApply(foo, ['programmer', 20]); //Selina programmer 20
bar.myApply(null, 'teacher', 25);
//瀏覽器環境: Chirs teacher 25; node 環境: undefined teacher 25
Function.prototype.bind()
function.bind(thisArg,arg1,arg2…)
bind 創建一個新的函式 而新函式的this被指定為bind的第一個引數,而其余的引數作為新函式的引數,回傳一個源函式的拷貝函式 并擁有指定的this值和引數
注意:
1.多次bind無效,只會系結在第一個上面
2.bind回傳的是源函式拷貝,所以呼叫bind的必須是一個函式
3.使用new呼叫bind回傳的函式的時候,this指向的是源函式建構式的實體
Function.prototype.myBind = function (thisArg,...rest) {
//如果呼叫者不是函式 報錯
if (typeof this !== 'function') throw new TypeError("invalid invoked!");
let self = this
//回傳源函式的拷貝函式
return function F(...args) {
console.log(this)
if(this instanceof F){
// 說明新回傳的物件被 new運算子呼叫 this指向那個建構式物件實體
return new self(...rest,...args)
// 就回傳源函式的建構式的實體
}
// 否則就呼叫那個函式
return self.apply(thisArg,[...rest,...args])
}
}
測驗
var name = 'window'
function fn(name) {
// console.log(this)
console.log(this.name)
console.log(name)
}
let obj = {
name:'obj'
}
let f= fn.myBind(obj)
f('小明') //obj 小明
let nF = new f('小白') // undefined 小白
new 運算子
new constructor[([arguments])]
constructor 一個指定實體的型別的類或者是函式
arguments 引數串列
new 運算子創建一個用戶定義的物件型別的實體或者是具有建構式內置物件的實體
new 關鍵字會進行以下操作
- 創建一個新的物件
- 將這個物件的__proto__指向該建構式的原型
- 將這個物件作為函式的this的背景關系
- 如果這個建構式沒回傳物件 則回傳這個新物件
function Person(name,age) {
this.name = name
this.age = age
}
let p = new Person('小明',23)
console.log(p) //Person { name: '小明', age: 23 }
原理
function myNew(fun, ...arg) {
// 創建一個新的物件
const result = {};
// 該物件的__proto__屬性指向該建構式的原型
result.__proto__ = fun.prototype
fun.prototype.constructor == fun
// 將執行背景關系(this)系結到新創建的物件中
const res = fun.apply(result, arg);
// 如果函式的回傳值是個物件
if(res&&res instanceof Object){
return res
}
//否則就回傳這個新創建的物件
return result;
}
測驗
function Person(name,age) {
this.name = name
this.age = age
}
let p = myNew(Person,'小明',22)
console.log(p) //Person { name: '小明', age: 22 }
function Person(name,age) {
this.name = name
this.age = age
return {}
}
let p = myNew(Person,'小明',22)
console.log(p) //{}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/279823.html
標籤:其他
上一篇:Webpack理論與實踐
下一篇:css重要標簽總結
