`

Javascript 中的Function, obj, prototype 和 __proto__

 
阅读更多

说到prototype,就不得不先说下new的过程。

我们先看看这样一段代码:

<script type="text/javascript">
var
Person = function () { };
var p = new Person();
</script>

很简单的一段代码,我们来看看这个new究竟做了什么?我们可以把new的过程拆分成以下三步:

<1> var p={}; 也就是说,初始化一个对象p。

<2> p.__proto__=Person.prototype;

<3> Person.call(p);也就是说构造p,也可以称之为初始化p。

关键在于第二步,我们来证明一下:

<script type="text/javascript">
var
Person = function () { };
var p = new Person();
alert(p.__proto__ === Person.prototype);
</script>
 

!注:__proto__这个属性只有在firefox或者chrome浏览器中才是公开允许访问的,因此,其他基于IE内核的浏览器是不会返回true的。


 

 

 

 

 

这段代码会返回true。说明我们步骤2的正确。

那么__proto__是什么?我们在这里简单地说下。每个对象都会在其内部初始化一个属性,就是__proto__,当 我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的 __proto__,于是就这样一直找下去,也就是我们平时所说的原型链的概念。

按照标准,__proto__是不对外公开的,也就是说是个私有属性,但是Firefox的引擎将他暴露了出来成为了一个共有的属性,我们可以对外访问和设置。

好,概念说清了,让我们看一下下面这些代码:

<script type="text/javascript">
var
Person = function () { };
Person.prototype.Say = function () {
alert("Person say");
}
var p = new Person();
p.Say();
</script>


 

这段代码很简单,相信每个人都这样写过,那就让我们看下为什么p可以访问Person的Say。

首先var p=new Person();可以得出p.__proto__=Person.prototype。那么当我们调用p.Say()时,首先p中没有Say这个属性, 于是,他就需要到他的__proto__中去找,也就是Person.prototype,而我们在上面定义了 Person.prototype.Say=function(){}; 于是,就找到了这个方法。

好,接下来,让我们看个更复杂的。

<script type="text/javascript">
var
Person = function () { };
Person.prototype.Say = function () {
alert("Person say");
}
Person.prototype.Salary = 50000;
var Programmer = function () { };
Programmer.prototype = new Person();
Programmer.prototype.WriteCode = function () {
alert("programmer writes code");
};
Programmer.prototype.Salary = 500;
var p = new Programmer();
p.Say();
p.WriteCode();
alert(p.Salary);
</script>

我们来做这样的推导:

var p=new Programmer()可以得出p.__proto__=Programmer.prototype;

而在上面我们指定了Programmer.prototype=new Person();我们来这样拆分,var p1=new Person();Programmer.prototype=p1;那么:

p1.__proto__=Person.prototype;

Programmer.prototype.__proto__=Person.prototype;

由根据上面得到p.__proto__=Programmer.prototype。可以得到p.__proto__.__proto__=Person.prototype。

好,算清楚了之后我们来看上面的结果,p.Say()。由于p没有Say这个属性,于是去p.__proto__,也就是 Programmer.prototype,也就是p1中去找,由于p1中也没有Say,那就去p.__proto__.__proto__,也就是 Person.prototype中去找,于是就找到了alert(“Person say”)的方法。

其余的也都是同样的道理。

这也就是原型链的实现原理。

最后,其实prototype只是一个假象,他在实现原型链中只是起到了一个辅助作用,换句话说,他只是在new的时候有着一定的价值,而原型链的本质,其实在于__proto__!

 

——————————————————————————————————————————————————————

以上涉及到一个概念—原型链,那么什么是原型链呢?

看下面代码及其注释便可了解。


首先声明:

Function和Object是js中的两个内置对象。js中包括Function在内的所有都是一个Object

Function 本身也是一个“类”,然而,所有“类”都是Funciton的实例,于是 Function instanceof Function; 为true。同时,所有对象都是 Object 类的实例,Object 本身也是一个对象,所有又有 Object instanceof Object 也为 true。另外,还可以认为 Funciton 类型是 Object   类型的一个“派生类”,class Function 继承了class Object ,是 class Object 的一个“子类”。看代码:

<script>
var Person = function () { };

 var p = new Person();

alert(p instanceof Object); //true
alert(Person instanceof Function); //true

</script>

 】

 

window.onload = function() { /* 每个对象实例都有个属性成员用于指向到它的instanceof 对象(暂称为父对象)的原型(prototype) 我们把这种层层指向父原型的关系称为[原型链 prototype chian] 原型也具有父原型,因为它往往也是一个对象实例,除非我们人为地去改变它 在JavaScript中,"一切都是对象,函数是第一型。" Function和Object都是函数的实例。 Function的父原型指向到Function的原型,Function.prototype的父原型是Object的原型 Object的父原型也指向到Function的原型,Object.prototype是所有父原型的顶层 在spiderMonkey引擎中,父原型可以通过 __proto__ 进行访问 大家在看的时候最后能反复的读几篇,能加深理解,尤其是原型,父原型,还有原型链的意思. * prototype 访问的是原型 * __proto__ 访问的父原型 * instanceof 原型链的父类 */ Function.prototype.hi = function(){alert('hi Function');} Object.prototype.hi = function(){alert('hi Object');} var a = function() { this.txt = 'a'; }; a.prototype = { say: function(){alert('a');} }; alert(a instanceof Function); //a是Function的实例; alert(a.__proto__ == = Function.prototype); //a的父原型指向到Function的原型; //a.__proto__父原型 Function //Function.prototype 父原型 Function alert(Function instanceof Object); //Function是Object的实例; alert(Function.__proto__ == = Function.prototype); //Function的父原型指向到Function的原型; alert(Function.prototype.__proto__ == = Object.prototype); //Function的原型的父原型指向到Object的原型 alert(Object.__proto__ == = Function.prototype); //Object的父原型指向到Function的原型; alert(Object.prototype.__proto__); //Object的原型是所有父原型的顶端,它不再具有父原型,所以结果为null; alert(a.prototype instanceof Object); //a的原型也是一个对象 alert(a.prototype.__proto__ == = Object.prototype); //a的原型的父原型指向Object的原型 };


 

 

以上代码描述的关系如下图所示:

 

定义:
1. constructor: Returns a reference to the Object function that created the instance's prototype.
2. instanceof: The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

__proto__和prototype的关系:
1. A function's .prototype is actually the prototype of things made by it, not its prototype.
2. __proto__ is the actual prototype, but don't use it.

JavaScript中class与instance的关系:

结构图
结构图
*************************************add*****************************************
   在js中,每个对象都有一个prototype属性:返回对象类型原型的引用。很拗口!习语“依葫芦画瓢”,这里的葫芦就是原型,那么“瓢.prototype” 返回的就是葫芦,或者“瓢.prototype= new 葫芦()”。

prototype的用途:

继承
有一个对象--子类:

function 子类() ...{
this.lastname = "Samuel";
}
有一个对象--父类:

function 父类() ...{
this.firstname = "Shen";
}
现在子类是有名无姓,父类是有姓无名,如果子类要有名有姓的话,只要说明--子类的原型是父类--就可以了,即子类继承自父类:

子类.prototype = new 父类();
至此,子类就不再是有名无姓了。

alert(子类.firstname + " " + 子类.lastname);    //Samuel Shen


牵一发而动全身
既然prototype返回的是原型的引用,那么如果改变原型的话,所有继承自该原型的对象都将受到影响。

    function Point(x,y)
    ...{
        this.x = x;
        this.y = y;
    }
    var p1 = new Point(1,2);
    var p2 = new Point(3,4);
    Point.prototype.z = 0; //动态为Point的原型添加了属性
    alert(p1.z);    //0
*********************************************************************************

函数:原型

每一个构造函数都有一个属性叫做原型(prototype,下面都不再翻译,使用其原文)。这个属性非常有用:为一个特定类声明通用的变量或者函数。

prototype的定义

你不需要显式地声明一个prototype属性,因为在每一个构造函数中都有它的存在。你可以看看下面的例子:

Example PT1

CODE:
function Test()
{
}
alert(Test.prototype); // 输出 "Object"

给prototype添加属性

就如你在上面所看到的,prototype是一个对象,因此,你能够给它添加属性。你添加给prototype的属性将会成为使用这个构造函数创建的对象的通用属性。

例如,我下面有一个数据类型Fish,我想让所有的鱼都有这些属性:livesIn="water"和price=20;为了实现这个,我可以给构造函数Fish的prototype添加那些属性。

Example PT2

CODE:
function Fish(name, color)
{
this.name=name;
this.color=color;
}
Fish.prototype.livesIn="water";
Fish.prototype.price=20;

接下来让我们作几条鱼:

CODE:
var fish1=new Fish("mackarel", "gray");
var fish2=new Fish("goldfish", "orange");
var fish3=new Fish("salmon", "white");

再来看看鱼都有哪些属性:

CODE:
for (int i=1; i<=3; i++)
{
var fish=eval_r("fish"+i);   // 我只是取得指向这条鱼的指针
alert(fish.name+","+fish.color+","+fish.livesIn+","+fish.price);
}

输出应该是:

CODE:
"mackarel, gray, water, 20"
"goldfish, orange, water, 20"
"salmon, white water, 20"

你看到所有的鱼都有属性livesIn和price,我们甚至都没有为每一条不同的鱼特别声明这些属性。这时因为当一个对象被创建时,这个构造函数 将会把它的属性prototype赋给新对象的内部属性__proto__。这个__proto__被这个对象用来查找它的属性。

你也可以通过prototype来给所有对象添加共用的函数。这有一个好处:你不需要每次在构造一个对象的时候创建并初始化这个函数。为了解释这一点,让我们重新来看Example DT9并使用prototype来重写它:

用prototype给对象添加函数

Example PT3

CODE:

function Employee(name, salary)
{
this.name=name;               
this.salary=salary;
}
Employee.prototype.getSalary=function getSalaryFunction()
{
return this.salary;
}

Employee.prototype.addSalary=function addSalaryFunction(addition)
{
this.salary=this.salary+addition;
}

 

我们可以象通常那样创建对象:

CODE:
var boss1=new Employee("Joan", 200000);
var boss2=new Employee("Kim", 100000);
var boss3=new Employee("Sam", 150000);

并验证它:

CODE:
alert(boss1.getSalary());   // 输出 200000
alert(boss2.getSalary());   // 输出 100000
alert(boss3.getSalary());   // 输出 150000

这里有一个图示来说明prototype是如何工作的。这个对象的每一个实例(boss1, boss2, boss3)都有一个内部属性叫做__proto__,这个属性指向了它的构造器(Employee)的属性prototype。当你执行 getSalary或者addSalary的时候,这个对象会在它的__proto__找到并执行这个代码。注意这点:这里并没有代码的复制(和 Example DT8的图表作一下对比)。

js的Prototype属性 <wbr>解释及常用方法

 

分享到:
评论

相关推荐

    JavaScript的prototype

    JavaScript中的`prototype`是一个核心概念,它涉及到对象继承和函数原型。在JavaScript中,每创建一个函数,该函数就会自动获得一个名为`prototype`的属性,这个属性是一个对象,用于实现对象间的继承。同时,每个...

    JavaScript中的prototype(原型)属性研究

    `__proto__`是一个非标准的属性,而`Object.getPrototypeOf`和`Object.setPrototypeOf`是ES5引入的标准方法,用于获取和设置一个对象的`[[Prototype]]`。 总结,JavaScript中的prototype属性是实现面向对象编程的...

    Js原型和原型链1

    在JavaScript中,每个对象还有一个隐藏的`__proto__`属性,它保存了父类的`prototype`。当创建一个新的对象,如`var obj = new f()`,`obj`的`__proto__`会被设置为`f`的`prototype`,从而建立起原型链。这个链允许...

    javaScript核心原理

    在这个例子中,`foo`对象有两个显式属性`x`和`y`,以及一个隐式的`__proto__`属性指向它的原型对象。 #### 原型链(Prototype Chain) **原型链**是一个由多个对象组成的链表,用于实现继承和共享属性。当查找一个...

    prototype 学习资料

    当我们调用一个对象的方法时,如果该方法在对象本身中没有找到,JavaScript会尝试在对象的`__proto__`链上查找,这个链的起点就是`prototype`对象。 ### 2. prototype对象的构造器 `prototype`对象有一个内置属性`...

    【JavaScript源代码】JavaScript 手动实现instanceof的方法.docx

    在JavaScript中,每个对象都有一个`__proto__`属性(在ES6中推荐使用`Object.getPrototypeOf`方法),这个属性指向创建该对象的构造函数的`prototype`。当调用`new`操作符创建一个新实例时,这个实例的`__proto__`就...

    Prototype Doc

    首先,原型在JavaScript中的核心是`__proto__`属性和`prototype`属性。每个函数(在JavaScript中,函数也是对象)都有一个`prototype`属性,这个属性是一个对象,用于创建该函数实例的原型。当尝试访问实例的一个...

    【JavaScript源代码】JavaScript中new操作符的原理示例详解.docx

    obj.__proto__ = Foo.prototype; ``` 3. **绑定`this`上下文**:构造函数内部的`this`关键字被指向新创建的空对象。这允许构造函数对新对象进行初始化。我们可以使用`call`或`apply`方法手动实现这一过程,如下所...

    javascript Object与Function使用.docx

    每个函数都有一个名为`prototype`的属性,而通过函数和`new`操作符创建的对象则具有一个`__proto__`属性,该属性指向创建该对象的构造函数的`prototype`属性。 **原型链结构**: ``` __proto__ foo ----------- Foo...

    【JavaScript源代码】JavaScript中实现new的两种方式引发的探究.docx

    - **设置原型链**:通过`obj.__proto__ = parent.prototype`将新对象的原型设置为构造函数的原型。 - **绑定`this`并执行构造函数**:通过`parent.apply(obj, rest)`调用构造函数,并确保`this`指向新创建的对象。 -...

    prototype 源码 注释

    console.log(obj.__proto__ === MyConstructor.prototype); // 输出:true ``` ### 4. `prototype.js`源码分析 ```javascript // 假设这是原型.js的一部分 function MyObject() {} // 添加一个属性到原型 My...

    prototype手册

    2. **原型链**:当试图访问一个对象的属性时,JavaScript会首先在当前对象中查找,如果找不到,则会沿着`__proto__`链接到其构造函数的原型,这一过程会一直持续,直到找到属性或者到达原型链的末端(通常是`null`)...

    JavaScript高级第02天笔记1

    总结来说,JavaScript的高级特性包括对象、构造函数、`this`、原型和`__proto__`。理解这些概念对于深入学习JavaScript至关重要,它们构成了JavaScript面向对象编程的基础。在实际开发中,合理利用这些特性可以构建...

    JavaScript学习笔记之创建对象_.docx

    JavaScript中的对象都有一个内置的`__proto__`属性,指向创建该对象的构造函数的原型。可以利用这个特性创建对象。不过现代JavaScript推荐使用`Object.getPrototypeOf`和`Object.setPrototypeOf`来操作原型链。 ...

    js遍历属性 以及 js prototype 和继承

    在JavaScript中,遍历属性、理解`prototype`和掌握继承机制是编程中不可或缺的基本技能。本文将深入探讨这些概念,并通过实例来加深理解。 首先,让我们来看如何遍历JavaScript对象的属性。JavaScript提供了多种...

    prototype的使用

    当我们创建一个函数(构造函数)时,该函数的`prototype`属性会自动被初始化为一个对象,这个对象有一个特殊的属性`__proto__`指向`Function.prototype`。我们可以直接在构造函数的`prototype`上添加方法或属性,...

    我所理解的从原型到原型链.pdf

    除了`prototype`之外,JavaScript中的每个对象还有一个`__proto__`属性。这个属性指向该对象的原型对象。当尝试访问一个对象的属性或方法时,如果该对象自身不具有此属性或方法,JavaScript引擎会沿着原型链向上查找...

    javascript原型继承工作原理和实例详解_.docx

    在JavaScript中,每个对象都有一个特殊的属性`__proto__`,这个属性指向该对象的原型对象。当我们试图访问一个对象的某个属性或方法时,如果该对象本身没有这个属性或方法,JavaScript引擎会沿着原型链向上查找,...

    JavaScript中的对象.zip

    JavaScript中的对象是编程的核心概念,它是语言特性和数据结构的基础。在JavaScript中,对象是一种复杂的数据结构,可以存储键值对,并且具有方法和属性。本文将深入探讨JavaScript对象的各个方面,包括创建、属性...

Global site tag (gtag.js) - Google Analytics