JS基礎知識(一)原型和原型鏈
原型和原型鏈
問題:
-
如何準確判斷一個變數是陣列型別
-
寫一個原型鏈繼承的例子
-
描述new 一個物件的過程
-
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.建構函式--擴充套件
語法糖:
語法糖就是一種便捷寫法。在達到相同的目的情況下,更簡便的方法。
- var a ={} 其實是var a = new Object() 的語法糖
- var a = [] 其實是var a = new Array()的語法糖
- function Foo(){...} 其實是var Foo =new Function(..)
- 使用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"
問題解決:
-
如何準確判斷一個變數是陣列型別
instanceof -
寫一個原型鏈繼承的例子
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可以使得在後面呼叫時候,進行迴圈呼叫。
-
描述new 一個物件的過程
先傳入相應的引數,也可以不傳,然後在建構函式裡面有一個this的空物件,對他進行擴充套件屬性賦值,再返回一個this。將他返回給那個物件。 -
Zepto(或其他框架)原始碼中如何使用原型鏈
可以自行去查詢相關資料看一下。