JS原型和原型链

构造函数

function Foo(name, age){
    this.name = name;
    this.age = age;
    this.class = 'class-1';
 }
var f =new Foo('zhangsan',20);

命名规则:大写字母开头;
那么,在使用new操作符来调用一个构造函数的时候,发生了什么呢?其实很简单,就发生了四件事:

10年积累的成都网站建设、网站设计经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有巫山免费网站建设让你可以放心的选择与我们合作。

var obj  ={};
obj.__proto__ = Foo.prototype;
Foo.call(obj);
return obj;

第一行,创建一个空对象obj。

第二行,将这个空对象的proto成员指向了构造函数对象的prototype成员对象,这是最关键的一步,将新生成的对象的prop属性赋值为构造函数的prototype属性,使得通过构造函数创建的所有对象可以共享相同的原型。

第三行,将构造函数的作用域赋给新对象,因此Foo函数中的this指向新对象obj,然后再调用Foo函数。于是我们就给obj对象赋值了。

第四行,返回新对象obj。

构造函数 - 扩展

var a = {} 其实是 var a = new Object()的语法糖;
var a = [] 其实是 var a = new Array() 的语法糖;
function Foo(){...} 其实是 var Foo = new Function(...)
》所有引用类型都有构造函数
》在实际开发过程中依然推荐使用左侧的实现方式,易读性、性能方面左侧都更好;

原型规则和示例

① 原型规则
 所有除了“null”以外的引用类型(数组、对象、函数),都具有对象特性,既可自由扩展属性
 所有除了“null”以外的引用类型(数组、对象、函数),都有一个proto属性(称它为‘隐式原型’,proto翻译为原型机、样机),属性值是一个普通的对象。附:之所以叫隐式,大概是因为proto里的方法是通过这种原型链的形式继承过来的,自己没定义却可以使用。
 所有的函数,都有一个prototype(称它为‘显式原型’prototype翻译为原型,雏形,蓝本)属性,属性值也是一个普通的对象;
 所有引用类型的proto属性值都指向它的构造函数的“prototype”属性值
 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么回去它的proto(既它的构造函数的prototype)中寻找
② 关于this在此场景的一个使用说明,无论是对象(或其他引用类型)自身的属性还是从原型中得到的属性,属性中用到的this都指向该对象自身
③ 循环对象自身的属性

 var item
 for (item in f){
      // 高级浏览器已经在 for in 中屏蔽了来自原型的属性
      // 但是这里建议大家还是加上这个判断,保证程序的健壮性
      if(f.hasOwnProperty(item)){
         // 如果是自身的属性就输出
         console.log(item); 
      }       
   }        

原型链

① 以调用toString()方法为例
var f =new Foo('zhangsan',20); //通过构造方法Foo创建了一个对象
f.toString()
→对象f(或其他引用类型)中没有此方法
→去f的proto中查找(即构造方法Foo.prototype中查找)
→仍然没找到,而Foo.prototype本身是个对象,所去 Foo.prototype.proto中查找(即构造方法Object.prototype)
→找到了toString()方法,执行
② 注意:
如果Object.prototype仍然没有的话,会继续去Object.prototype.proto中查找;
不过js规定了Object.prototype.proto返回的是null,这是特例,大概是防止这么无限循环下去吧;
③ instanceof方法工作原理:
a)定义:用于判断引用类型是否属于某个构造函数
b)f instanceof Foo的判断逻辑是:从f开始通过proto一层层往上,能否找到Foo.prototype (第一下就找到了,正确)
c)f instanceof Object 的判断逻辑:从f开始通过proto一层层往上,能否找到Object.prototype (第二层找到了,正确)
d)注意:
所有的引用类型都能匹配到Object这个构造函数,因为他们的隐式原型都是对象。
这更加能理解数组和函数是一个特殊的对象,也是其构造函数返回的对象跟我们自己写个构造方法创建一个对象的形式差不多,都是基于Object而来。
官方定义: 在Javascript中,每一个函数实际上都是一个函数对象。
new一个function 实际上是返回一个函数对象。这与其他的对象有很大的不同。其他的类型Array、Object等都会通过new操作符返回一个普通对象。尽管函数本身也是一个对象,但它与普通的对象还是有区别的,因为它同时也是对象构造器,所有typeof返回 “function”的对象都是函数对象。因而,所有的构造器都是对象,但不是所有的对象都是构造器。
④ 可以修改Object这个类型来让所有的对象具有一些通用的属性和方法:
Function是所有函数对象的基础,而Object则是所有对象(包括函数对象)的基础,所有对象都由Object继承而来。在JavaScript中,任何一个对象都是 Object的实例,因此,可以修改Object这个类型来让所有的对象具有一些通用的属性和方法,修改Object类型是通过prototype来完成 的:

以下是引用片段:

Object.prototype.getType=function(){ 
       return typeof(this); 
} 
var array1=new Array(); 
function func1(a,b){ 
      return a+b; 
} 
alert(array1.getType()); 
alert(func1.getType()); 

上面的代码为所有的对象添加了getType方法,作用是返回该对象的类型。两条alert语句分别会显示“object”和“function”

如何准确判断一个变量是数组类型

var arr = [];
arr instanceof Array // true
       // instanceof 只能用来判断引用类型中的Array和 function ,原因见上文
// 另外typeof 是无法判断是否是数组的,对于引用类型它只能区分function
typeof arr // object

描述new一个对象的执行过程

创建一个空对象,
this指向这个对象,
执行代码,即对this赋值,
返回this

原型链继承的实例

function Elem(id){
    this.elem = document.getElementById(id);
}
Elem.prototype.html = function (val) {
    var elem = this.elem;
    if(val){
        elem.innerHTML =val;
        return this; //链式操作
    }else{
        return elem.innerHTML
    }
}
Elem.prototype.on = function (type, fn) {
    var elem = this.elem;
    elem.addEventListener(type, fn);
    return this;
}
var div1 = new Elem('detail-page');
//console.log(div1.html());
div1.html('

hello

').on('click',function(){ alert('clicked'); })

另:在实际工作中也经常会在公用的js文件中给Date写一个格式化时间的方法,例如Date.prototype.format = function(fmt) {...},然后新创建的Date对象就可以直接调用format方法了。


当前标题:JS原型和原型链
地址分享:http://pwwzsj.com/article/ghsieh.html