一、深入理解prototype, getPrototypeOf和_ proto _
prototype,getPropertyOf和 _ proto _ 是三個用來存取prototype的方法。它們的命名方式很類似因此很容易帶來困惑。
它們的使用方式如下:
- C.prototype: 一般用來為一個型別建立它的原型繼承物件。例如C.prototype = xxx,這樣就會讓使用new C()得到的物件的原型物件為xxx。當然使用obj.prototype也能夠得到obj的原型物件。
- getPropertyOf: Object.getPropertyOf(obj)是ES5中用來得到obj物件的原型物件的標準方法。
- _ proto _: obj._ proto _是一個非標準的用來得到obj物件的原型物件的方法。
為了充分了解取得原型的各種方式,以下是一個例子:
function User(name, passwordHash) { this.name = name; this.passwordHash = passwordHash; } User.prototype.toString = function() { return "[User " + this.name + "]"; }; User.prototype.checkPassword = function(password) { return hash(password) === this.passwordHash; }; var u = new User("sfalken", "0ef33ae791068ec64b502d6cb0191387");
User函數擁有一個預設的prototype屬性,該屬性的值是一個空物件。在以上的例子中,在prototype物件上新增了兩個方法,分別是toString和checkPassword。當呼叫User建構函數得到一個新的物件u時,它的原型物件會被自動賦值到User.prototype物件。即u.prototype === User.prototype會回傳true。
User函數,User.prototype,物件u之間的關係可以表示如下:
上圖中的箭頭表示的是繼承關係。當存取u物件的某些屬性時,會先嘗試讀取u物件上的屬性,如果u物件上並沒有這個屬性,就會尋找其原型物件。
例如當呼叫u.checkPassword()時,因為checkPassword定義在其原型物件上,所以在u物件上找不到該屬性,就在u的原型上查找,查找順序是u-> u.prototype (User.prototype)。
前面提到過,getPrototypeOf方法是ES5中用來得到某個物件的原型物件的標準方法。因此:
Object.getPrototypeOf(u) === User.prototype; // true
在某些環境中,同時提供了一個非標準的_ proto _ 屬性用來得到某個物件的原型物件。當環境不提供ES5的標準方法getPrototypeOf方法時,可以暫時使用該屬性作為替代。可以使用下面的程式碼測試環境中是否支援_ proto _:
u.__ proto __ === User.prototype; // true
所以在JavaScript中,類別的概念是由建構函式(User)和用於實例間共用方法的原型物件(User.prototype)共同完成的。 建構子中負責建構每個物件特有的屬性,例如上述範例中的name和password屬性。而其原型物件中負責存放所有物件共有的屬性,例如上述範例中的checkPassword和toString方法。就像下面這張圖所表示的:
二、取得物件優先使用Object.getPrototypeOf,而不是_ proto _
在ES5中引入了Object.getPrototypeOf作為取得物件原型物件的標準API。但是在許多執行環境中,也提供了一個特殊的_ proto _屬性來達到同樣的目的。
因為並不是所有的環境都提供了這個_ proto _屬性,且每個環境的實現方式各不相同,因此一些結果可能不一致,例如,對於擁有null原型的對象:
// 在某些环境中 var empty = Object.create(null); // object with no prototype "_proto _" in empty; // false (in some environments) // 在某些环境中 var empty = Object.create(null); // object with no prototype "_proto_" in empty; // true (in some environments)
所以當環境中支援Object.getPrototypeOf方法時,優先使用它。即使不支持,也可以為了實現一個:
if (typeof Object.getPrototypeOf === "undefined") { Object.getPrototypeOf = function(obj) { var t = typeof obj; if (!obj || (t !== "object" && t !== "function")) { throw new TypeError("not an object"); } return obj._proto_; }; }
上述代码首先会对当前环境进行检查,如果已经支持了Object.getPrototypeOf,就不会再重复定义。
三、绝不要修改_ proto _
和Object.getPrototypeOf相比,_ proto _的特殊之处还体现在它能够修改一个对象的原型继承链。因为它是一个属性,除了执行获取它的操作外,还能够对它进行设置。
但是,绝不要修改_ proto _。原因如下:
- 首先,最显而易见的原因就是便携性。因为不是所有的JavaScript执行环境都支持这一属性,所以使用了_ proto _ 之后,代码就不能在那些不支持_ proto _的环境中运行了。
- 其次,是性能上的考虑。现在的JavaScript引擎的实现都会针对对象属性的存取作出大量的优化,因为这些操作是最常用的。当修改了对象的_ proto _后,就相当于修改了对象的整个继承结构,这样做回导致很多优化都不再可用。
- 最后,最重要的原因是需要保证程序的可靠性。因为改变_ proto _属性后,对象的原型继承链也许会被完全地改变。当程序中有其他代码依赖于原来的继承链时,就会出现不可意料的错误。通常而言,原型继承链需要保持稳定。
当需要为一个新创建的对象赋予一个原型对象时,可以使用ES5提供的Object.create方法。对于未实现ES5标准的环境,可以给出来一个不依赖于_ proto _的Object.create方法的实现。
四、解决 _ proto _兼容问题, 让构造函数不再依赖new关键字
在将function当做构造函数使用时,需要确保该函数是通过new关键字进行调用的。
function User(name, passwordHash) { this.name = name; this.passwordHash = passwordHash; }
如果在调用上述构造函数时,忘记了使用new关键字,那么:
var u = User("baravelli", "d8b74df393528d51cd19980ae0aa028e"); u; // undefined this.name; // "baravelli" this.passwordHash; // "d8b74df393528d51cd19980ae0aa028e"
可以发现得到的u是undefined,而this.name以及this.passwordHash则被赋了值。但是这里的this指向的则是全局对象。
如果将构造函数声明为依赖于strict模式:
function User(name, passwordHash) { "use strict"; this.name = name; this.passwordHash = passwordHash; } var u = User("baravelli", "d8b74df393528d51cd19980ae0aa028e"); // error: this is undefined
那么在忘记使用new关键字的时候,在调用this.name= name的时候会抛出TypeError错误。这是因为在strict模式下,this的默认指向会被设置为undefined而不是全局对象。
那么,是否有种方法能够保证在调用一个函数时,无论使用了new关键字与否,该函数都能够被当做构造函数呢?下面的代码是一种实现方式,使用了instanceof操作:
function User(name, passwordHash) { if (!(this instanceof User)) { return new User(name, passwordHash); } this.name = name; this.passwordHash = passwordHash; } var x = User("baravelli", "d8b74df393528d51cd19980ae0aa028e"); var y = new User("baravelli", "d8b74df393528d51cd19980ae0aa028e"); x instanceof User; // true y instanceof User; // true
以上的if代码块就是用来处理没有使用new进行调用的情况的。当没有使用new时,this的指向并不是一个User的实例,而在使用了new关键字时,this的指向是一个User类型的实例。
另一个更加适合在ES5环境中使用的实现方式如下:
function User(name, passwordHash) { var self = this instanceof User ? this : Object.create(User.prototype); self.name = name; self.passwordHash = passwordHash; return self; }
Object.create方法是ES5提供的方法,它能够接受一个对象作为新创建对象的prototype。那么在非ES5环境中,就需要首先实现一个Object.create方法:
if (typeof Object.create === "undefined") { Object.create = function(prototype) { function C() { } C.prototype = prototype; return new C(); }; }
实际上,Object.create方法还有接受第二个参数的版本,第二个参数表示的是在新创建对象上赋予的一系列属性。
当上述的函数确实使用了new进行调用时,也能够正确地得到返回的新建对象。这得益于构造器覆盖模式(Constructor Override Pattern)。该模式的含义是:使用了new关键字的表达式的返回值能够被一个显式的return覆盖。正如以上代码中使用了return self来显式定义了返回值。
当然,以上的工作在某些情况下也不是必要的。但是,当一个函数是需要被当做构造函数进行调用时,必须对它进行说明,使用文档是一种方式,将函数的命名使用首字母大写的方式也是一种方式(基于JavaScript语言的一些约定俗成)。
以上就是针对javascript的prototype,getPrototypeOf和__proto__进行的深入学习,希望对大家的学习有所帮助。

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

WebStorm Mac版
好用的JavaScript開發工具

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。