1. 程式人生 > 其它 >【JS小知識】this的指向、工廠方法、建構函式及優化、prototype原型、forEach()的使用

【JS小知識】this的指向、工廠方法、建構函式及優化、prototype原型、forEach()的使用

技術標籤:JSjavascriptjs

/**
* 解析器在呼叫函式時,每次都會向函式內部傳遞一個隱含的引數
* 這個隱含的引數就是this,this指向的是一個物件,
* 這個物件我們稱為函式執行的上下文物件,
* 根據函式的呼叫方式的不同,this會指向不同的物件
* 1、以函式方式呼叫,this是window
* 2、以方法的形式呼叫時,this就是呼叫方法的那個物件
* 3、以建構函式的形式呼叫時,this是新建立的物件
* */

function func(){
	console.log(this.name);
}

// 建立一個物件
var obj = {
	name:"sun",
	sayName:func
};

var obj2 = {
	name:"zhu",
	sayName:func
};

var name = "全域性的name屬性";
//以函式方式呼叫,this是window
func(); 
//以方法的形式呼叫,this是呼叫方法的物件
obj.sayName();
obj2.sayName();

/**

* 由於普通建立多個物件時會佔用大量篇幅,而此類程式碼嗎是可以複用的,因此
* 使用工廠方法建立物件
* 通過該方法可以大批量的建立物件
* 使用工廠方法建立的物件,使用的建構函式都是Object
* 所以創造的物件都是objec型別
* 就導致我們無法區分出多種不同型別的物件
* */

普通建立與工廠方法建立物件對比如下所示:

// 普通建立物件
var obj01 = {
	name:"sun",
	age:28,
	gender:"男",
	sayName:function(){
		console.log(this.name);
	}
}

var obj02 = {
	name:"zhu",
	age:218,
	gender:"男",
	sayName:function(){
		console.log(this.name);
	}
}
var obj03 = {
	name:"sha",
	age:286,
	gender:"nv",
	sayName:function(){
		console.log(this.name);
	}
}

obj03.sayName();
// 使用工廠方法建立物件
function createPerson(name, age, gender){
	// 建立一個新的物件
	var obj = new Object();
	
	// 向物件中新增屬性
	obj.name = name;
	obj.age = age;
	obj.gender = gender;
	obj.sayName = function(){
		console.log(this.name);
	}
	
	return obj;
}

var sun = createPerson("sun", 28, "男");
var zhu = createPerson("豬", 28, "男");
var bai = createPerson("白", 228, "女");

bai.sayName();

/**
* 由於工廠方法每次都要建立一個新的物件,所以我們使用建構函式
* 建構函式
* 建立一個建構函式,專門用來建立Person物件的
* 建構函式就是一個普通的函式,建立方式和普通函式沒有區別,
* 不用的是建構函式習慣上首字母大寫
*
* 建構函式和普通函式的區別就是呼叫方式的不同
* 普通函式是直接呼叫,而建構函式需要使用new關鍵字來呼叫
*
* */

程式碼如下所示(分為加入形參與不加形參兩種):

function Person(){
	this.name = "hanzi";
	this.age = 18;
	this.sayName = function(){
		console.log(this.name);
	}
}

// 加入形參以能複用建構函式
function Person_New(name, age){
	this.name = name;
	this.age = age;
	this.sayName = function(){
		console.log(this.name);
	}
}

var per = new Person();
var per1 = new Person_New("卓", 888);
var per2 = new Person_New("卓", 888);

per.sayName();
per1.sayName();
per2.sayName();

// 使用instanceof 可以檢查一個物件是否是一個類的例項
// 語法:物件instanceof 建構函式,如果是,則返回true,否則返回false
console.log(per instanceof Person);
// 判斷兩個物件呼叫的方法是否一致,此處返回值應為false,因為每次呼叫方法都是建立新的物件
// 想要解決這種問題就要優化建構函式
console.log(per1.sayName == per2.sayName);

/**
* 優化建構函式
* 將function寫到建構函式的屬性中的時候,建構函式執行一次就會建立一個方法
* 執行1000次就會建立1000次的方法,但其作用是一樣的,
* 因此,我們將它寫到全域性中
*
* 但是!!!!將函式定義在全域性作用域,汙染了全域性作用域的名稱空間
* 而且定義在全域性作用域中也很不安全,所以使用prototype(原型)
* 將函式寫到建構函式的原型中,可以讓所有物件訪問到它
* */

function Person_New02(name, age){
	this.name = name;
	this.age = age;
	this.sayName = fun;
}

function fun(){
	console.log(this.name);
}

var per3 = new Person_New02("卓11", 888);
var per4 = new Person_New02("卓11", 888);

per3.sayName();
per4.sayName();
console.log(per3.sayName == per4.sayName);

/**
* prototype原型
* 我們所建立的每一個函式,解析器都會向函式中新增一個屬性prototype
* 這個屬性對應著一個物件,這個物件就是我們所謂的原型物件
* 如果函式作為普通函式呼叫prototype沒有任何作用
* 當函式通過以建構函式呼叫時, 他所建立的物件中都會有一個隱含的屬性指向該建構函式的原型物件
* 我們可以通過__proto__來訪問屬性
* 原型物件就相當於一個公共的區域,所有同一個類的例項都可以訪問到這個原型物件
* 我們可以將物件中共有的內容,統一設定到原型物件中
*
* 當我們訪問物件的一個屬性或者方法時,它會先在物件自身中尋找,如果有則直接使用
* 如果沒有則在物件的原型物件中尋找,如果有則直接使用
* 一直找到Object物件,若沒有則返回Undefined
*
* 以後我們建立建構函式時,可以將這些物件共有的屬性和方法,同一新增到建構函式的原型物件中,
* 這樣不用分別為每一個物件新增,也不會影響到全域性作用域就可以使每個物件都具有這些屬性和方法了
*
* */

function MyClass(){
	
}

// 向MyClass的原型中新增屬性a
MyClass.prototype.a = 123;

var myc = new MyClass();

console.log(myc.__proto__ == MyClass.prototype);
console.log(myc.a);

// 向myc中新增a屬性
myc.name = "我是myc中的name";
console.log(myc.name);

//向MyClass的原型中新增方法
MyClass.prototype.sayHello = function(){
	console.log("我是原型中的方法 ");
}
myc.sayHello();

// 可以使用hasOwnProperty()來檢查自身中是否含有該函式
console.log(myc.hasOwnProperty("name"));

/**
* forEach()方法需要一個函式作為引數
* 像這種函式,由我們建立但不由我們呼叫,我們稱為回撥函式
*
* */

//建立一個數組
var arr = ["孫悟空","豬八戒","白骨精","牛魔王"];

arr.forEach(function(value, index, obj){
	console.log(value);
});