原型链

11,780次阅读
没有评论

共计 2846 个字符,预计需要花费 8 分钟才能阅读完成。

常见概念

  • 构造函数

  • 构造函数 - 扩展

  • 原型规则和示例

  • 原型链

  • instanceof

构造函数

任何一个函数都可以被 new,new 了之后,就成了构造方法。

如下:

function Foo(name, age) {
    this.name = name;
    this.age = age;
    //retrun this;   // 默认有这一行。new 一个构造函数,返回一个对象
}

var fn1 = new Foo('smyhvae', 26);
var fn2 = new Foo('vae', 30); //new 多个实例对象

与普通函数相比,构造函数有以下明显特点:

  • 用 new 关键字调用。

  • 不需要用 return 显式返回值的,默认会返回 this,也就是新的实例对象。

  • 建议函数名的首字母大写,与普通函数区分开。

参考链接:

当 new 之后,this 会先变成一个空对象,然后通过 this.name = name 来赋值。

构造函数的扩展

原型链

上图中发现,数组、对象、函数也有构造函数,它们的构造函数是 Array、Object、function。实际开发中,都推荐前面的书写方式。

原型规则

原型规则是学习原型链的基础。原型规则有五条,下面来讲解。

规则 1

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

举例:

原型链

规则 2

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

原型链

其实,规则 2 是规则 1 的特例,只不过,js 语法帮我们自动加了 规则 2。

规则三

所有的 函数 (不包括数组、对象),都有一个prototype 属性,属性值是一个 普通的对象 prototype 的含义是 显式原型。(实例没有这个属性)

原型链

规则四

所有的 引用类型 (数组、对象、函数),_proto_ 属性指向它的 构造函数 prototype值。

原型链

总结:以上四条,要先理解清楚,然后再来看下面的第五条。

规则五

当试图获取一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的 _proto_ 中寻找(即它的构造函数的prototype)。

举例代码 1

// 创建方法
function Foo(name) {this.name = name;}

Foo.prototype.alertName = function () {
    // 既然 Foo.prototype 是普通的对象,那也允许给它添加额外的属性 alertName
    console.log(this.name);
};

var fn = new Foo('smyhvae');
fn.printName = function () {console.log(this.name);
};

// 测试
fn.printName(); // 输出结果:smyhvae
fn.alertName(); // 输出结果:smyhvae

上方代码中,虽然 alertName 不是 fn 自身的属性,但是会从它的构造函数的 prototype 里面找。

** 扩展:** 遍历循环对象自身的属性

我们知道,for in循环可以遍历对象。针对上面的那个 fn 对象,它自身有两个属性:nameprintName,另外从原型中找到了第三个属性alertName。现在,如果我们对 fn 进行遍历,能遍历到两个属性还是三个属性呢?

答案:两个。因为,高级浏览器中已经在 for in循环中屏蔽了来自原型的属性。但是,为了保证代码的健壮性,我们最好自己加上判断,手动将第三个属性屏蔽掉:

for (var item in fn) {if (fn.hasOwnProperty(item)) {console.log(item);
    }
}

原型链

还是拿上面的 举例代码 1 举例,如果此时在最后面加一行代码:

	fn.toString();   // 去 fn._proto_._proto_ 中查找 toString()方法

上面的代码中,fn 直接调用了 toString()方法,这是因为它通过 原型链 ,去_proto__proto_里找到了 Object,而Object 是由 toString() 方法的。

instanceof

格式:

对象 instanceof 构造函数;

instanceof的作用:用于判断 引用类型 属于哪个 构造函数

例 1:判断一个变量是否为数组:变量 instanceof Array

例 2:

function Person() {}

//p--->Person.prototype--->Object.prototype--->null
var p = new Person();
// 构造函数的 ** 原型 ** 是否在 p 对象的原型链上!console.log(p instanceof Person);

例 3:

fn instanceof Foo;

上面这句话,判断逻辑是:fn 的 _proto_ 一层一层往上找,看能否对应到 Foo.prototype

原型链如下:(重要)

原型链

注意,Object 这个构造方法的显式原型是 null,这是一个特例。

issues 101 补充:通过原型链查找时,如果你找的是一个属性的话,则返回 undefined,如果你找的是一个方法,则报错。

常见题目

  • 如何准确判断一个变量是数组类型

  • 写一个原型链继承的例子

  • 描述 new 一个对象的过程

  • zepto(或其他框架)源码中如何使用原型链

下面分别讲解。

题目一:如何准确判断一个变量是数组类型

答案:

var arr1 = [];

console.log(arr1 instanceof Array); // 打印结果:true。console.log(typeof arr1); // 打印结果:object。提示:typeof 方法无法判断是否为数组

上方代码表明,只能通过 instanceof 来判断是否为数组。而 typeof 的打印结果是 object。

题目二:写一个原型链继承的例子

来看个基础的代码:

原型链

上面这个例子是基础,但是,在回答面试官的问题时,不要写上面的例子。要写成下面这个例子:(更贴近实战)

function DomElement(id) {this.dom = document.getElementById(id);
}
DomElement.prototype.html = function (val) {
    var ele = this.dom;
    if (val) {
        ele.innerHTML = val;
        return this;
    } else {return ele.innerHTML;}
};
DomElement.prototype.on = function (type, fn) {
    var ele = this.dom;
    ele.addEventListener(type, fn);
    return this;
};
var div1 = new DomElement('div1');
div1.html('<p> 这是一段文字 </p >');
div1.on('click', function () {console.log('clicked');
});

题目三:描述 new 一个对象的过程

(1)创建一个新对象

(2)this 指向这个新对象

(3)执行代码(对 this 赋值)

(4)返回 this

参考链接:

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-10发表,共计2846字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)