var obj = {} //obj的原型是Object.prototype
var a = ["hey", "you", "!"]; //a的原型为Array.prototype
var obj2 = new String("hey!") //obj2的原型是String.prototype
obj2.length //length是String.prototype的属性;通过原型,obj2也获得(继承)了这个属性
function Apple() {}
var obj3 = new Apple //obj3的原型是Apple.prototype
##创建对象
###使用字面表达式(literal)
var o = {a: 1};
//对象o的原型是Object.prototype;原型链如下:
// o ---> Object.prototype ---> null
var a = ["hey", "you", "!"];
//对象o的原型是Array.prototype;继承了indexOf、forEach等方法;原型链如下:
// a ---> Array.prototype ---> Object.prototype ---> null
function f(){
return "how u doing?";
}
//对象f的原型是Function.prototype;继承了call、bind等方法;原型链如下:
// f ---> Function.prototype ---> Object.prototype ---> null
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function() { //增加一个方法
console.log('hi');
}
var p = new Person();
//对象g有一个自有属性,name;p的原型是Person.prototype
var a = {a: 1};
//原型链为:a ---> Object.prototype ---> null
var b = Object.create(a);
//原型链为:b ---> a ---> Object.prototype ---> null
console.log(b.a); // 输出1,对象b的属性a继承自它的原型a
var d = Object.create(null);
//原型链为:d ---> null; 这种情况下b没有继承任何Object.prototype里的属性,比如hasOwnProperty
//假设原型链如下:o-->Apple.prototype-->...
o.__proto__ = obj1; //现在原型链为:o-->obj1-->...
Apple.prototype = obj2; //o的原型链保持不变,没有影响
var o2 = new Apple; //后续新建的对象o2的原型链为o2-->obj2-->...
###其他代码示例
function Foo() {};
( new Foo ).__proto__ === Foo.prototype //true, new Foo产生的新对象以Foo.prototype为原型
( new Foo ).prototype === undefined //true, 新对象并没有一个属性叫prototype
var o = Object.create(new Foo) //o的原型是new Foo返回的对象
Javascript中的对象和继承
最近要写一些Javascript代码,发现Javascript相比其它的面向对象语言有着很大的不同。C++、Java等以类为基础 的(class-based)面向对象语言是通过子类-父类来实现继承的概念。Javascript只有对象,并没有“类(class)” 的概念(Javascript保留了“class”关键字,但是并没有使用)。
##概述 Javascript中的对象(假设为o)除了自有的属性(own property)之外,还维护着一个“链接”,这个“链接”指向另一个对象; 这个对象称为对象o的原型(prototype)。o的原型对象中也有一个“链接”指向它自己的原型。这样就形成了一个原型 链(prototype chain)。原型链以null为结尾。
Javascript中的对象在访问一个属性时,首先在自有属性中查找。如果没有找到,则会沿着原型链依次查看原型链上的对象是否 有该属性,直至找到或者到达原型链的终点。所以,一个对象的属性集合也包括了它原型链上的所有对象的所有属性;也就可以 说一个Javascript对象“继承”了它的原型。
Javascript在创建一个对象时会指派这个新建对象的原型。如果我们在创建不同的对象时指派同一个原型对象,那么就可以 认为这些对象“继承”自同一个“父亲(原型对象)”。
##名词解释
###[[Prototype]] 有时候会在文档中看到[[Prototype]]。[[Prototype]]源自ECMAScript标准,仅仅是一个符号标识(pure notation), 表示对象的“原型”。它是一个名词,或者说是一个概念。某些对象,比如Object或Function,它们有一个属性叫prototype。引 入[[Prototype]]应该是为了在英语环境中区分“叫prototype的属性”和“名词prototype(原型)”。
###__proto__ 在具体的Javascript实现中,__proto__是对象的一个属性,通过它我们可以访问这个对象的原型([[Prototype]])。
实际上,对象的__proto__属性继承自Object.prototype。__proto__是Object.prototype对象上的一个 “存取属性”(accessor property,由一对getter和setter函数组成的属性)。因为几乎所有对象的原型链上都有 Object.prototype对象,所以自然每个对象也都继承__proto__属性。
obj.__proto__
的值视对象的创建方式而定,见 下文。要注意的是,不推荐使用__proto__,因为它已经被弃用了(deprecated)。如果要用__proto__的getter,推荐用
Object.getPrototypeOf
来代替。另外,不推荐修改一个对象的原型,不管是通过obj.__proto__ = sth_new
还是Object.setPrototypeOf
。修改对象原型在现代的Javascript实现上是一个非常慢的操作。通常,可以通过Object.create
在对象创建时指定新建对象的原型。###prototype属性 Object、Array、Date、String等内建对象都有一个属性叫prototype,比如Object.prototype,String.prototype。 用户定义的函数对象也会有一个prototype属性。当通过关键字
new
或者“字面表达式(literal)”的方式创建对象 时,Javascript会把相应对象的prototype属性设置为新建对象的原型,即new_obj.__proto__ === SomeObj.prototype
为 真。##创建对象
###使用字面表达式(literal)
###通过new关键字和构造函数 JavaScript中的“构造函数”只是普通的函数。当通过new关键字调用一个函数时,这个函数就可以叫做构造函数。
###通过Object.create 调用Object.create函数会创建一个新的对象。传入的第一个参数作为新建对象的原型。
##继承
###自有属性和覆盖 JavaScript对象有自有的属性(own properties),也有继承自原型的属性。当自有属性和继承来的属性同名时, 自有属性会覆盖继承来的属性。
通常,通过类似
o.e = 'hello'
的方式,对象会创建一个自有属性,无论原型链上是否已经存在一个同名的属性。 唯一的例外情况是,在原型链上存在一个同名的属性e
,且e
是一个存取属性(accessor property,有 getter和setter)。比如__proto__就是一个典型的存取属性,###this 对象调用继承来的函数时,this会指向当前的对象。
###一个例子 例子来自MDN。
##其它
###原型链对性能的影响 在原型链上查找属性会对性能产生一定的影响。特别是查找不存在的属性时,要遍历原型链上的所有属性后才会以失败中止。 另外,要遍历一个对象的属性也会遍历整个原型链上的所有属性。
如果仅仅需要查看自有属性,那么可以使用
hasOwnProperty
方法。这个方法是JavaScript中唯一不会检查原型 链上属性的处理函数。###preventExtensions 使用preventExtensions可以防止对象的__proto__被修改,见这里。
另外注意下面两种修改的不同,
###其他代码示例
###参考文档 Mozilla Developer Network(MDN)上有很多好的文档值得一看。比如,
MDN JavaScript Guide
Inheritance and the prototype chain
Object.prototype.__proto__
Object.prototype
Defining getters and setters
Stackoverflow上的一个回答
(测试环境:Chrome)
如果你觉得这篇文章对你有用,可以微信扫一扫表示🙏 / If you find this post is useful to you, buy me 🍶 via Wechat