new 運算符建立一個用戶定義的對象類型的實例或具備構造函數的內置對象的實例數組
其實咱們瞭解了new的整個過程咱們是比較容易去實現一個new的 1.let obj = {} 或者 let obj = new object(); 二者等價 2.obj.proto = Func.prototype (Func爲構造函數) 3.經過apply改變this,以訪問函數內部變量 4.返回bash
function New() {
let obj = {}; // 建立對象
console.log(arguments);
let constructor = [].shift.call(arguments); // 獲取構造函數
console.log(arguments);
if (constructor.prototype !== null) {
obj.__proto__ = constructor.prototype; // 構造函數連接到新對象
}
let ret = constructor.apply(obj, [].slice.call(arguments)); // 改變this指向
console.log(arguments);
console.log(typeof ret);
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return obj; // 若是函數沒有返回對象類型Object(包含Functoin, Array, Date, RegExg, Error),那麼new表達式中的函數調用將返回該對象引用。
}
function name(a, b) {
this.a = a;
this.b = b;
}
let c = New(name, 1, 2)
let d = new name(1, 2)
console.log(c);
console.log(d);
複製代碼
咱們來看返回值:app
咱們看到New 和 new產生了一樣的效果函數
注意:[].shift.slice()會改變咱們的arguments。typeof null == "object"性能
重點:爲何要進行對象判斷,通常實現new時會把這一點的解釋給忽略。優化
默認狀況下函數的返回值爲undefined(即沒有顯示地定義返回值的話),可是構造函數比較例外,new構造函數在沒有return的狀況下默認返回新建立的對象。可是在有顯示返回值的狀況下,若是返回值爲基本數據類型的話(string,number,boolean,undefined,null),返回值仍然爲新建立的對象,這一點比較奇怪,須要注意。只有在顯示返回一個非基本數據類型的對象的時候,函數的返回值才爲指定的對象。在這種狀況下,this值所引用的對象就被丟棄了。ui
看下面兩個例子:this
例1: spa
例2: prototype
// return; // 返回 this
// return null; // 返回 this
// return this;
// return []; // 返回 []
// return function(){}; // 返回 這個 function,拋棄 this
// return false; // 返回 this
// return new Boolean( false); // 返回新 boolean;拋棄 this
// return 'hello world'; // 返回 this
// return new String( 'hello world'); // 返回 新建的 string,拋棄 this
// return 2; // 返回 this
// return new Number( 32); // 返回新的 number,拋棄 this
arguments 是一個對應於傳遞給函數的參數的類數組對象。
arguments 對象只能在函數內使用
將arguments轉換成數組
相似的轉換方法
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
// ES2015
const args = Array.from(arguments);
const args = [...arguments];
MDN上不建議咱們對參數進行slice 解決方案:
function New() {
let obj = {}; // 建立對象
console.log(arguments);
let constructor = [].shift.call(arguments); // 獲取構造函數
console.log(arguments);
if (constructor.prototype !== null) {
obj.__proto__ = constructor.prototype;
}
let ret = constructor.apply(obj, (arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments)));
console.log(ret);
console.log(arguments);
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return obj;
}
function name(a, b) {
this.a = a;
this.b = b;
}
let c = New(name, 1, 2)
let d = new name(1, 2)
console.log(c);
console.log(d);
複製代碼
對參數使用slice會阻止某些JavaScript引擎中的優化。若是你關心性能,嘗試經過遍歷arguments對象來構造一個新的數組。另外一種方法是使用被忽視的Array構造函數做爲一個函數
獲取arguments的第一個參數,改變arguments的length
返回一個新的數組,包含從 start 到 end (不包括該元素)的 arrayObject 中的元素。
.slice()方法
定義和用法 slice(start, end) 方法可提取數組的某個部分,並以新的數組返回被提取的部分。
使用start(包含) 和 end(不包含)
參數來指定提取數組開始和結束的部分。
若是未指定start和end,則返回整個數組。
若是指指定一個參數,該參數做爲start使用,返回包括start位置以後的所有數組。
若是是負數,則該參數規定的是從數組的尾部開始算起的位置。也就是說,-1 指數組的最後一項,-2 指倒數第二個項,以此類推。
改變[]中的this指向
改變this的指向
經過 apply指向 apply將構造函數的this指向新建立的對象
array.form() 或者 ... 或則遍歷
類數組對象的key值爲數字
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length; //this指向調用的對象,當用了call後,可以改變this的指向,也就是指向傳進來的對象,這是關鍵
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
複製代碼