理解原型及原型链(笔记)

私有变量和函数

Javascript中是没有块级作用域的,但是有函数作用域。在函数内部定义的变量和函数是私有的,不能被外界访问到。

function Foo(){
    //私有变量
    var name='A';
    //私有函数
    var fn=function(){
        return 'fn';
    }
    console.log('inside: name:' + name); //inside: name:A
    console.log('inside: fn:' + fn());   //inside: fn:fn
}
Foo();
console.log('outside: name:' + name);   //Uncaught TypeError: name is not defined
console.log('outside: fn:' + fn());     //Uncaught TypeError: fn is not a function(…)

静态变量和函数

当定义一个函数后通过点号 “.”为其添加的属性和函数,通过对象本身仍然可以访问得到,但是其实例却访问不到,这样的变量和函数分别被称为静态变量和静态函数。

function Person(){
    //静态变量
    Person.eye= 2;
    //静态函数
    Person.say=function(){
        console.log('Hello');
    }
};
Person();
console.log(Person.eye);//2
Person.say();//Hello

var Tom= new Person();
console.log(Tom.eye);//undefined
Tom.say();//Uncaught TypeError: Tom.say is not a function(…)

实例变量和函数

在面向对象编程中除了一些库函数我们还是希望在对象定义的时候同时定义一些属性和方法,实例化后可以访问,JavaScript也能做到这样

function Person(){
    //实例变量
    this.eye=2;
    //实例方法
    this.say=function(){
        console.log('Hello');
    }
}
var Tom = new Person();
console.log(Tom.eye);//2
Tom.say();//Hello

prototype的由来

下例中,我们发现实例中改变了属性,并不影响另外一个实例。两个实例中的属性方法名相同,但不是一个引用,而是对Person对象定义的属性和方法的复制。

但是对于方法而言,完全一样的功能但复制了无数份,显然不科学。于是,prototype应运而生。

function Person(){
    this.name=[];
    this.say=function(){
        console.log('Hello');
    }
}
var Tom = new Person();
Tom.name.push('Tom');
console.log(Tom.name);//["Tom"]
console.log(typeof Tom.name);//object

var Jerry= new Person();
console.log(Jerry.name);//[]
Jerry.name.push('Jerry');
console.log(Jerry.name);//["Jerry"]

prototype的基本概念

创建函数时,会自动创建一个名为prototype(原型对象)的属性,它的用途是包含所有实例共享的属性和方法。prototype调用构造函数创建对象实例的原型对象。

prototype中除了有构造函数,还有一个属性 __proto__,它指向创建它的函数对象的prototype

var Person=function(){};
Person.prototype.name='super man';
Person.prototype.say=function(){
    console.log('Hello');
}
var Tom = new Person();
console.log(Tom.name);//super man
Tom.name= 'Tom';
console.log(Tom.name);//Tom

var Jerry= new Person();
console.log(Jerry.name);//super man
Jerry.say(); //Hello

在调用Jerry.say()时,Jerry没有这个方法,于是会沿着Jerry的__proto__(指向的是Person的prototype)向上查找,找到了say()方法,于是执行。

原型及原型链

var Person=function(name){
    this.name=name;
};
Person.prototype.say=function(){
    console.log('Hello, I am ' + this.name);
}
var person1 = new Person('Byron');
person1.say(); //Hello, I am Byron
var person2= new Person('Frank');
person2.say(); //Hello, I am Frank

这里写图片描述

我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。

原型继承

function Father(){
    this.familyname='Lee'; 
}
Father.prototype.getFamilyName = function(){
    console.log('My family name is ' + this.familyname);
}

function Son(){
    this.age=1;
}

Son.prototype= new Father();
var Tom = new Son();
console.log(Tom.familyname); //Lee

实现继承的核心就是Son.prototype= new Father();,为什么这样就实现了继承呢?我们通过框图来理解。

这里写图片描述

上文中提到,实例对象(此处为new Father())的__proto__指向的是创建它的函数对象的prototype(此处为Father.prototype),于是能访问到Father.prototype中的getFamilyName方法。Son.prototype 等价于 new Father(),则Son.prototype.__proto__ 等价于 new Father()__proto__。于是Son和Fahter之间产生了继承的关系。

当实例化一个Son时(上代码中为Tom),Tom的__proto__指向Son.prototypeSon.prototype中的__proto__指向Father.prototypeFather.prototype中含有getFamilyName方法。

强调一下:函数对象有prototype属性,普通对象没有prototype,但有__proto__属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值