函数对象的prototype并不作用于原型链查找过程中
分类:巴黎人-前端

JS 中原型和原型链深入理解

2018/05/05 · JavaScript · 原型

原文出处: erdu   

首先要搞明白几个概念:

  1. 函数(function)
  2. 函数对象(function object)
  3. 本地对象(native object)
  4. 内置对象(build-in object)
  5. 宿主对象(host object)

大家好,我是IT修真院成都分院第7期的学员韩建名,一枚正直纯洁善良的WEB前端程序员。

一、构造函数

function Foo(name, age) {

    this.name = name;

    this.age = age;

    this.class = 'class-1';

    //return this;    //默认有这一行

}

var foo = new Foo('zhangsan', 20);    //创建一个构造函数Foo的对象

Javascript原型链和原型的一个误区,javascript原型误区

之前我对Javascript的原型链中, 原型继承与标识符查找有些迷惑,

如, 如下的代码:

复制代码 代码如下:

function Foo() {};
var foo = new Foo();
Foo.prototype.label = "laruence";
alert(foo.label); //output: laruence
alert(Foo.label);//output: undefined

今天看到了如下这个图:

图片 1

Javascript object layout
另外, 在Javascript Object Hierarchy看到:

The prototype is only used for properties inherited by objects/instances created by that function. The function itself does not use the associated prototype.

也就是说, 函数对象的prototype并不作用于原型链查找过程中,

今天在firefox下发现(因为firefox通过__proto__暴露了[[prototype]]), 真正参与标识符查找的是函数对象的__proto__,

复制代码 代码如下:

function Foo() {};
var foo = new Foo();
Foo.__proto__.label = "laruence";
alert(Foo.label); //output: laruence
alert(foo.label);//output: undefined

而, 显然的:

复制代码 代码如下:

function Foo() {};
alert(Foo.__proto__ === Foo.prototype); //output: false

另外, 也解释了,

复制代码 代码如下:

alert(Object.forEach); // undefined
 
Function.prototype.forEach = function(object, block, context) {
    for (var key in object) {
        if (typeof this.prototype[key] == "undefined") {
            block.call(context, object[key], key, object);
        }
    }
 
};
 
alert(Object.forEach);
alert(Function.forEach);
alert(Object.forEach === Function.forEach); // true

原型和原型链也是一个老生常谈的问题,很多初学者对于__proto__和prototype搞不清楚。其实我刚开始学习的时候也搞不清楚,因此写这篇文章对于这方面的知识进行一个巩固。

函数

function foo(){ } var foo = function(){ }

1
2
3
4
5
6
function foo(){
    
}
var foo = function(){
    
}

前者为函数声明,后者为函数表达式。typeof foo
的结果都是function。

今天给大家带来的是:JS原型链

二、构造函数——扩展

语法糖

var a = {};    //var a = new Object();

var a = [];    //var a = new Array();

function Foo(){……}    //var Foo = new Function(……);

使用instanceof判断一个函数是否是一个变量的构造函数

if (arr instanceof Array) {}

javascript原型链 问题 跪帮助

你要分清函数和对象实例是不同的,函数有2个属性,prototype,和__proto__,对象实例只有__proto__属性,__proto__属性是隐藏的,不可访问,但在高级浏览器中科院直接访问,比如谷歌。__proto__才是真正的原型链指针,prototype只是指定函数的原型对象。A.prototype是指向一个原型对象,它没有prototype属性,你换成console.log(A.prototype.__proto__.name);在谷歌中运行,控制台里面就会显示出了。  

作者:一木

函数对象

函数就是对象,代表函数的对象就是函数对象

官方定义, 在Javascript中,每一个函数实际上都是一个函数对象.JavaScript代码中定义函数,或者调用Function创建函数时,最终都会以类似这样的形式调用Function函数:var newFun = new Function(funArgs, funBody)

其实也就是说,我们定义的函数,语法上,都称为函数对象,看我们如何去使用。如果我们单纯的把它当成一个函数使用,那么它就是函数,如果我们通过他来实例化出对象来使用,那么它就可以当成一个函数对象来使用,在面向对象的范畴里面,函数对象类似于类的概念。

var foo = new function(){ } typeof foo // object 或者 function Foo (){ } var foo = new Foo(); typeof foo // object

1
2
3
4
5
6
7
8
9
10
11
12
13
var foo = new function(){
    
}
typeof foo // object
 
或者
 
function Foo (){
    
}
var foo = new Foo();
 
typeof foo // object

上面,我们所建立的对象

目录

三、5条原型规则

