js原型和原型链学习笔记详解

首先做到题看看对原型和原型链的理解如何

//第一题
var F = function () {}
Object.prototype.a = function () {}
Function.prototype.b = function () {}

var f = new F();

console.log(f.a, f.b, F.a, F.b);

//第二题
function A() {}
function B(a) {
    this.a = a;
}
function C(a) {
    if (a) {
        this.a = a;
    }
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;

console.log(new A().a);
console.log(new B().a);
console.log(new C(2).a);

在这里就不揭晓答案了,否则一个不注意看到了答案就测试不了自己了
这都是很简单的题了,如果做错了,或者做的过程中磕磕碰碰,可要好好看看下面的讲解咯
最后还有一道压轴题,我相信看完之后可以很轻松做出来

原型和原型链

  • 所有对象都是通过new 函数创建
  • 所有的函数也是对象
    • 函数中可以有属性,比如Array.from()、Number.isNaN()
  • 所有对象都是引用类型

在这里插入图片描述

原型 prototype

所有函数都有一个属性:prototype,称之为函数原型

默认情况下,prototype是一个普通的Object对象

默认情况下,prototype中有一个属性,constructor,它也是一个对象,它指向构造函数本身。

隐式原型 proto

在这里插入图片描述
所有的对象都有一个属性:__proto__,称之为隐式原型,因为函数也是对象,所以函数也拥有__proto__

默认情况下,隐式原型指向创建该对象的函数的原型。

function test(){
            
}

var obj = new test();
console.log(obj.__proto__ === test.prototype); //true;

请看下面两道面试题:

  function A() {}

        function B() {}

        function create() {
            if (Math.random() < 0.5) {
                return new A();
            } else {
                return new B();
            }
        }

  var obj = create();
  //如何得到创建obj的构造函数名称
  console.log(obj.__proto__.constructor.name);

function A() {}

var obj1 = new A();
var obj2 = new A();
obj1.abc = 123;
obj2.__proto__.bcd = 456;

//输出结果是多少
console.log(obj1.abc, obj2.abc); //123 undefined
console.log(obj1.__proto__.bcd, obj2.__proto__.bcd);//456  456

第二个输出都是456的原因就是,obj2.proto.bcd = 456;就相当于给A的原型链上添加了一个属性bcd:A.prototype.bcd = 456
所以A的所有对象都有了一个bcd属性

当访问一个对象的成员时:

  1. 看该对象自身是否拥有该成员,如果有直接使用
  2. 在原型链中依次查找是否拥有该成员,如果有直接使用
  //函数功能:给字符串的首字母大写
  String.prototype.camel = function() {
            return this.replace(/\b(\w)(\w*)\b/g, function($, $1, $2) {
                return $1.toUpperCase() + $2;
            }).replace(/\s/g, "");
        }

上面这种给对象原型添加属性或者方法的方式,有许多叫法,最贴切的应该是猴子补丁
猴子补丁:在函数原型中加入成员,以增强起对象的功能,猴子补丁会导致原型污染,使用需谨慎。

原型链

记住了这张图,我想应该可以应付大多数关于原型链的题目了
在这里插入图片描述
特殊点:

  1. Function的__proto__指向自身的prototype
  2. Object的prototype的__proto__指向null
//第一种方法
function A() {}
var obj = new A();
obj.toString = function() {
    return "123";
}

//第二种方法
function A() {}
A.prototype.toString = function() {
    return "123";
}
var obj = new A();

此时在调用obj.toString()得到的结果就是’123’,产生这种情况的原因就是,当obj调用toString时
在自己身上就找到了需要的东西,就不会再向上找。

第二种方法会把toString方法添加在函数的原型上,被所有的对象共享,只要是通过这个函数创建的对象都会共享这个函数
如果想强行调用Object的toString可以这样做:

Object.prototype.toString.call(obj);

来看最后一道题目,可能比较难,不过,只要记住了上面的图,这都不是事

function User() {}
User.prototype.sayHello = function() {}

var u1 = new User();
var u2 = new User();

console.log(u1.sayHello === u2.sayHello);
console.log(User.prototype.constructor); 
console.log(User.prototype === Function.prototype);
console.log(User.__proto__ === Function.prototype);
console.log(User.__proto__ === Function.__proto__);
console.log(u1.__proto__ === u2.__proto__);  
console.log(u1.__proto__ === User.__proto__); 
console.log(Function.__proto__ === Object.__proto__); 
console.log(Function.prototype.__proto__ === Object.prototype.__proto__)
console.log(Function.prototype.__proto__ === Object.prototype); 

原型链的应用

基础方法

W3C不推荐直接使用系统成员__proto__

Object.getPrototypeOf(对象)
获取对象的隐式原型

Object.getPrototypeOf === obj.proto

Object.prototype.isPrototypeOf(对象)
判断当前对象(this)是否在指定对象的原型链上

function A() {};
var obj = new A();
var o = {};
o.isPrototypeOf(obj);//false
//换种写法
Object.getPrototypeOf(o).isPrototypeOf(obj); //true

因此o的隐式原型是Object.proto,正好它也在obj的原型链上,所以是true,具体可以看上图

对象 instanceof 函数

判断函数的原型是否在对象的原型链上

Object.create(对象)

创建一个新对象,其隐式原型指向指定的对象

Object.prototype.hasOwnProperty(属性名)

判断一个对象自身是否拥有某个属性,在循环遍历的时候经常使用

应用

类数组转换为真数组

Array.prototype.slice.call(类数组);
这个方法与[].slice.call(类数组)的区别:后者的[]是重新创建了一个数组从而得到slice方法,但是这是不必要的


创作不易,转载请注明出处
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值