欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JS原型

程序员文章站 2022-06-12 20:45:01
...

原型(对象属性)

  • Javascript规定,每一个函数都有一个prototype对象属性,指向另一个对象(原型链上面的)。(prototype指向的是一个对象)
  • prototype(对象属性)的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变(公用)的属性和方法,直接定义在prototype对象属性上。
  • prototype就是调用构造函数所创建的那个实例对象的原型(proto)。(说明原型是相对的,讲谁是谁的原型)
  • prototype可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中
  • 摘自链接:https://www.jianshu.com/p/72156bc03ac1

给原型添加属性和方法

1、创建一个构造器函数

function Gadget(name,color){
  this.name = name;
  this.color = color;
  this.whatAreYou = function(){
    return 'I am a '+this.color+' ' + this.name;
  };
}

2、给原型添加方法与属性(给prototype指向的对象添加方法与属性,原型可以看成prototype指定的对象)

//原型是一个对象
//方法1
Gadget.prototype.price = 100;
100
Gadget.prototype.rating = 3;
3
Gadget.prototype.getInfo = function(){
  return 'Rating: '+this.rating+', price: '+this.price;
};
//方法2,如果不想将它们逐一添加到原型对象中去,可以用一个对象覆盖
Gadget.prototype = {
  price: 100,
    ration: 3
}

使用原型的方法与属性

原型是给它实例的对象提供支持的。使用原型先要实例对象,在由实例的对象调用。

var newtoy = new Gadget('webcam','black');
undefined
newtoy.whatAreYou();
"I am a black webcam"
newtoy.getInfo();
"Rating: undefined, price: 100"

​

可看newtoy不但能调用Gadget本身的this方法,还能调用Gadget的prototype内的方法。说明prototype(对象属性)的所有属性和方法,都会被构造函数的实例继承。两者最大的区别是实时性。

Gadget.gad = 'gadget';
"gadget"
newtoy.gad; //构造函数添加了 gad 属性,以前创建的对象无变化
undefined
Gadget.prototype.pro = 'prototype'; //原型中添加了新属性,以前创建的对象也可以访问。
"prototype"
newtoy.pro;
"prototype"

原型具有实时性,当原型修改后甚至会影响在修改之前就已经创建了的对象。

利用自身属性重写原型属性

当对象查找一个属性时,先是在自身属性中查找,如果没有找到在去原型链(prototype)查找。也就是说自身属性的优先级高于原型属性(当自身与原型有相同属性时,访问的是自身属性)

function Gadget(name){
  this.name = name;
}
undefined
Gadget.prototype.name = 'mirror';
"mirror"
var toy = new Gadget('camera');
undefined
toy.name; //访问的是自身的name属性
"camera"

constructor始终指向创建当前对象实例的(构造)函数,如 toy.constructor === Gadget。说明toy是由Gadget构造的。

X.hasOwnProperty('Y') 用来判断X对象是否有Y属性,当前对象不包括原型。

Gadget.hasOwnProperty('name'); 
true
toy.constructor.hasOwnProperty('name'); //这两个是等价的,因为toy.constructor就是Gadget
true

X.propertyIsEnumerable('Y')用来判断X对象的Y属性是否可以被枚举。

是X对象的内容,不包括原型。对于所有的原型属性都会返回false。同时数组的length属性和constructor也是返回false。

toy.constructor.prototype.propertyIsEnumerable('color');
true
//toy.constructor === Gadget 而 Gadget.prototype 也是在一个对象,而这个对象有color属性,返回true

使用fin in遍历时,会把原型的属性也遍历出来:

Gadget.prototype.color = 'red';
"red"
var toy = new Gadget();
undefined
for(var i in toy)
  console.log(i+':'+toy[i]);
age:12 debugger eval code:2:11
color:red //可见这个属性是原型里的

isPrototypeOf() 这个方法会告诉我们当前对象是否是另一个对象的原型

var monkey = {
  hair: true,
  feeds:'bananas',
  breathes:'air'
};
undefined
function Human(name){
  this.name = name;
}
undefined
Human.prototype = monkey;
Object { hair: true, feeds: "bananas", breathes: "air" }

var george = new Human('George');
undefined
monkey.isPrototypeOf(george);  //monkey是不是george的原型
true

Object.getPrototypeOf(x) 获取x的原型

Object.getPrototypeOf(george) === monkey;

true

神秘的__proto__链接

它会指向原型。指向的是一个对象。__proto__是某个实例对象的属性,而prototype则是属于构造器函数的属性。

function a1(){}
undefined
a1.prototype.a2 = 12;
12
var a3 = new a1();
Object {  }

a3.constructor.prototype === a1.prototype;
true
a3.__proto__ == a1.prototype;
true

扩展内建对象

给数组添加一个inArray函数,可以用来查看这个数组有没有特定的值。

Array.prototype.inArray = function (needle){
  for(var i = 0; i < this.length; i++){ //this指的就是当前数组
    if(this[i] === needle){
      return true;
    }
  }
  return false;
}
function inArray()

var a = [1,2,3,4,5];
Array(5) [ 1, 2, 3, 4, 5 ]

a.inArray(3);
true
a.inArray(10);
false

​

给String添加一个 reverse()方法。用于反转字符串。

String.prototype.reverse = function(){
  return Array.prototype.reverse.apply(this.split('')).join('');
}
function reverse()


'asdf'.reverse();
"fdsa"

在扩展内建对象的时候,首先应该先检查该方法是否已经存在。当方法存在的时候就就忘用原生方法。

if(typeof Array.prototype.reverse !== 'function'){
  console.log('对象不存在');
}

原型陷阱

function Dog(){}
undefined
Dog.prototype = {};
Object {  }

new Dog().constructor === Dog;
false

当我们重写某对象的prototype时,constructor属性会出错。

Dog.prototype.constructor = Dog //每次重写对象的prototype,都要手动修改constructor属性

function Dog()

 

new Dog().constructor.prototype === Dog.prototype;

true

 

相关标签: 原型