1、所有的引用类型(对象、数组、函数),都具有对象特性,即可自由扩展属性(除了“null”以外)

var obj = {};

obj.a = 100;

var arr = [];

arr.a = 100;

function fn() {}

fn.a = 100;

2、所有的引用类型(对象、数组、函数),都有一个__proto__(隐式原型)属性,属性值是一个普通对象

console.log(obj.__proto__);

console.log(arr.__proto__);

console.log(fn.__proto__);

3、所有的函数,都有一个prototype(显式原型)属性,属性值是一个普通对象

console.log(fn.prototype);

4、所有的引用类型(对象、数组、函数),__proto__属性值指向它的构造函数的prototype属性值

console.log(obj.__proto__ === Object.prototype);    //true

5、当试图得到一个对象的某个属性时,如果这个对象变量本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找

function Foo(name) {

    this.name;

}

Foo.prototype.alertName = function () {

    alert(this.name);

};

var foo = new Foo('zhangsan');

foo.printName = function (){

    console.log(this.name);

};

foo.printName();    //'zhangsan'

foo.alertName();    //'zhangsan'

this永远指向实例本身

遍历对象自身的属性

高级浏览器已经在for...in中屏蔽了来自原型的属性,但最好还是使用hasOwnProperty判断一下,保证程序的健壮性

var item;

for (item in f) {

    if (f.hasOwnProperty(item)) {

        console.log(item);

    }

}

javascript作用域链与原型链有联系?从原理上分析,不要说我网上找得到的

个人感觉,没什么联系。
一般来说,作用域链是针对变量的,js里面大的范围上来说,只有两种作用域,全局作用域和函数内部作用域,如果函数1里面又定义了函数2(一般都是匿名函数), 那么就有了这么一个作用域链全局作用域==>函数1作用域==>函数2作用域;特点是函数1里面可以直接使用全局作用域的变量,函数2里面可以直接使用全局作用域和函数1作用域的变量
原型链的话,一般是定义构造函数时用到,可以认为是针对构造函数的或者说针对构造函数对应的类的;原型链的头部就是Object类/构造函数,如果有构造函数1.prototype = 构造函数2;那么也就有这么一个原型链; Object ==> 构造函数1 ==> 构造函数2,这样的好处是构造函数2对应的类,可以拥有构造函数1 和Object中的属性,js没有对应继承的关键字,所以用原型链来模拟继承的效果。
纯手打,希望对你有帮助  

之前我对Javascript的原型链中, 原型继承与标识符查找有些迷惑, 如, 如下的代码: 复制代...

链接:

本地对象

ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。它们包括:
Object,Function,Array,String,Boolean,Number
Date,RegExp,Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError.

我们不能被他们起的名字是本地对象,就把他们理解成对象(虽然是事实上,它就是一个对象,因为JS中万物皆为对象),通过

typeof(Object) typeof(Array) typeof(Date) typeof(RegExp) typeof(Math)

1
2
3
4
5
6
typeof(Object)
typeof(Array)
typeof(Date)
typeof(RegExp)
typeof(Math)
 

返回的结果都是function

也就是说其实这些本地对象(类)是通过function建立起来的,

function Object(){ } function Array(){ } ...

1
2
3
4
5
6
7
function Object(){
    
}
function Array(){
    
}
...

可以看出Object原本就是一个函数,通过new Object()之后实例化后,创建对象。类似于JAVA中的类。

1.背景介绍

四、原型链

去foo.__proto__.__proto__...中查找

图片 2

对象的__proto__属性即其构造函数的prototype属性引用

foo.__proto__ === Foo.prototype    //true

Foo.prototype.__proto__ === Object.prototype    //true

来源:LOFTER

内置对象

ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。

理清楚了这几个概念,有助于理解我们下面要讲述的原型和原型链。

2.知识剖析

五、原型链类instanceof

foo instanceof Foo的判断原理是:

foo的__proto__属性和Foo的prototype属性是否是同一个引用

foo instanceof Foo的判断逻辑是:

foo的__proto__一层一层向上,能否对应到Foo.prototype,再试着判断foo instance Object

foo instanceof Foo    //true

foo instanceof Object    //true

如果要判断一个对象是否是一个构造函数生成的实例,使用constructor更严谨

foo.__proto__.constructor === Foo    //true

foo.__proto__.constructor === Object    //false

在说原型和原型链之前,我们先来看看如下知识点:

prototype

prototype属性是每一个函数都具有的属性,但是不是一个对象都具有的属性。比如

function Foo(){ } var foo = new Foo();

