js高级,函数的原型和原型链

函数的prototype

  1. 函数的prototype属性(图)
    - 每个函数都有一个propotype属性,它默认指向一个object空对象(即称为:原型对象)
    - 原型对象就相当于一个公共区域,所有同一个类的实例都可以访问到这个原型对象
    - 我们可以将对象中共有的内容,统一设置到原型对象中
    - 查找时:
    当我们访问对象的一个属性或方法时,它会在对象自身中寻找,如果有则直接使用,如果没有则他会在原型对象中寻找,如果找则直接使用
    - 设置时:
    - 当我们设置对象的属性值时,不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
    - - 也就是说添加的属性直接添加到对象上,而不是原型上。
    - 方法一般定义在原型中,属性一般通过构造函数定义在对象上
    - - 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每一个对象都具有这些属性和方法啦

  2. 给原型对象添加属性(一般都是方法)
    - 作用:函数的所有实例对象自动拥有原型中的属性(方法)

  3. 如果函数是普通函数调用prototype没有任何作用

  4. 当函数以构造函数形式调用时,它所创建的对象中都有一个隐含的属性
    - 指向该构造函数的原型对象,我们可以通过__proto__来访问该属性 (对象的隐式原型的值为其对应的构造函数的的显示原型的值)

function MyClass(){
}
//向MyClass的原型中添加属性a
MyClass.prototype.a=123;
//向mc中添加a属性
mc.a="我是mc中的a";
var mc=new MyClass();
var mc2=new MyClass();
// 指向该构造函数的原型对象,通过__proto__来访问该属性
console.log(mc.__proto__ === MyClass.prototype);//true
console.log(mc2.__proto__ === MyClass.prototype);//true
//先查看自身,再查看原型里有没有
console.log(mc.a);//我是mc中的a
console.log(mc2.a);//123

补充JS构造函数修改部分

/*
创建一个Person构造函数

*/
function Person(name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
//向对象中添加一个方法
/*this.sayName=function(){
alert(this.name);
};*/
//this.sayName=fun;
}
//将sayName方法在全局作用域中定义
/*
将函数定义在全局作用域,污染了全局作用域的命名空间
而且定义在全局作用域中很不安全
*/

/*function fun(){
alert(this.name);
};*/

//向原型中添加sayName的方法
Person.prototype.sayName=function(){
alert(this.name);
};

//创建一个Person的实例
var per=new Person("A",18,"男");
per.sayName();
per2.sayName();
var per2=new Person("B",28,"男");
console.log(per.sayName == per2.sayName);//true

原型对象中有一个属性constructor,它指向函数对象

console.log(Date.prototype,typeof(Date.prototype));
function Fun(){

}
Fun.prototype.test=function(){
console.log('test()')
}
console.log(Fun.prototype);//默认指向一个object空对象(没有我们的属性)
console.log(Date.prototype.constructor===Date)//true
console.log(Fun.prototype.constructor===Fun)
//给原型对象添加添加属性==》实例对象可以访问
Fun.prototype.test=function(){
 	console.log('test()')
 }

没搞懂啥意思啊

显式原型和隐式原型

  1. 每个函数function都有一个prototype,即显示原型属性
    - 原型对象也是对象,所以它也有原型
    - 隐式原型链:
    - 当我们在使用一个对象的属性或方法时,会先在自身中寻找,自身中如果有则直接使用;
    - 如果没有则去原型对象中寻找,如果原型对象中有,则使用;
    - 如果没有则去原型的原型中寻找,直到找到Object对象原型,Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined

    - Object的原型对象时原型链的尽头
    - console.log(Object.prototype.__proto__);//null
    - 一般最多只有两层原型
    - - 以下几个关系说明了几条原型链
    - fn.__proto__= Fn.prototype;
    - fn.__proto__.__proto__==>Object.prototype;
    - Fn.prototype.__proto__==>Object.prototype;
    - Object.prototype.__prototype__=null;
    - Fn.__proto__==>Function.prototype;
    - Fn.__proto__.__proto__==>Object.prototype;
//原型中没找到
console.log(mac.__proto__.hasOwnProperty("hasOwnProperty"));//false
//在原型的原型中找到了
console.log(mac.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));//true
  1. 每个实例对象都有一个_proto_,即隐式原型属性
  2. 对象的隐式原型的值为其对应的构造函数的的显示原型的值
//定义构造函数
function Fn(){
}
//创建实例对象
var fn=new Fn()
//给原型添加方法
Fn.prototype.test=function(){
console.log("test()")
}
//通过实例调用原型的方法
fn.test()
  1. 在JS对象和构造函数中讲到instanceof的使用,这里结合原型进行补充:
    - 语法:实例对象 instanceof 构造函数
    - 如果构造函数的显示原型对象在实例对象的原型链上,返回true,否则返回false
    -

  2. 总结:
    - 函数的prototype属性:在定义函数时自动添加的,默认值是一个空Object对象,内部语句:this.prototype={};
    - 对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值,内部语句:fn.__proto__=Fn.prototype;
    - 程序员能直接操作显示原型,但不能直接操作隐式原型 (ES6之前)
    - 所有函数都是Function的实例(包含Function自身)
    - console.log(Function__proto__ === Function.prototype)

原型面试题:

function A (){

}
A.prototype.n=1
var b=new A()
A.prototype={
n:2,
m:3
}
var c=new A()
//开始b的原型就是A的原型,后来A的原型改变,c的原型为新的A的原型
console.log(b.n,b.m,c.n,c.m)//1 undefined 2 3
var F=function(){
}
Object.prototype.a=function(){
console.log('a()')
}
Function.prototype.b=function(){
console.log("b()")
}
var f=new F()
f.a()//a()
f.b()//报错,Function.prototype不和f在一条原型链上,
F.a()//a()
F.b()//b()
console.log(f)
console.log(Object.prototype)
console.log(Function.prototype)

你可能感兴趣的:(js高级,函数的原型和原型链)