先貼出一個網上的例子:數組
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
var obj = New(A, 1, 2);
// equals to
var obj = new A(1, 2);複製代碼
是否是看的不是很明白呢??彆着急,我帶你一點點深刻!!bash
var name = 'globalName'; //定義一個全局name
var obj = {
name: 'objName'
}
var foo = {
name: 'fooName',
getName: function() {
return this.name;
}
}
console.log(foo.getName()) // fooName
console.log(foo.getName.apply(obj)); // objName
console.log(foo.getName.apply()) // globalName
console.log(foo.getName.apply(window)) // globalName
console.log(foo.getName()) // fooName
console.log(foo.getName.call(obj)); // objName
console.log(foo.getName.call()) // globalName
console.log(foo.getName.call(window)) // globalName
複製代碼
foo.getName()
//這裏foo調用本身的方法,返回自身name屬性值fooName,若是你們對於this指向還不清楚,請自行補課複製代碼
foo.getName.apply(obj)
//這裏經過使用apply方法切換getName函數執行的上下文環境,將this指向了obj,因此輸出了objName,有一種借殼生蛋的做用複製代碼
foo.getName.apply()
//這裏在調用apply並無傳入須要指向的參數,默認全局window對象複製代碼
foo.getName.apply(window)
//這裏顯示的傳入window對象,將this指向了window,輸出了globalName複製代碼
相信你們已經明白了apply的用法,call也是一樣的道理,這裏咱們只用到了apply和call方法的第一個參數,咱們再看看他們第一個參數後面的參數怎麼回事?app
經過apply和call實現數組追加:函數
var arr1 = [1,2,3,4];
Array.prototype.push.apply(arr1, [5,6,7]); //調用數組原型上的push方法,至關因而arr1借用了push方法實現尾部追加元素,第二個元素是以數組形式
console.log(arr1) //[1, 2, 3, 4, 5, 6, 7]複製代碼
var arr1 = [1,2,3,4];
Array.prototype.push.call(arr1,5,6,7); //而call方法是已參數列表形式傳入追加的元素
console.log(arr1) //[1, 2, 3, 4, 5, 6, 7]複製代碼
function createPerson(name,age,job) {
var obj = new Object(); //建立一個對象
obj.name = name; //給對象添加屬性 和方法
obj.age = age;
obj.job = job;
obj.sayName = function() {
console.log(this.name)
}
return obj; //返回這個對象
}
var person1 = createPerson("lili", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
console.log(person1 instanceof createPerson) //false
console.log(person2 instanceof createPerson) //false複製代碼
優勢:解決了建立多個對象的時候的重複代碼問題。ui
缺點:不能解決對象識別問題,也就是不知道一個對象的類型,上面的instanceof 說明問題。this
ECMAScript中的構造函數可用來建立特定類型的對象。像Object和Array這樣的原生構造函數,在運行時會自動出如今運行環境中,咱們能夠建立自定義的構造函數,從而定義自定義對象類型的屬性和方法。下面就是使用構造函數模式將前面的例子重寫以下:spa
function Person(name,age,job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name);
}
}
var person1 = new Person("lili", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
console.log(person1 instanceof Person); // true 這裏能夠判斷其屬於Person類型的實例對象了
console.log(person2 instanceof Person); // true複製代碼
咱們能夠注意到,Person()中的代碼除了與createPerson()中相同的部分外,還存在如下不一樣之處:prototype
注意: 經過new實例化的對象,咱們就能夠明確知道了其類型,code
要建立Person的新實例,必須使用new操做符,那麼new的過程當中都經歷了那幾個步驟呢:對象
咱們嘗試本身用代碼來實現一下new過程吧!!!
function New(Person,name,age,job) { //Person是上面那個構造函數
//1.建立一個對象,
var obj = {};
//2.將構造函數的做用域賦給新對象,所以this就指向了這個新對象,這裏咱們將obj的__proto__指向了Person的prototype,由於通用new出來的實例的__proto__屬性都指向構造函數的原型(prototype)
obj.__proto__ = Person.prototype;
//執行構造函數Person中的代碼,這裏經過apply將做用域切換爲當前obj,這裏的arguments是New方法傳入的參數,經過slice去掉第一個參數,傳入剩下的參數,
var ret = Person.apply(obj,Array.prototype.slice.call(arguments,1));
// 若是ret是對象或者是函數,就返回,若是不是就返回obj;
if((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
return ret;
}
return obj;
}
var o = New(Person,'jiji',1,'mother');
console.log(o)複製代碼
碼字不易,若是對你有幫助的話,不忙點個贊再走~~~~~