原型和原型鏈

題目:javascript

  1.如何正確判斷一個變量是數組html

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

  3.描述 new 一個對象的過程jquery

知識點:數組

  構造函數函數

  構造函數-擴展this

  原型規則spa

  原型鏈prototype

  instanceofcode

 

建立對象的幾種方法:

  1. 字面量方法

    var o1 = {name:'o1'};

  2. new Object():

    var o2 = new Object({name:'o2'})

  3. 構造函數:

    var M = function(name){this.name = name};

    var o3 = new M('o3');

  4. Object.create():

    var f = {name: 'o4'};

    var o4 = Object.create(f);

構造函數

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

 

構造函數的擴展

  var a = {};其實就是 var a = new Object()的語法糖

  var a = []; 其實就是var a = new Array()語法糖

  function Foo(){...};其實就是 var Foo = new Function(){...}

 

原型規則

   1. 全部的引用類型(數組、對象、函數),都具備對象特性,能夠自由擴展屬性

var obj = {};obj.a = 100;
var arr =[];arr.a = 100;
function fn(){}; fn.a = 100;

   2. 全部的引用類型(數組、對象、函數),都有一個__proto__隱式原型屬性

var obj = {};obj.a = 100;
var arr =[];arr.a = 100;
function fn(){}; fn.a = 100;
		
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);

   3. 全部函數,都具備一個prototype顯示原型屬性

function fn(){}; fn.a = 100;
console.log(fn.prototype);

   4. 全部引用類型(數組、對象、函數)的__proto__屬性值 指向它的構造函數的 prototype屬性值

var obj = {};
var arr =[];
function fn(){};

console.log(obj.__proto__ === Object.prototype)//true
console.log(arr.__proto__ === Array.prototype)//true
console.log(fn.__proto__ === Function.prototype) //true

   5. 當獲取一個對象的某個屬性時,若是這個對象自己沒有這個屬性,那麼會去它的__proto__(即構造函數的prototype)中尋找

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

var f = new Foo('zhangsan');
f.printName = function(){
  console.log(this.name);  
}

f.printName();
f.alertName();//f自己沒有alertName,但Foo.prototype存在。因此能夠找到並執行

 

原型鏈

  簡單理解就是:原型對象組成的鏈,一直經過__proto__屬性向上找,直到找到Object的原型時結束:

function Foo(name,age){
    this.name = name;
}
Foo.prototype.alertName = function(){
    alert(this.name);
}
var f = new Foo('zhangsan');
f.printName = function(){
    console.log(this.name);
}
f.printName();
f.alertName();
f.toString();//要去f.__proto__.__proto__中查找

 以上面代碼爲例

 1. f沒有alertName方法,因此會去f.__proto__上去查找,由於f.__proto__ === Foo.prototype ,而Foo.prototype上有該方法。因此f.alertName()能夠找到並被執行

 2. f沒有toString方法,因此會先去f.__proto__上去查找,Foo.prototype上也沒有改方法;因此會繼續去f.__proto__.__proto__上去查找(f.__proto__.__proto__ === Foo.prototype.__proto__ === Object.prototype),即Object.prototype上查找,因此f.toString()能夠找到並執行

  3.Object.prototype也一樣有__proto__屬性,只不過有點特殊,爲null

  咱們把__proto__串聯起來,直到Object.prototype.__proto__爲止的鏈叫作原型鏈

 下面用一張圖來表示:

  

原型、實例、構造函數的關係?

  經過代碼來解釋

var M = function (name) { this.name = name; };
var o1 = new M('test'); console.log(M.prototype === o1.__proto__);//true console.log(M.prototype.constructor === M);//true

  1.實例是經過new 一個構造函數生成的,即代碼中 o1就是實例,M就是構造函數。

  2.構造函數的prototype屬性指向的是原型(或者說原型對象)。即代碼中 M.prototype === o1.__proto__

  3. 實例的__proto__屬性指向的也是原型(或者說原型對象)。即 代碼中 M.prototype === o1.__proto__

  4. 原型(或者說原型對象)對象的constructor指向的是構造函數。即代碼中 M.prototype.constructor === M

原型鏈繼承的例子

  題目二解答:寫一個原型鏈繼承的例子?

//封裝DOM查詢 相似jquery用法
function Elem(id){
	this.elem = document.getElementById(id);
}
//jquery中 html 方法
Elem.prototype.html = function(val){
	var elem = this.elem;
	if (val){ //設置html結構
		elem.innerHTML = val;
		return this; //鏈式操做
	}else{//獲取html結構
		return elem.innerHTML;
	}
}
//事件
Elem.prototype.on = function(type,fn){
	var elem = this.elem;
	elem.addEventListener(type,fn,false);
	return this; //鏈式調用
}

 

  調用:

var div1 = new Elem('div1')

div1.on('click',function(){
	alert('clicked');
})

div1.html('點擊');

console.log(div1.html());

  

 

instanceof 和 constructor

  檢測某個對象是否是另外一個對象的實例能夠用constructor 或者instanceof

  1. instanceof的原理是:判斷實例對象的__proto__和生成該實例的構造函數的prototype是否是引用的同一個地址(或者說是否是相等),若是是返回ture;若是是原型鏈上向上找的構造函數一樣返回true。

  經過代碼來解釋:    

var M = function (name) { this.name = name; };
var o1 = new M('test');
console.log(o1 instanceof M) //true
console.log(o1 instanceof Object) //true

    由於o1.__proto__ === M.prototype 因此 o1 instanceof M 返回爲true;

    由於 M.prototype.__proto__ === Object.prototype ,即Object是原型鏈上的構造函數,因此返回爲true.

  2. constructor是:判斷實例是由哪一個構造函數生成的。

  經過代碼來解釋:

var M = function (name) { this.name = name; };
var o1 = new M('test');
console.log(o1.__proto__.constructor === M) //true
console.log(o1.__proto__.constructor === Object) //false

 題目一解答:如何準確判斷一個變量是數組類型?

  用instanceof來判斷一個變量是不是數組,代碼示例:

var arr =[];
arr.instanceof Array //true;
typeof arr //object

  

new 運算符的原理

  當咱們new一個實例對象時,JS執行時在內部作了不少工做,下面用僞代碼模擬其工做流程:

new Foo('name') => {
    var obj = {}; //建立一個空對象
obj.__proto__ = Foo.prototype; //把obj的__proto__指向構造函數的原型對象(Foo.prototype),此時創建了obj的原型鏈 obj->Foo.prototype -> Object.prototype
   var result = Foo.call(obj,'name');//改變this指向 

  return typeof result === 'object'? result : obj //判斷result類型是否是對象,是返回result,不是返回obj
}

     1)建立一個空對象obj,該對象obj繼承構造函數的原型(Foo.prototype)

    2) 將這個空對象的__proto__指向構造函數Foo的原型對象

    3)構造函數Foo被執行,在執行的時候,相應的參數會被傳入,同時上下文(this)會被替換成obj

    4) 考察第三步的返回值result,若是無返回值或者返回一個非對象的值,則將obj做爲新對象返回;不然將result做爲新對象返回

  題目三解答:描述 new 一個對象的過程?

    1. 首先建立一個新對象{};

    2. 將構函數的做用域賦給新的對象向(所以 this指向了這個新建立的對象);

    3. 執行構造函數中的代碼(爲這個新對象添加屬性);

    4. 返回這個新對象

相關文章
相關標籤/搜索