[进修笔记] JavaScript 原型

本日研讨了一下js的原型,把本身的明白写到这里,若有不正确的处所,还望指出,在此先谢过啦~

什么是原型?

原型是一个对象。统统对象都有原型。任何一个对象也都能够成为其他对象的原型。
每一个原型都有一个 constructor 属性指向其组织函数。

怎样接见原型?

一个对象的原型被对象内部的 [[Prototype]] 属性所持有。
一句话就是,统统对象都有原型,其原型是该对象的内部属性。那末有哪些要领能够接见到这个内部属性呢?

  • ECMAScript 5 增加了要领 Object.getPrototypeOf() ,用于返回对象 [[Prototype]] 的值。IE 9+、Firefox 3.5+、Safari 5+、Opera 12+ 和 Chrome 都完成了该要领。
  • 除了IE,其他浏览器都支撑非标准的接见器 __proto__
  • 假如这两者都不起作用,我们就需要经由过程对象的组织函数找它的原型属性了。
var a = {};
Object.getPrototypeOf(a);
a.__proto__;
a.constructor.prototype;

函数的 prototype 属性

不知亲方才有无注意到接见 [[Prototype]] 的末了一个要领 a.constructor.prototype; ,直接运用了组织函数的 prototype属性。

在这里要多说两句,js中函数也是对象,所以函数也有原型,其原型也和其他对象一样,能够经由过程 Object.getPrototypeOf()__proto__ 接见。然则建立对象时,我们每每要运用组织函数 (constructor) 的原型,为了用起来轻易,就给组织函数增加了 prototype 属性,用于直接接见其原型。由于统统的函数都能够成为组织函数,所以就作育了函数有那末一点点特(you)殊(shi)—— 一个函数能够经由过程其 prototype 属性直接接见其原型,或许说 一个函数的 prototype 属性指向其原型对象

假如仅仅只是由于一个实例而运用原型是没有多大意义的,这和直接增加属性到这个实例是一样的。原型真正魅力体现在多个实例共用一个原型,原型对象的属性一旦定义,就能够被多个援用它的实例所继承,这类操纵在机能和保护方面其意义是不言自明的。

这也是组织函数存在的缘由,组织函数供应了一种轻易的跨浏览器机制,这类机制许可在建立实例时为实例供应一个通用的原型。

原型语法

在运用原型前,先写一下组织函数部份。

function Calculator (decimalDigits, tax) {
    this.decimalDigits = decimalDigits;
    this.tax = tax;
};

分步声明

离开设置原型的每一个属性。

Calculator.prototype.add = function (x, y) {
    return x + y;
};

Calculator.prototype.subtract = function (x, y) {
    return x - y;
};

如许,在new Calculator对象今后,就能够挪用add要领来计算效果了。
此时, Calculator.prototypeconstructor 属性指向 Calculator。即:
Calculator.prototype.constructor = Calculator

更简朴的原型语法

经由过程给Calculator的prototype属性赋值对象字面量来设定Calculator对象的原型。

Calculator.prototype = {
    add: function (x, y) {
        return x + y;
    },

    subtract: function (x, y) {
        return x - y;
    }
};

上面的代码中,将 Calculator.prototype 赋值为一个以对象字面量情势建立的新对象。终究效果雷同,然则,此时 constructor 属性不再指向 Calculator ,即 Calculator.prototype.constructor != Calculator

每建立一个函数,就会同时建立它的 prototype 对象,这个对象会自动取得 constructor 属性。而我们这里运用的语法,本质上完整重写了默许的 prototype 对象,因而 constructor 属性也就变成了新对象的 constructor 属性 —— 指向 Object 组织函数。

假如 constructor 的值很主要,能够向下面一样设定:

Calculator.prototype = {

    constructor: Calculator, // 修复constructor 属性

    add: function (x, y) {
        return x + y;
    },

    subtract: function (x, y) {
        return x - y;
    }
};

其他体式格局

运用function马上实行的表达式来为prototype赋值,花样以下:

Calculator.prototype = function () {
    var add = function (x, y) {
        return x + y;
    },

    var subtract = function (x, y) {
        return x - y;
    }

    return {
        add: add,
        subtract: subtract
    }
} ();

原型的动态性

var friend = new Person();

Person.prototype.sayHi = function () {
    alert("hi");
};

friend.sayHi(); // "hi" (没有问题)

在以上代码中,纵然 friend 是在增加新要领之前建立的,但它依然能够接见这个新要领。其缘由能够归结为实例与原型之间的松懈衔接关联。当我们挪用 friend.sayHi() 时,会首先在实例中搜刮名为 sayHi 的属性,在没有找到的情况下,会继承搜刮原型。由于实例实例与原型之间衔接是一个指针,而非副本,因而能够在原型中找到新的 sayHi 属性并返回保留在那里的函数。

能够随时为原型增加属性和要领,而且修正能马上在统统对象实例中反应出来,但假如重写了原型对象,那效果就不一样了……

function Person () {
}

var friend = new Person();

Person.prototype = {
    constructor: Person,
    name: "Nicholas",
    age: 29,
    job: "software Engineer",
    sayHi: function () {
        alert("hi");
    }
};

friend.sayHi(); // error

在这个例子中,先建立了 friend 实例,然后又重写其原型对象。在挪用 friend.sayHi() 时发作毛病,由于friend 指向的原型中不包括以该名字定名的属性。

重写原型对象切断了现有原型与任何之前已存在的对象实例之间的联络,这些实例依然援用的是最初的原型。

统统都是对象

这部份与原型没什么大关联,只是看到了觉有协助,就插到这里了,莫要见责 :)

固然,也不是统统的都是对象,值范例就不是对象。

举个不太轻易明白的例子,函数作为对象时,其属性照样函数的例子。

var fn = function () {
    alert(100);
};

fn.a = 10;
fn.b = function () {
    alert(123);
};
fn.c = {
    name: "福布斯",
    year: 1968
};

上段代码中,函数就作为对象被赋值了a、b、c三个属性,第二个属性值就是函数,这个有用吗?
能够看看jQuery源码。

在jQuery源码中,“jQuery”或许“$”,这个变量实际上是一个函数,不信能够用 typeof 考证一下。

console.log(typeof $);  // function
console.log($.trim(" ABC "));

验明正身!的确是个函数。而常常运用的 $.trim() 也是个函数。

很明显,这就是在 $ 或许 jQuery 函数上加了一个 trim 属性,属性值是函数,作用是截取前后空格。要习气的把js中的统统看做对象,只如果对象,就是属性的鸠合,属性是键值对的情势。

参考资料

    原文作者:梦禅
    原文地址: https://segmentfault.com/a/1190000002867132
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