03月06, 2018

认识 JavaScript 的 prototype

认识 JavaScript 的 prototype

prototype

在Java里获取对象的实例一般是通过Class来获取,在ES6以前js中是没有class的概念,获取实例是通过构造方法来获取。

function ClassMate(name,age) {
    this.name = name;
    this.age = age;
    this.say = function (){
        return 'hello'
    }
}

let zhangsan = new ClassMate("张三",18);
console.log(zhangsan)
let lisi = new ClassMate("李四",20);
console.log(lisi)
console.log(zhangsan.say === lisi.say)//false

但是这样有一个缺陷,所有的实例对象都可以继承构造函数中的属性和方法。但是,同一个对象的不同实例之间,无法共享属性。这样是解决了属性和方法继承的问题,但是却没法实现java中静态属性这样的类变量。 prototype属性就是为了解决多个实例共享属性的问题。

function ClassMate(name,age) {
    this.name = name;
    this.age = age;
}
ClassMate.prototype.say = function (){
    return 'hello'
}

let zhangsan = new ClassMate("张三",18);
console.log(zhangsan)
let lisi = new ClassMate("李四",20);
console.log(lisi)
console.log(zhangsan.say === lisi.say)//true

从上可以看出,原型上的属性就类似其他语言中的静态属性在默认情况下只有Function对象才能直接调用prototype属性,但是所有的对象都有原型。普通对象可以通过Object.getPrototypeOf来获取其构造函数的原型。

function ClassMate(name,age) {
    this.name = name;
    this.age = age;
}
console.log(ClassMate.prototype.constructor == ClassMate)//true
console.log(ClassMate.prototype)//ClassMate {}
console.log(new ClassMate("张三",18).prototype)//undefined
console.log(ClassMate.prototype === Object.getPrototypeOf(new ClassMate("张三",18)))//true

函数的的prototype.constructor指向函数本身

prototype.__proto__属性

一个函数的的prototype属性对象中有一个__proto__属性,它指向这个函数原型的原型,也就是JavaScript中原型链prototype chains

function People() {

}
function ClassMate() {
    this.name = "张三";
    this.age = 18;
}
ClassMate.prototype= Object.create(People.prototype);

console.log(ClassMate.prototype.__proto__)//People {}
console.log(People.prototype.__proto__ === Object.prototype)//true

prototype chains原型链

上一节已经了解到了js中原型链的设计,这样设计的目的也是为了更好实现js中属性个方法的继承,原型链有如下特征:

  • a:读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype中找,如果最后还是找不到,则返回undefined。
  • b:如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。
  • c:一级级向上在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。 在网上找了几个图片来形象的表示原型链
function ClassA(name,age,sex) {
  this.name = name;
  this.age = age;
  this.sex = sex;
  this.say = function say() {
    console.log(`i am ${this.name}`)
  }
}
// 把需要共用的东西放到单独的对象里头
let proto = {
  sayHello: function () {
    console.log("i am prototype sayHello")
  }
};

ClassA.prototype = proto;


let zhangsan = new ClassA("张三",18,"男");
let lisi = new ClassA("李四",18,"女");

console.log(zhangsan.say === lisi.say);//false
console.log(zhangsan.sayHello === lisi.sayHello);//true
console.log(zhangsan.sayHello === lisi.sayHello && zhangsan.sayHello === proto.sayHello);//true

  1. Object的原型关系 alt
  2. Function的原型关系 alt

instanceof运算符

instanceof运算符返回一个布尔值,表示指定对象是否为某个构造函数的实例。所以对整个原型链上的对象都有效

function People() {

}

function ClassMate() {
    this.name = "张三";
    this.age = 18;
}


ClassMate.prototype= Object.create(People.prototype);

let classMate = new ClassMate();
console.log(classMate instanceof People)//true
console.log(classMate instanceof ClassMate)//true
console.log(classMate instanceof Object)//true

参考

https://www.cnblogs.com/DF-fzh/p/5619319.html http://www.jb51.net/article/91826.htm

本文链接:https://www.qiangshuidiyu.xin/post/js-prototype.html

-- EOF --

Comments