1
2
3
4
5
function Foo(){
    
}
 
var foo = new Foo();

其中Foo中有prototype属性,而foo没有。但是foo中的隐含的__proto__属性指向Foo.prototype。

foo.__proto__ === Foo.prototype

1
foo.__proto__ === Foo.prototype

为什么会存在prototype属性?

Javascript里面所有的数据类型都是对象,为了使JavaScript实现面向对象的思想,就必须要能够实现‘继承’使所有的对象连接起来。而如何实现继承呢?JavaScript采用了类似C++,java的方式,通过new的方式来实现实例。

举个例子,child1,child2都是Mother的孩子,且是双胞胎。(虽然不是很好,但是还是很能说明问题的)

function Mother(name){ this.name = name; this.father = 'baba'; } var child1 = new Mother('huahua'); var child2 = new Mother('huihui');

1
2
3
4
5
6
function Mother(name){
    this.name = name;
    this.father = 'baba';
}
var child1 = new Mother('huahua');
var child2 = new Mother('huihui');

如果有一天,发现孩子的父亲其实是Baba,那么就要对孩子每一个孩子的father属性。

child1.father ='Baba'; console.log(child2.father) // baba

1
2
child1.father ='Baba';
console.log(child2.father) // baba

也就是说修改了其中一个孩子的father属性不会影响到下一个,属性的值无法共享。

正是这个原因才提出来prototype属性,把需要共享的属性放到构造函数也就是父类的实例中去。

3.常见问题

六、new一个对象的过程

1、创建一个新对象,它继承自Foo.prototype

2、执行函数,传入相应的参数,同时上下文(this)被指定为这个新实例

    在不传递任何参数的情况下,new Foo等同于new Foo()

3、如果构造函数返回了一个对象,那么这个对象会取代整个new出来的结果

    如果构造函数没有返回对像,那么new出来的结果为步骤1创建的对象

var new2 = function (func) {

    var o = Object.create(func.prototype);    //创建一个新对象

    var k = func.call();    //执行函数

    if (typeof k === 'object') {    //判断构造函数是否返回了一个对象

        return k;

    } else {

        return o;

    }

}

一、私有变量和私有函数

__proto__

__proto__属性是每一个对象以及函数都隐含的一个属性。对于每一个含有__proto__属性,他所指向的是创建他的构造函数的prototype。原型链就是通过这个属性构件的。

想像一下,如果一个函数对象(也成为构造函数)a的prototype是另一个函数对象b构件出的实例,a的实例就可以通过__proto__与b的原型链起来。而b的原型其实就是Object的实例,所以a的实例对象,就可以通过原型链和object的prototype链接起来。

function a(){ } function b(){ } var b1 = new b(); a.prototype = b1; var a1 = new a(); console.log(a1.__proto__===b1);//true console.log(a1.__proto__.__proto__===b.prototype) //true console.log(a1.__proto__.__proto__.__proto__===Object.prototype) //true

1
2
3
4
5
6
7
8
9
10
11
12
function a(){
    
}
function b(){
    
}
var b1 = new b();
a.prototype = b1;
var a1 = new a();
console.log(a1.__proto__===b1);//true
console.log(a1.__proto__.__proto__===b.prototype) //true
console.log(a1.__proto__.__proto__.__proto__===Object.prototype) //true

如果要理清原型和原型链的关系,首先要明确一下几个概念:
1.JS中的所有东西都是对象,函数也是对象, 而且是一种特殊的对象

2.JS中所有的东西都由Object衍生而来, 即所有东西原型链的终点指向Object.prototype

3.JS对象都有一个隐藏的__proto__属性,他指向创建它的构造函数的原型,但是有一个例外,Object.prototype.__proto__指向的是null。

4.JS中构造函数和实例(对象)之间的微妙关系

构造函数通过定义prototype来约定其实例的规格, 再通过 new 来构造出实例,他们的作用就是生产对象.

function Foo(){ } var foo = new Foo(); foo其实是通过Foo.prototype来生成实例的。

1
2
3
4
5
6
function Foo(){
    
}
var foo = new Foo();
foo其实是通过Foo.prototype来生成实例的。
 

构造函数本身又是方法(Function)的实例, 因此也可以查到它的__proto__(原型链)

function Foo(){ } 等价于 var Foo= new Function();

1
2
3
4
5
function Foo(){
    
}
等价于
var Foo= new Function();

而Function实际上是

function Function(){ Native Code } 也就是等价于 var Function= new Function();

1
2
3
4
5
function Function(){
    Native Code
}
也就是等价于
var Function= new Function();

