1. 程式人生 > >JS基礎知識(一)原型和原型鏈

JS基礎知識(一)原型和原型鏈

原型和原型鏈

問題:

  1. 如何準確判斷一個變數是陣列型別

  2. 寫一個原型鏈繼承的例子

  3. 描述new 一個物件的過程

  4. Zepto(或其他框架)原始碼中如何使用原型鏈

     

知識點: 

1.建構函式

function Foo (name, age) {
	this.name = name;
	this.age = age;
	this.class = 'class-1';
}


Foo
/* ƒ Foo (name, age) {
	this.name = name;
	this.age = age;
	this.class = 'class-1';
} */
var f = new Foo('xiaoming', 12)

f
//Foo {name: "xiaoming", age: 12, class: "class-1"}

 建議建構函式的首字母用大寫便於閱讀。

建構函式會預設return this.

這裡講一下“var f = new Foo('xiaoming', 12)”也就是new一個物件的過程:

首先先傳入相應的引數在這個建構函式,然後其實先有一個this,為空物件,再將其進行賦值。像我們前一次講到的物件是屬於引用型別,引用型別可以無限的擴充套件屬性,這裡this.name,this.age都可以有點像那個無限擴充套件屬性,給他加上屬性,然後賦值,然後最後再返回一個return this。再將這個this傳回來,賦值給f.

2.建構函式--擴充套件

語法糖:

語法糖就是一種便捷寫法。在達到相同的目的情況下,更簡便的方法。

  1. var a ={} 其實是var a = new Object() 的語法糖
  2. var a = [] 其實是var a = new Array()的語法糖
  3. function Foo(){...} 其實是var Foo =new Function(..)
  4. 使用instanceof 判斷一個函式是否是一個變數的建構函式
     

對於一個變數的所有東西都有建構函式,物件,函式,陣列都是有建構函式的.

對於1,2,3都推薦前者,易讀且效能更好

//建構函式拓展
var a = {}

var b = []

function fn (){}

var a = new Object

var b = new Array

fn = new Function (...)

3.原型規則和示例

5條原型規則

原型規則是學習原型鏈的基礎
(1)所有的引用型別(陣列,物件,函式),都可以可自由擴充套件屬性(除了null除外)

(2)所有的引用型別(陣列,物件,函式),都有一個_proto_屬性(簡稱他隱式原型),屬性值是一個普通的物件。

(3)所有的函式,都有一個prototype(顯式原型)屬性,屬性值也是一個普通的物件

(4)所有的引用型別(陣列,物件,函式),_proto_屬性值指向它的建構函式”prototype ”的屬性值

(5) 當試圖得到一個物件的某個屬性時,如果這個物件本身沒有這個屬性,那麼會去它的_proto_(即它的建構函式的prototype)中尋找。

var obj = {}

obj.a = 100

obj.b = 'abc'

obj
//{a: 100, b: "abc"}

var arr = [1,2,3]

arr.a = 100

arr
//(3) [1, 2, 3, a: 100]

function fn () {}

fn.a = 100

fn.b =200
obj
//{a: 100, b: "abc"}
arr
//(3) [1, 2, 3, a: 100]
fn
//ƒ fn () {}
obj.__proto__
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
arr.__proto__
//[constructor: ƒ, concat: ƒ, find: ƒ, findIndex: ƒ, pop: ƒ, …]
fn.__proto__
//ƒ () { [native code] }
fn
//ƒ fn () {}
Object
//ƒ Object() { [native code] }
fn.prototype
//{constructor: ƒ}
Object.prototype
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
obj
//{a: 100, b: "abc"}
obj.__proto__
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
Object
//ƒ Object() { [native code] }
Object.prototype
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
obj.__proto__ === Object.prototype
//true

4.原型鏈

 以一個例子來具體來看:

f是 通過建構函式Foo new的一個物件,他有一個自己的方法printName。同時建構函式還增加了一個方法的alertName。

Foo像一個類,而f是他類別下面一個具體的例項。

類的方法他都有,例項還有自己單獨的方法。

function Foo(name,age){
	this.name = name;
}


Foo.prototype.alertName= function(){
	alert(this.name)
}

var f = new Foo('dd',13)

f.printName = function () {
	console.log(this.name)
}

f
//Foo {name: "dd", printName: ƒ}
f.printName()
//dd
f.alertName()

f.toString()
//"[object Object]"

f
//Foo {name: "dd", printName: ƒ}
f.__proto__
//{alertName: ƒ, constructor: ƒ}
Object
//ƒ Object() { [native code] }
Object.prototype
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
f.__proto__.__proto__
/*{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()*/

其中含有一個this,this要看具體的情形來判斷的,當比如說f.name這個this就是指向f. 

5.instanceof

用於判斷引用型別屬於哪個建構函式的方法

var arr = [1,2,3]

arr instanceof Array
//true
typeof arr
//"object"

問題解決:

  1. 如何準確判斷一個變數是陣列型別

    instanceof

  2. 寫一個原型鏈繼承的例子
     

    function Elem(id){
    	this.ele = document.getElementById(id);
    }
    
    Elem.prototype.html = function (value) {
    	var ele = this.ele;
    	if (value) {
    		ele.innerHTML = value;
    		return this;
    	}else {
    		return ele.innerHTML
    	}
    }
    
    Elem.prototype.on = function (type,fn) {
    	var ele = this.ele;
    	ele.addEventListener(type,fn);
    }
    
    
    var a = new Elem('article');
    a.on('click',function() {
    	alert('hello');
    });
    console.log(a.html());

    這裡的return this可以使得在後面呼叫時候,進行迴圈呼叫。

  3. 描述new 一個物件的過程
    先傳入相應的引數,也可以不傳,然後在建構函式裡面有一個this的空物件,對他進行擴充套件屬性賦值,再返回一個this。將他返回給那個物件。

  4. Zepto(或其他框架)原始碼中如何使用原型鏈
    可以自行去查詢相關資料看一下。