JS原型

一. 普通对象与函数对象

JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象,Object ,Function 是JS自带的函数对象。new方法产生的是对象。下面举例说明

function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');

var o3 = new f1();
var o1 = {};
var o2 =new Object();

console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function 

在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 New Function()创建的。

1.1 instanceof()

在前文已经谈到过,并不是所有的类型都能用typeof检测出数据类型,typeof检测的是基本的数据类型。instanceof()检测引用类型,判断一些复杂的数据类型是否相等,返回值是true/false。

var arr = [1,2,3,4,5];
console.log(arr instanceof Array);//true
console.log(arr instanceof Function);//false

instanceof()可以检测function、object、array、New number()、new String()、new Boolean(),instanceof()对于值类型检测不出来。

二. 原型对象

函数有prototype属性,该属性是一个对象。如果函数没有任何属性的话,prototype默认有一个constructor属性。注:普通对象没有prototype(原型),但有__proto__属性。
在JavaScript中,每当定义一个对象(函数)时候,对象中都会包含一些预定义的属性,比如说__proto__属性,该属性是一个对象。__proto__属性指向创建当前对象的函数的prototype。
原型对象其实就是普通对象。

function f1(){};
console.log(f1.prototype); //f1{}:包括constructor: f1(){}__proto__: Object
console.log(typeof f1.prototype); //Object
console.log(typeof Function.prototype); // Function,这个特殊
console.log(typeof Object.prototype); // Object
console.log(typeof Function.prototype.prototype); //undefined

从这句console.log(f1.prototype); //f1{} 的输出就结果可以看出,f1.prototype就是f1的一个实例对象。就是在f1创建的时候,创建了一个它的实例对象并赋值给它的prototype,基本过程如下:

var temp = new f1();
f1.prototype = temp;

所以,Function.prototype为什么是函数对象就迎刃而解了,上文提到凡是new Function()产生的对象都是函数对象,所以temp1是函数对象。

var temp1 = new Function();
Function.prototype = temp1;

那原型对象是用来做什么的呢?主要作用是用于继承。举了例子:

var fn = function(){
    this.x = 10;
    return this.x;
}
var fn2 = new fn();
fn2.a = 30;
console.log(fn2.__proto__ === fn.prototype);//true
fn2.__proto__.x = 40;
console.log(fn.prototype);//x=40。fn的x属性被篡改

那么该如何判断x是否是自身的属性呢?一般,如果fn2有x属性,则输出fn2的x,否则向上寻找x,输出的是fn的x。

console.log(fn2.hasOwnProperty('x'));//true

2.1 this

这里涉及到this,讲一下this是什么吧。

var obj = {
    x: 10,
    y: 20,
    fn: function(){
        console.log(this);//obj
        this.x = 100;
    }
}
obj.fn();
console.log(obj.x);//100

this当前所在函数是对象的属性时,this指向该对象。

//函数声明
function text1(){
    console.log(this);//window
    this.a = 10;
}
text1();
console.log(a);//10
console.log(this);//window
//匿名函数
(function(){
    console.log(this);//window
    this.a = 30;
})();
console.log(a);//10
console.log(this);//window
//函数表达式
var text2 = function(){
    console.log(this);//window
    this.a = 20;
}
text2();
console.log(a);//20

在全局作用域下调用this,this指向window。函数声明、匿名函数、函数表达式在全局中调用是,指向window。

var fn = function(){
    console.log(this);//fn{}
    this.x = 10;
    this.y = 20;
    return this.x;
}
var fn2 = new fn();
console.log(fn2.x);//10

在上面的例子中,new关键字构造的对象,this指向该对象的父对象。

2.2 关于继承

function test(){
    test.a = 20;
    test.prototype.x = 10;
}
var fn2 = new test();
for(var i in test){//test是一个函数
    console.log(i);
}//a(为什么只有a,没有x,此处韩哥说以后会讲,莫急莫慌)
for(var i in fn2){//fn2是一个对象
    console.log(i);
}//x
console.log(fn2.a);//undefined,继承的是prototype定义的属性

注意哦!fn2继承的是fn1的prototype定义的属性
未完待续。。。有补充的请联系我哦!