所以说Function是通过自己创建出来的。正常情况下对象的__proto__是指向创建它的构造函数的prototype的.所以Function的__proto__指向的Function.prototype

Object 实际上也是通过Function创建出来的

typeof(Object)//function 所以, function Object(){ Native Code } 等价于 var Object = new Function();

1
2
3
4
5
6
7
typeof(Object)//function
所以,
function Object(){
    Native Code
}
等价于
var Object = new Function();

那么Object的__proto__指向的是Function.prototype,也即是

Object.__proto__ === Function.prototype //true

1
Object.__proto__ === Function.prototype //true

下面再来看Function.prototype的__proto__指向哪里

因为JS中所有的东西都是对象,那么,Function.prototype 也是对象,既然是对象,那么Function.prototype肯定是通过Object创建出来的,所以,

Function.prototype.__proto__ === Object.prototype //true

1
Function.prototype.__proto__ === Object.prototype //true

综上所述,Function和Object的原型以及原型链的关系可以归纳为下图。图片 3

对于单个的对象实例,如果通过Object创建,

var obj = new Object();

1
var obj = new Object();

那么它的原型和原型链的关系如下图。
图片 4

如果通过函数对象来创建,

function Foo(){ } var foo = new Foo();

1
2
3
4
function Foo(){
    
}
var foo = new Foo();

那么它的原型和原型链的关系如下图

图片 5那JavaScript的整体的原型和原型链中的关系就很清晰了,如下图所示图片 6

1 赞 2 收藏 评论

图片 7

4.解决方案

在函数内部定义的变量和函数,如果不对外提供接口,那么外部是无法访问到的。这个被定义的变量和函数就叫做该函数的私有变量和私有函数。

5.编码实战

function Foo() {

6.扩展思考

var name = "yiMu";  //私有变量

7.参考文献

var fn = function() {   //私有函数

8.更多讨论

console.log("hello word");

1.背景介绍

};

JavaScript对象是一个属性的集合,另外有一个隐式的对象:原型对象。原型的值可以是一个对象或者null。一般的引擎实现中,JS对象会包含若干个隐藏属性,对象的原型由这些隐藏属性之一引用,我们在本文中讨论时,将假定这个属性的名称为"__proto__"(事实上,SpiderMonkey内部正是使用了这个名称,但是规范中并未做要求,因此这个名称依赖于实现)。 由于原型对象本身也是对象,根据上边的定义,它也有自己的原型,而它自己的原型对象又可以有自己的原型,这样就组成了一条链,这个链就是原型链。

}

先来看看有什么用处

var bar = new Foo();

function Foo(){ this.y=2; } Foo.prototype.x=1; var obj3 = new Foo(); obj1.y;//2 obj1.x://1

console.log(bar.name);  //undefined

这里就是用原型链继承了Foo的属性 obj1的原型(proto)会指向Foo的prototype属性 当函数声明的时候——function Foo(){} 实质上在做: 这个函数会有一个prototype属性,且默认会有两个属性 Foo.prototype { constructor:Foo, __proto__:Object.prototype } prototype是函数对象上的预设的对象属性,而原型通常都是其构造器的prototype属性 实例的__proto__属性会指向构造函数的prototype属性

console.log(bar.fn);    //undefined

2.知识剖析

二、静态变量和静态函数

ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法。

当定义一个函数后通过"."的方式为其添加属性和函数,通过对象本身可以访问到,但是其实例却无法访问到,这样的变量和函数叫做静态变量和静态函数。

JavaScritp引擎在访问对象的属性时,如果在对象本身中没有找到,则会去原型链中查找,如果找到,直接返回值,如果整个链都遍历且没有找到属性,则返回undefined.原型链一般实现为一个链表,这样就可以按照一定的顺序来查找。

function Foo(){}

原型的动态性:对原型对象所做的实时修改都能从实例上立即反应出来。(注意区别添加修改和重写了原型对象)

Foo.num = 10;  //静态变量

原型对象包含指向构造函数的指针。a实例包含指向a原型对象内部的指针,使得我们可以访问原型对象的属性。如果让b原型对象等于a对象的实例那我们就可以访问a对象的原型对象及其属性和方法了。同理a的原型对象也可以是通过该种方法从c继承过来...

Foo.fn = function() {   //静态函数

本文由巴黎人手机版发布于巴黎人-前端,转载请注明出处:函数对象的prototype并不作用于原型链查找过程中

上一篇:没有了 下一篇:没有了
猜你喜欢
热门排行
精彩图文