Open fred-ye opened 6 years ago
这篇文章来自于我的博客, 后面会慢慢的把东西整理整理移到博客上去。
每个函数都有一个prototype属性,该属性指向一个对象。而该属性只有在该函数做为构造器时才会发生作用,当函数作为构造器时,通过new去创建对象, 对象的原型(内置的prototype属性)会指向构造器(函数)的prototype属性。对象会自动拥有这个对象的构造函数的prototype的成员属性和方法.
prototype
先看一个示例:
function P () { } typeof P.prototype; //"object" //prototype指向的是一个对象
我们来修改P的prototype属性.
var protoObj = { date: new Date(), say: function() { console.log('Hello World'); } } P.prototype = protoObj; var obj = new P(); obj.date; obj.say();
当我们将P作为构造器来创建obj时,obj就会拥有对P.prototype的访问权限。obj便可以将P.prototype对应的对象中的属性当作自己的属性来用。
P
obj
P.prototype
我们定义一个构造函数,包含属性和方法,代码如下:
function Person(name, age) { this.name = name; this.age = age; this.getName = function() { return this.name; }; }
这种方式,每次生成一个对象时会创建一个函数对象用来获取name属性 再看一种定义类的方式:
name
function getName() { return this.name; } function Person(name, age) { this.name = name; this.age = age; this.getName = getName; }
和上一种写法相比,我们只需要创建一次方法函数,在构造函数中引用它们。更优雅的写法如下,将方法挂到原型上。
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function() { return this.name; }
Person.prototype可以被Person的所有实例共享。JavaScript 允许在程序中的任何时候修改原型(prototype)中的一些东西,也就是说可以在运行时(runtime)给已存在的对象添加额外的方法。如给String添加一个方法来返回逆序的字符串。
Person.prototype
Person
String
var s = "Simon"; s.reversed(); // TypeError on line 1: s.reversed is not a function String.prototype.reversed = function() { var r = ""; for (var i = this.length - 1; i >= 0; i--) { r += this[i]; } return r; } s.reversed(); // nomiS
此部份参看这里
有以下代码:
function Gadget(name, color) { this.name = name; this.color = color; }
添加原型的两种方式:
Gadget.prototype.price = 100; Gadget.prototype.rating = 3;
Gadget.prototype = { price: 100, rating: 3 }
javascript中每个对象中并没有属于自己的原型副本,我们可以随时修改prototype属性,并且由同一构造器创建的所有对象的prototype属性都会同时改变
var newtoy = new Gadget('test', 'red');
当我们在调用对象的某个属性时,javascript引擎会查询该对象的所有属性,如果没有找到。则会去查询创建这个对象的构造器函数的原型newtoy.constructor.prototype,如果在原型中找到了这个属性,就使用该属性。
newtoy.constructor.prototype
hasOwnProperty(prop)
propertyIsEnumerable()
function Gadget(name, color) { this.name = name; this.coloe = color; this.getName = function() { return this.name; } } Gadget.prototype.price = 100; Gadget.prototype.rating = 3; var newtoy = new Gadget('webcam', 'black'); newtoy.propertyIsEnumerable('name'); //true; newtoy.propertyIsEnumerable('constructor'); //内建属性和方法通常是不可枚举的 newtoy.propertyIsEnumerable('price'); //false; 原型链中的属性也是不可枚举的
但是,newtoy.constructor.prototype.propertyIsEnumerable('price')返回的是true; 其它很好理解,因为price原本就在newtoy.constructor.prototype这个对象上。
newtoy.constructor.prototype.propertyIsEnumerable('price')
price
每一个对象都有一个isPrototypeOf方法,用来判断当前对象是否是另一个对象的原型。
isPrototypeOf
ES5中提供的获取某个对象的原型的方法。
var mokey = { hair: true, feeds: 'banana' } function Human(name) { this.name = name; } Human.prototype = mokey; var george = new Human('George'); Object.getPrototypeOf(george).feeds; // banana
对于另一部份实现了ES5的功能,但没有getPrototypeOf方法的浏览器,我们可以采用__proto__
getPrototypeOf
__proto__
采用原型来扩展内建对象
Array.prototype.inArray = function(data) { for (var i = 0, len = this.length; i < len; i ++) { if (this[i] == data) { return true; } } return false; }
var colors = ['red', 'green', 'blue']; colors.inArray('red');
* 字符串反转
String.prototype.reverse = function() { return Array.prototype.reverse.call(this.split('')).join(''); }
### `__proto__` 链接 (该属性非标准,先不做深入了解) `__proto__`和`prototype`不是等价的,`__proto__`是某个实例对象的属性,而`prototype`则是构造器的属性。当一个对象被创建时,它的`__proto__` 属性和内部属性[[Prototype]]指向了相同的对象 (也就是它的构造函数的prototype属性).
// 声明一个函数作为构造函数 function Employee() { / 初始化实例 / }
// 创建一个Employee实例 var fred = new Employee();
// 测试相等性 fred.proto === Employee.prototype; // true
### 原型的陷阱; 当我们对原型对象进行替换时,会触发原型链上的异常
function Dog() { this.tail = true; } var benji = new Dog(); var rusty = new Dog(); Dog.prototype.say = function() { return 'woof'; }
然后我们对`Dog`的原型进行如下替换:
Dog.prototype = { paws: 4, hair: true }
再来看原有对象:
typeof benji.paws; //undefined benji.say();// woof
之前创建的对象使用的是之前的`prototype`,我们来新建对象
var lucy = new Dog(); lucy.paws; //4 lucy.say;//undefined lucy.constructor//function Object() { [native code] } typeof lucy.proto.say; //undefined typeof lucy.proto.paws; //number
会发现,其`constructor`的指向都不对了,为此,我们需要重写`constructor`。
Dog.prototype.constructor = Dog;
这篇文章来自于我的博客, 后面会慢慢的把东西整理整理移到博客上去。
每个函数都有一个
prototype
属性,该属性指向一个对象。而该属性只有在该函数做为构造器时才会发生作用,当函数作为构造器时,通过new去创建对象, 对象的原型(内置的prototype属性)会指向构造器(函数)的prototype属性。对象会自动拥有这个对象的构造函数的prototype的成员属性和方法.先看一个示例:
我们来修改P的
prototype
属性.当我们将
P
作为构造器来创建obj
时,obj
就会拥有对P.prototype
的访问权限。obj
便可以将P.prototype
对应的对象中的属性当作自己的属性来用。将方法挂到类的原型上
我们定义一个构造函数,包含属性和方法,代码如下:
这种方式,每次生成一个对象时会创建一个函数对象用来获取
name
属性 再看一种定义类的方式:和上一种写法相比,我们只需要创建一次方法函数,在构造函数中引用它们。更优雅的写法如下,将方法挂到原型上。
Person.prototype
可以被Person
的所有实例共享。JavaScript 允许在程序中的任何时候修改原型(prototype)中的一些东西,也就是说可以在运行时(runtime)给已存在的对象添加额外的方法。如给String
添加一个方法来返回逆序的字符串。此部份参看这里
利用原型添加属性
有以下代码:
添加原型的两种方式:
原型的使用
javascript中每个对象中并没有属于自己的原型副本,我们可以随时修改prototype属性,并且由同一构造器创建的所有对象的prototype属性都会同时改变
自身属性和原型属性
当我们在调用对象的某个属性时,javascript引擎会查询该对象的所有属性,如果没有找到。则会去查询创建这个对象的构造器函数的原型
newtoy.constructor.prototype
,如果在原型中找到了这个属性,就使用该属性。hasOwnProperty(prop)
来判断一个属性是自身属性还是原型属性。propertyIsEnumerable()
来判断。ES5可以指定哪些属性可枚举。propertyIsEnumerable()
都会返回false,包括那些在for-in循环中可枚举的属性。但是,
newtoy.constructor.prototype.propertyIsEnumerable('price')
返回的是true; 其它很好理解,因为price
原本就在newtoy.constructor.prototype
这个对象上。isPrototypeOf()
每一个对象都有一个
isPrototypeOf
方法,用来判断当前对象是否是另一个对象的原型。getPrototypeOf()
ES5中提供的获取某个对象的原型的方法。
对于另一部份实现了ES5的功能,但没有
getPrototypeOf
方法的浏览器,我们可以采用__proto__
扩展内建对象
采用原型来扩展内建对象
var colors = ['red', 'green', 'blue']; colors.inArray('red');
String.prototype.reverse = function() { return Array.prototype.reverse.call(this.split('')).join(''); }
// 声明一个函数作为构造函数 function Employee() { / 初始化实例 / }
// 创建一个Employee实例 var fred = new Employee();
// 测试相等性 fred.proto === Employee.prototype; // true
function Dog() { this.tail = true; } var benji = new Dog(); var rusty = new Dog(); Dog.prototype.say = function() { return 'woof'; }
Dog.prototype = { paws: 4, hair: true }
typeof benji.paws; //undefined benji.say();// woof
var lucy = new Dog(); lucy.paws; //4 lucy.say;//undefined lucy.constructor//function Object() { [native code] } typeof lucy.proto.say; //undefined typeof lucy.proto.paws; //number
Dog.prototype.constructor = Dog;