JavaScript基础知识——原型和原型链

二、原型和原型链

Q:1、如何准确判断一个变量是数组类型?

var arr = [];
arr instanceof Array; // true
//反例
typeof arr;// typeof不能判断arr是否是数组

  2、写一个原型链继承的例子

//封装一个DOM查询
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('div1');
// console.log(div1.html());
// div1.html('<p>Hello</p>');
// div1.on('click',function(){
//   alert('clicked')
// });
div1.on('click',function(){alert('clicked')}).html('<p>链式操作</p>')
//在之前的函数中增加了return this,由div1调用时便会返回当前对象,即div1,便可以实现链式操作

 

  3、描述new一个对象的过程

    a、创建一个新对象

    b、this指向这个新对象

    c、执行代码,即对this赋值

    d、最后返回this

 

  知识点:

    (1)、构造函数 

function Foo (name, age) {
    this.name = name;
    this.age = age;
    this.class = 'class-2';
    // return this;// 默认有这一行
}    
var f = new Foo('张三',20);
//当在执行new Foo()的时候,是先return 空this,然后会赋值this.name = '张三',this.age = 20
console.log(f);//Foo {name: "张三", age: 20, class: "class-1"}
console.log(f.name);//张三
console.log(f.age);//20

    (2)、构造函数-扩展

var a={}; //其实是var a=new Object()的语法糖
var b=[]; //其实是var b=new Array()的语法糖
function Foo(){...} //其实是var Foo=new Function(...)
//使用instanceof判断一个函数是否是一个变量的构造函数

所有的引用类型(对象、数组、函数)都有构造函数,a的构造函数是Object(),b的构造函数是Array(),Foo的构造函数是Function()。所以假如想要判断一个变量是否为数组就可以使用 var a = {}; a instanceof Array // false,更推荐var a = {};这种方式声明一个对象的方式

    (3)、原型规则(5条)和示例

    a、所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(null除外)

var obj={};obj.a=100;// obj可以扩展一个属性a
var arr=[];arr.a=100;// arr可以扩展一个属性a
function fn(){}
fn.a=100;// fn可以扩展一个属性a

    b、所有引用类型(数组、对象、函数)都有一个__proto__(隐式原型)属性,属性值是一个普通的对象

var obj={};obj.a=100;
var arr=[];arr.a=100;
function fn(){}
fn.a=100

console.log(obj.__proto__)
console.log(arr.__proto__)
console.log(fn.__proto__)

    c、所有的函数,都有一个prototype属性,属性值也是一个普通对象

    d、所有引用类型的__proto__属性值指向它的构造函数的prototype的属性值

var obj={};obj.a=100;
console.log( obj.__proto__ === Object.prototype );//true

    e、当试图得到 一个对象的某个属性时,如果这个对象本身没有这个属性,那么回去它的__proto__(即它的构造函数的prototype)中寻找。

// 构造函数
function Foo(name,age) {
  this.name = name;
  this.age = age;            
}

Foo.prototype.alertName = function () {
  alert(this.name);      
}

var f = new Foo('小明');
f.printName = function () {
  console.log(this.name);  
}

f.alertName();//弹出提示框'小明'
f.printName();//小明 f没有alertName属性,于是去f._proto_即Foo.prototype中查找

    由对象调用原型中的方法,this永远指向对象本身。  

  (4)循环对象自身的属性

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

  (6)原型链

// 构造函数
function Foo(name,age) {
  this.name = name;
  this.age = age;            
}

Foo.prototype.alertName = function () {
  alert(this.name);      
}

var f = new Foo('小明');
f.printName = function () {
  console.log(this.name);  
}

f.alertName();//弹出提示框'小明'
f.printName();//小明 f没有alertName属性,于是去f._proto_即Foo.prototype中查找
f.toString();//要去f.__proto__.__proto__中查找
所有的引用类型都有__proto__属性,且__proto__属性值指向它的构造函数prototype的属性值,所以当f不存在toString时,便会在f.__proto__Foo.prototype中查询,而Foo.prototype中也没有找到toString。由于Foo.prototype也是一个对象,所以它隐式原型__proto__的属性值便指向它的构造函数Object的prototype的属性值。

  (7)、instanceof

    用于判断引用类型属于哪个构造函数的方法
    f instanceof Foo的判断逻辑是f__proto__一层层向上能否对应到Foo.prototype,再试着判断f instanceof Object

 

posted @ 2018-03-12 12:50  utrustme  阅读(153)  评论(0编辑  收藏  举报