JavaScript进阶–原型、原型链、闭包

原型

1.prototype

在JavaScript中,每个函数 都有一个prototype属性,当一个函数被用作构造函数来创建实例时,这个函数的prototype属性值会被作为原型赋值给对象实例(也就是设置 实例的__proto__属性),也就是说,所有实例的原型引用的是函数的prototype属性。

**构造函数使用方式

function Person(name,age){
    this.name = name
    this.age = age
}
var p = new Person('张三',20);

每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型

console.log(p.__proto__ === Person.prototype); // true

2.constructor

每个原型都有一个 constructor 属性指向关联的构造函数

console.log(Person === p.__proto__.constructor); //true

在 Javascript 语言中,constructor 属性是专门为 function 而设计的,它存在于每一个 function 的prototype 属性中。这个 constructor 保存了指向 function 的一个引用

通过构造函数创建的对象,constructor 指向构造函数,而构造函数本身的constructor ,则指向Function本身,因为所有的函数都是通过**new Function()**构造的

   function Person() {

    }
    var p = new Person()
    console.log(Person.prototype); // Object{} 
    console.log(p.prototype); // undifined
    console.log(p.constructor); //function Person(){}    
    此处的p是通过 Person函数构造出来的,所以p的constructor属性指向Person
    console.log(Person.constructor); //function Function(){}
    之前提过,每个函数其实是通过new Function()构造的
    console.log({}.constructor); // function Object(){}
    每个对象都是通过new Object()构造的
    console.log(Object.constructor); // function Function() {}
    Object也是一个函数,它是Function()构造的
    console.log([].constructor);  //function Array(){}

函数是对象构造的 对象也是函数构造的,俩者即是函数也是对象,所以为什么构造函数它是一个函数却返回一个对象,俩者是互相继承的关系

    var o1 = new f1();
    typeof o1 //"object"  

prototype的用法

最主要的方法就是将属性暴露成公用的

代码对比:

    function Person(name,age){
        this.name = name;
        this.age = age;
        this.sayHello = function(){
            console.log(this.name + "say hello");
        }
    }
    var girl = new Person("bella",23);
    var boy = new Person("alex",23);
    console.log(girl.name);  //bella
    console.log(boy.name);   //alex
    console.log(girl.sayHello === boy.sayHello);  //false
     function Person(name,age){
        this.name = name;
        this.age = age;

    }
    Person.prototype.sayHello=function(){
        console.log(this.name + "say hello");
    }
    var girl = new Person("bella",23);
    var boy = new Person("alex",23);
    console.log(girl.name);  //bella
    console.log(boy.name);   //alex
    console.log(girl.sayHello === boy.sayHello);  //true 

总结:

function Person(){

 }
var person1=new Person()

person1.__proto__==Person.prototype

person1.constructor==Person

Person.__proto__==Function.prototype

Person.prototype.constructor==Person

person1.__proto__.constructor==Person

原型链

在js中,大部分东西都是对象,数组是对象,函数也是对象,对象更加是对象。不管我们给数组和函数定义什么内容,它们总是有一些相同的方法和属性。比如说valueOf(),toString()等

**这说明一个对象所拥有的属性不仅仅是它本身拥有的属性,它还会从其他对象中继承一些属性。当js在一个对象中找不到需要的属性时,它会到这个对象的父对象上去找,以此类推,这就构成了对象的原型链

function Foo(_name) {
  this.name = _name;
}
Foo.prototype.show = function() {
  console.log('I am ', this.name);
};
var f1 = new Foo('obj1');
var f2 = new Foo('obj2');

f1.show();  //  I am obj1
f2.show();  //  I am obj2
//我们定义的show函数在Foo.prototype中,当我们执行f1.show()时,js发现f1本身没有show这个属性,所以它就到f1的原型(也就是__proto__指向的对象)去找,找到了就可以调用
  • 所有函数都有一个prototype指针,指向原型对象,如图中的Foo的prototype指针。prototype指针的意义是,当我们使用这个构造函数new出新对象的时候,新对象的__proto__指向prototype
  • 构造函数的prototype所指向的原型对象有一个constructor指针,指回构造函数。如图中Foo.prototype的constructor指针指向Foo。constructor指针有助于我们找到一个对象的构造函数是谁。
  • __proto__每个对象都有,js在new一个对象的时候,会将它的__proto__指向构造函数的prototype指向的那个对象。在上图中,f1、f2这些实例对象的__proto__都指向了Foo.prototype。
function Foo(_name) {
  this.name = _name;
}
Foo.prototype.show = function() {
  console.log('I am ', this.name);
};
var f1 = new Foo('obj1');
var f2 = new Foo('obj2');

var obj = {
  type:1
}
f1.__proto__ = obj
console.dir(f1)

f1.show();  //  I am obj1
f2.show();  //  I am obj2
 

Foo是一个函数,它的构造函数是js内部的function Function(),Function的prototype指向了一个对象Function.prototype,因此Foo的__proto__就指向了Function.prototype

所有的函数都以function Function()为构造函数,因此,所有函数**(包括function Function()和function Object())**的__proto__都指向Function.prototype这个对象,这个对象中定义了所有函数都共有的方法,比如call()、apply()等。

我们继续深入下去,Function.prototype这个对象,它就是一个普通的对象,它的构造函数是js内置的function Object(),function Object()的prototype指向Object.prototype,因此Function.prototype.__proto__就指向Object.prototype,这个对象中定义了所有对象共有的属性,比如我们之前说的hasOwnProperty()和toString()等。

同理,Foo.prototype和其他自定义的对象也是__proto__指向Object.prototype对象

Object.prototype就是原型链的终点了,它的__proto__是null,js查找属性时,如果到这里还没有找到,那就是undefined了

闭包

函数和函数内部能访问到的变量加在一起就是一个闭包

常规认为,一个函数嵌套另一个函数,两个函数中间的环境,叫闭包,但其实这也是制造一个不会被污染沙箱环境,实质上,由于js函数作用域的存在,所有的函数,都可以是一个闭包

function foo(){
  var num = 1
  function add(){
    num++
    return num
  }
  return add
}

var func = foo()
func()

闭包常常用来间接访问一个变量也可以理解为**隐藏一个变量

function foo(){
  var num = 18
  var obj = {
      text:'我是一个字符串',
      getNUm:function(){
          return num
      }
  }
  return obj
}

var obj = foo()
var age = obj.getNUm()
console.log(age)

由于 JS 的函数内部可以使用函数外部的变量,而函数外部无法访问到函数内部的变量,所以正好符合了闭包的定义。所以只要懂了 JS 的作用域,自然而然就懂了闭包。

版权声明:
作者:大数据爱好者
链接:https://jkboy.com/archives/12980.html
来源:随风的博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
海报
JavaScript进阶–原型、原型链、闭包
在JavaScript中,每个函数 都有一个prototype属性,当一个函数被用作构造函数来创建实例时,这个函数的prototype属性值会被作为原型赋值给对...
<<上一篇
下一篇>>