原型链

原型和实例对象

每一个函数天生都有一个原型(prototype),当函数被new关键字调用的时候,产生的实例的__proto__都指向次构造函数的prototype对象

 

 

 

 function Person() {}
 console.log(Person.prototype);

  function Person() {}
      var xiaoming = new Person();
      console.log(xiaoming);

 

此时我们可以判断一下这个xiaoming的__proto__是否等于Person构造函数的prototype

 console.log(xiaoming.__proto__ == Person.prototype)

构造函数的prototype指向了谁,该实例的__proto__就指向谁

__proto__有什么用?

所有的对象都有__proto__属性,这个属性指向的就是自己的“原型对象”,每一个对象在通过点语法访问自己的属性、方法的时候,都拥有原型链查找(proto search)的功能。什么叫做原型链查找?如果当前对

象自己身上有这个属性或者方法,则用自己的,如果没有则沿着__proto__指向的原型对象中去查找,如果在原型对象上有这个方法,则调用这个原型对象属性或者方法

 function Person(name,sex) {
        this.name = name;
        this.sex = sex;
      }
      Person.prototype.sayHello = function () {
        console.log("你好,我是" + this.name + ",我是一个" + this.sex + "生,")
      };
      var xiaoming = new Person("小明",  "");
      var xiaohong = new Person("小红", "");
      console.log(xiaoming);
      console.log(xiaohong);

此时就可以看到方法是在原型对象上(也就是构造函数的原型上)

 

 

此时我们也可以验证xiaoming和xiaohong调用的是同一个函数

      console.log(xiaoming.sayHello == xiaohong.sayHello)     

 

 语法:

function 构造函数(属性1,属性2,属性3) {
this.属性1 = 属性1;
this.属性2 = 属性2;
this.属性3 = 属性3;
}
构造函数.prototype.方法1 = function(){

}
构造函数.prototype.方法2 = function(){

}

构造函数.prototype.方法3 = function(){

}

 

内置构造函数

在JavaScript中,对象是对象,数组是对象,函数是对象,正则表达式是对象。所有的引用类型值在JavaScript中都是对象。他们都有__proto__属性

 

函数是可以通过new 关键字创建的,但是其他的数据类似也是可以通过关键字创建的

此时有一些内置构造函数和包装类

new Array()、new Object()、new String()、new Nubmer()

 

引用类型值的构造函数

1、Object类型

任何的“真”对象都可以认为被Object new出来的

var obj = new Object();
obj.name = "小明";
obj.age = 20;
obj.sex = "";
//等同于
var obj = {
    name: '小明',
    age: 20,
    sex: ''
}

2、Function类型

Function是一个内置的构造函数,任何的函数都可以视作为是Function new出来的

var sum = new Function('a', 'b', 'return a + b;')
//等价于
var sum = function(a,b){
    return a + b
}

需要注意的是,这个是内置的构造函数,Function首字母是大写的

3、Array类型

Array是一个内置的构造函数,任何的函数都可以视作为是Array new出来的

var arr = new Array(4);
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
console.log(arr)
//等价于
var arr = [0,1,2,3]

3、RegExp类型

RegExp是一个内置的构造函数,任何的函数都可以视作为是RegExp new出来的

var reg = new RegExp("\d", "g");
//等价于
var reg = /\d/g;

 4、基本类型值的包装类

基本类型值三种:Number、String、Boolean

基本类型值也有构造器,他们被视作为“包装类”。JavaScript为了体系的完整,所以就认为的造出了基本类型的包装类,本质上没有用

比如new一个Number

 var a = new Number(3);
 console.log(a);

[[PrimitiveValue]]对象叫做(原始值)作用就是赋值一个初始值,值是3

console.log(typeof a)

此时你会发现返回的是一个object,并不是一个number类型,但是一旦参与了运算,就变成了number类型,这种类叫做包装类

var a = new Number(3);
console.log(typeof a);
a += 5;
console.log(typeof a);

 

 

 

String类型也是包装类

var str = new String("hello");
console.log(str);

Boolean类型也是包装类

   var boo = new Boolean(true);
      console.log(boo);

这些包装类有一个隐式转换功能

比如我们字符串的”100”,通过Number转换后为100数字类型

   var a = new Number("100");
      console.log(a);

 

 

 

Number需要注意的是如果隐式转换不是纯数字不会和parseInt一样净化,会返回NaN

console.log(Number("100你好,我是"));
console.log(parseInt("100你好,我是"));

 

 

 

Object.prototype是所有原型链的终点

任何对象都有原型对象__proto__

更恐怖的是构造函数的实例的__proto__也是一个对象,这个对象也有__proto__

