【知识梳理】3.6原型链

1.创建对象

    //第一种方式:字面量
    var o1 = {name:"o1"};//{name: "o1"}
    var o2 = new Object({name:"o2"});//{name: "o2"}

    //第二种方式:构造函数
    var M = function(name){this.name = name;};
    var o3 = new M("o3");//M {name: "o3"}

    //第三种方式:Object.create(o4.__proto__===p//true)
    var p = {name:"p"};
    var o4 = Object.create(p);//{}

2.原型、构造函数、实例、原型链

原理:ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。在JavaScript中,用__proto__ 属性来表示一个对象的原型链。

任何一个函数,被new使用了,new后面的函数就是一个构造函数。构造函数可以通过new运算符来生成一个实例

在声明一个(构造)函数的时候,js引擎会自动给它加上一个prototype属性,此属性会初始化一个空对象,即向原型对象M.prototype.constructor===M;返回true

原型对象怎么能区分是被哪一个构造函数引用的呢?原型对象中有一个构造器(constructor),默认的是声明的构造函数。o3.__proto__===M.prototype;返回true

小提示:

1.实例对象只有__proto__,没有prototype属性。
2.构造函数有prototype属性。(也有__proto__,因为函数也是一个对象。M.__proto__===Function.prototype;返回true。)

3.instanceof的原理

instanceof的原理:用来判断实例对象的__proto__属性和构造函数的prototype属性是不是同一个引用。/ 判断类(构造函数)的prototype对象是否存在于实例对象的原型链上。是则返回true。

  • o3 instanceof M;返回true(o3.__proto__===M.prototype;返回true)
  • o3 instanceof Object;返回true(M.prototype.__proto__===Object.prototype;返回true)
  • M instanceof Function;返回true。
  • M instanceof Object;返回true。

*使用 instanceof 判断 引用类型 属于哪个 构造函数 的方法。

*判断一个对象是否为数组:arr instanceof Array

*判断一个对象的构造函数用constructor比较合理

  1. o3.__proto__.constructor===M;//true
  2. o3.__proto__.constructor===Object;//false

4.new运算符

  1. 先创建一个新对象,继承构造函数的原型对象;(继承自foo.prototype
  2. 当构造函数foo被执行时,传入相应的参数,同时this指向这个新实例;
  3. 如果构造函数没有返回对象,那么new出来的结果为第一步创建的对象;如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果。
  • 创建一个新对象;
  • this指向这个新对象;
  • 执行代码,即对this赋值
  • 返回this
//模拟new运算符

var new2 = function(func){
    var o =Object.create(func.prototype); //第一步
    var k =func.call(o);//第二步
    //第三步
    if(typeof k ==="object"){
        return k;
    }else{
        return o;
    }
}

//验证
o6=new2(M)//创建一个新对象
o6 instanceof M//rue
o6 instanceof Object//true
o6.__proto__.constructor===M//true

5.原型规则和示例

  1. 所有的引用类型(对象、数组、函数),都具有对象特性,即可自由扩展属性(除了null);
  2. 所有的引用类型(对象、数组、函数),都有一个__proto__属性,属性值是一个普通的对象;
  3. 所有的函数,都有一个prototype属性,属性值也是一个普通的对象;
  4. 所有的引用类型(对象、数组、函数),__proto__属性值指向他的构造函数的prototype属性值;obj.__proto__ === Object.prototype
  5. 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去他的__proto__(即他的构造函数的prototype)中寻找。
//构造函数
function Foo(name,age){
    this.name = name;
}
Foo.prototype.alertName = function(){
    alert(this.name);//this是f
}
//创建实例
var f = new Foo('zhangsan');
f.printName = function(){
    console.log(this.name);//this是f
}
//测试
f.printName();
f.alertName();

6.循环对象自身的属性

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

7.画一个原型链

画出一下代码的原型链,便于理解。

//构造函数
function Foo(name,age){
    this.name = name;
    this.age = age;
    //return this; // 默认有这一行
}
var f = new Foo('zhangsan',21);

8.手写一个原型链继承的例子

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('test');
div1.html('

hello world

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

你可能感兴趣的:(原型链)