這篇文章帶給大家的內容是關於JavaScript原型和原型鏈的方法介紹(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
1、題目
如何準確判斷一個變數是數組
寫一個原型鏈繼承的範例
繼承實作的其他方式
es6 實作繼承的底層原理是什麼
描述new一個物件的過程
zepto及其他原始碼中如何使用原型鏈
#2.知識點
2.1 建構子
特點:以大寫字母開頭
function Foo(name,age){ //var obj = {} //this = {} this.name = name; this.age = age; this.class = 'class1' // return this } var f1 = new Foo('liming',19);
擴充
var o = {} 是var o = new Object() 的語法糖
var a = [] 是var a = new Array() 的語法糖
function Foo(){} 相當於var Foo = new Function(){}
2.2 原型規則
五條規則:
1.所有引用類型(對象,數組,函數)都具有物件特性,即可以自由擴展屬性
2.所有引用類型(對象,數組,函數)都具有一個__proto__(隱式原型)屬性,是一個普通對象
3.所有的函數都具有prototype(顯式原型)屬性,也是一個普通對象
4.所有引用類型(對象,數組,函數)__proto__值指向它構造函數的prototype
#5.當試圖得到一個物件的屬性時,如果變數本身沒有這個屬性,則會去他的__proto__中去找
for (var key in object) { //高级浏览器中已经屏蔽了来自原型的属性 //建议加上判断保证程序的健壮性 if (object.hasOwnProperty(key)) { console.log(object[key]); } }
2.3 原型鏈
obj.__ proto . proto . proto __ ...
Object.prototype === null
instanceof 用來判斷引用型別屬於哪個建構子
obj instanceob Foo
實際意義:判斷Foo.prototype 在不在obj的原型鏈上
3.題目解答
3.1 如何精確判斷一個變數是陣列
arr instanceof Array
3.2 寫一個原型鏈繼承的範例
封裝dom查詢
function Elem(id){ this.elem = document.getElementById(id); }; Elem.prototype.html = function(val){ var elem = this.elem; if (val) { elem.innerHTML = val; return this; }else{ return elem.innerHTML; } } Elem.prototype.on = function(type,fun){ var elem = this.elem; elem.addEventListener(type,fun); return this; } var p1 = new Elem('id1'); p1.html("test").on('click',function(){ console.log('点击'); })
3.3 繼承實作的其他方式
3.3.1 原型繼承
var obj = { 0:'a', 1:'b', arr:[1] } function Foo(arr2){ this.arr2 = [1] } Foo.prototype = obj; var foo1 = new Foo(); var foo2 = new Foo(); foo1.arr.push(2); foo1.arr2.push(2); console.log(foo2.arr); //[1,2] console.log(foo2.arr2); //[1]
優點:實作簡單
##缺點:1.無法向父類別建構子傳參2.同時new兩個物件時改變一個物件的原型中的參考類型的屬性時,另一個物件的該屬性也會修改。因為來自原型物件的引用屬性是所有實例共享的。 3.3.2 建構繼承function Super(b){ this.b = b; this.fun = function(){} } function Foo(a,b){ this.a = a; Super.call(this,b); } var foo1 = new Foo(1,2); console.log(foo1.b);
function Super(){ // 只在此处声明基本属性和引用属性 this.val = 1; this.arr = [1]; } // 在此处声明函数 Super.prototype.fun1 = function(){}; Super.prototype.fun2 = function(){}; //Super.prototype.fun3... function Sub(){ Super.call(this); // 核心 // ... } Sub.prototype = new Super();
function Super(b){ this.b = b; this.fun = function(){} } Super.prototype.c = function(){console.log(1111)} function Foo(a,b){ this.a = a; Super.call(this,b); } Foo.prototype = Super.prototype; //修复构造函数: var foo1 = new Foo(1,2);缺點:無法區分實例是父類別建立還是子類別所建立的3.3.4 寄生組合繼承
function Super(b){ this.b = b; } Super.prototype.c = function(){console.log(1111)} function Foo(a,b){ this.a = a; Super.call(this,b); } var f = new Function(); f.prototype = Super.prototype; Foo.prototype = new f(); //等同于 Foo.prototype = Object.create(Super.prototype); var foo1 = new Foo(1,2);
Foo.prototype.constructor = Foo這種解決方法不能用於上面的組合最佳化方法,因為子類父類引用的是同一個原型對象,修改會同時修改。 總結:繼承主要是實作子類別對父類別方法,屬性的複用。 來自原型物件的參考屬性是所有實例共享的,所以我們要避免從原型繼承屬性。 在建構子中透過call函數可以繼承父類別建構子的屬性和方法,但是透過這種方式實例化出來的實例會將父類別方法多次存儲,影響效能。 透過組合繼承我們使用call繼承屬性,使用原型繼承方法,可以解決以上兩個問題,但是透過這種方式實例化出來的物件會儲存兩份父類別建構子中的屬性。 用父類別的原型建構一個新物件作為子類別的原型,就解決了多次儲存的問題,所以最終的寄生組合繼承就是最佳繼承方式,它的缺點就是書寫起來比較麻煩。 3.3.6 node原始碼中的繼承實作
function inherits(ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); }; function Stream(){ //... } function OutgoingMessage() { Stream.call(this); //... } inherits(OutgoingMessage, Stream); OutgoingMessage.prototype.setTimeout = ...
ctor.prototype=Object.create(superCtor.prototype,{.....});該方法實際上就做了我們上面寄生組合繼承中的工作
var f = new Function(); f.prototype =superCtor.prototype; return new f();後面的參數是給原型對象添加屬性,可選屬性(非必填),即把自身作為新建立物件的建構子。
value: 表示constructor 的属性值; writable: 表示constructor 的属性值是否可写;[默认为: false] enumerable: 表示属性constructor 是否可以被枚举;[默认为: false] configurable: 表示属性constructor 是否可以被配置,例如 对obj.a做 delete操作是否允许;[默认为: false]3.4 es6繼承的實作方式參考我這篇文章:https://segmentfault.com/a/11...
创建一个对象
{}._proto_ = 构造函数.prototype
this指向这个对象
执行代码即对this赋值
返回this
var Zepto = (function(){ var $,zepto = {} // ...省略N行代码... $ = function(selector, context){ return zepto.init(selector, context) } zepto.init = function(selector, context) { var dom // 针对参数情况,分别对dom赋值 // 最终调用 zepto.Z 返回的数据 return zepto.Z(dom, selector) } fnction Z(dom, selector) { var i, len = dom ? dom.length : 0 for (i = 0; i < len; i++) this[i] = dom[i] this.length = len this.selector = selector || '' } zepto.Z = function(dom, selector) { return new Z(dom, selector) } $.fn = { // 里面有若干个工具函数 } zepto.Z.prototype = Z.prototype = $.fn // ...省略N行代码... return $ })() window.Zepto = Zepto window.$ === undefined && (window.$ = Zepto)
以上是JavaScript原型和原型鏈的方法介紹(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!