Object.prototype是所有原型链的终点,Object.prototype虽然也是一个对象,但是这个对象没有__proto__指向的是空

 

 

 

看一个小案例

var obj = {};
console.log(obj.__proto__ == Object.prototype); 

Object是一个内置的构造函数,所有的对象都可以认为是Object new出来

  var obj = new Object();
      obj.age = 12;
      obj.name = "小明";
      console.log(obj);

 

 

 

此时需要注意这个对象必须是“真对象”,(而不是函数、正则表达式、数组的__proto__)的__proto__都是Object.prototype,因为它们本质上都是被Object new出来的

此时再看之前的Person构造函数就得到一个完整的原型链

 

内置构造函数的关系

规律:

  • 任何的“真”对象都是Object new出来的。所以只要是“真”对象,并且没有特别的构造函数,它的__proto__就指向的是Object.prototype
  • 任何的函数都是Function new出来的,所以只要它是函数(内置构造函数也是函数),它的__proto__就会指向Function.prototype

 

 

 

      console.log(Object.__proto__ === Function.prototype);
      console.log(Array.__proto__ === Function.prototype);
      console.log(Number.__proto__ === Function.prototype);
      console.log(Number.__proto__.__proto__ === Object.prototype);
      console.log(Function.prototype == Function.__proto__);

比如数组字面量的原型链关系

 

原型链相关的方法

1、hasOwnProperty()方法

hasOwnProperty方法的作用是用来检测某个属性或者是方法是否在自己的身上

需要注意的是hasOwnProperty方法检测的是该属性是否真实的在自己的身上,而不是在原型链上面

 function Person(name) {
        this.name = name;
      }
      Person.prototype.sayHello = function () {
        alert("你好,我是" + this.name);
      };
      var xiaoming = new Person("小明");
      console.log(xiaoming.hasOwnProperty("name"));
      console.log(xiaoming.hasOwnProperty("sayHello"));

 

 

2、in运算符

in运算符返回的也是一个布尔值,作用是检测某个对象有没有能力调用该属性或者是方法,不管这个属性或者方法是否在原型链上,只看调用能力

语法:

字符串 in 对象
  function Person(name) {
        this.name = name;
      }
      Person.prototype.sayHello = function () {
        alert("你好,我是" + this.name);
      };
      var xiaoming = new Person("小明");
      console.log("name" in xiaoming); 
      console.log("sayHello" in xiaoming); 

 

 

3、 instanceof运算符

instanceof运算符返回的是一个布尔值,作用是用来检测某一个对象是不是某一个函数的实例

原理是:o instanceof F,如果o在原型链上,返回的就是true,否则返回false

  function Person(name) {
        this.name = name;
      }
      Person.prototype.sayHello = function () {
        alert("你好,我是" + this.name);
      };

      function Dog() {}
      var xiaoming = new Person("小明");
      console.log(xiaoming instanceof Person); 
      console.log(xiaoming instanceof Object); 
      console.log(xiaoming instanceof Dog);

 

 

 

因为Person的prototype在xiaoming的原型链上,所以,xiaoming instanceof Person 返回的就是true,又因为Object的prototype也在小明的原型链上,所以xiaoming instanceof Object 返回的也是true,但是Dog

就和小明没有关系了,所以返回false

 

再看下一个小题目

console.log(Object instanceof Object)
console.log(Function instanceof Function)
console.log(Number instanceof Number)
console.log(Function instanceof Object)

此时我们会发现Number instanceof Number 返回的是false

 

 

 

发现Number 的原型链上根本没有Number什么事,本质上和Function和Object产生的关系,所以

console.log(Number instanceof Function)
console.log(Number instanceof Object)

 

 

发现Object.prototype是所有的对象原型链终点,所以 任何元素 instanceof Object 都是true

x instanceof Object // true

我们也发现了内置构造 instanceof 自己是false,但是由于Function是自己new自己,所以返回的是true

Function instanceof Function   //true

4、constructor属性

任何一个prototype对象天生都有一个constructor属性,指向的是对应的构造器

function Person(name) {
        this.name = name;
      }
      var xiaoming = new Person("xiaoming");
      console.log(Person.prototype.constructor);
      console.log(Person.prototype.constructor == Person);

 

 

可以验证一下,constructor属性是否在prototype上面

   function Person(name) {
        this.name = name;
      }
      var xiaoming = new Person("xiaoming");
      console.log(Person.prototype.hasOwnProperty("constructor")); 
      console.log(Person.hasOwnProperty("constructor"));

 

posted @ 2022-01-03 21:46  keyeking  阅读(1183)  评论(0编辑  收藏  举报