原型链是js面向对象的基础,非常重要。
一,创建对象的几种方法:
1,字面量
var o1 = {
name:'o1'
};
2,构造函数
var M = function(name){
this.name = name;
};
var o2 = new M('o2');
var a = {} 其实是 var a = new Object()的语法糖,推荐使用前者
var a = [] 其实是 var a = new Array()的语法糖,推荐使用前者
function Foo(){} 其实是 var Foo = new Function()的语法糖,推荐使用前者
 

3,Object.create(Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 )
var P = {name:'o3'};
var o3 = Object.create(P);

二,原型链

JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
 Object.getPrototypeOf(Object.prototype) //null

Object.prototype === Object.getPrototypeOf( {} ); //true
5条原型规则
1,所有的引用类型(数组,对象,函数),都具有对象特性,即可自由扩展属性
2,所有的引用类型(数组,对象,函数),都有一个__proto__属性(隐式原型),属性值是一个普通的对象
3,所有的函数,都有一个prototype属性(显式原型),属性值也是一个普通的对象
4,所有的引用类型(数组,对象,函数)__proto__属性值指向它的构造函数的prototype属性值
5,当试图得到一个引用类型(数组,对象,函数)的某个属性时,如果这个引用类型本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找

看下图

 

三,instanceof原理

判断一个函数是否是一个变量的构造函数

工作原理:判断实例对象的__proto__属性和构造函数的prototype是否同一个地址,只要在原型链上的构造函数,都会被instanceof认为是实例的构造函数。如图:

    // 判断实例对象的proto属性和构造函数的prototype是否同一个地址
// 只要在原型链上的构造函数,都会被instanceof认为是实例的构造函数
var M = function(name) { this.name = name; };
var o2 = new M('o2');
o2.__proto__ === M.prototype //true
M.prototype.__proto__ === Object.prototype //true
o2.__proto__.__proto__ === Object.prototype //true o2 instanceof M //true
o2 instanceof Object //true // 用constructor属性判断更严谨
o2.__proto__.constructor === M //true
o2.__proto__.constructor === Object //false

四,new运算符工作原理

    // new运算符及背后工作原理 new后跟构造函数
// 1,一个新对象被创建,它继承自func.prototype(构造函数的原型对象)
// 2,构造函数func被执行,执行的时候,相应的传参会被传入,同时上下文(this)会被指定为这个新实例
// 3,如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果,如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象
var new2 = function(func) {
var o = Object.create(func.prototype);
var k = func.call(o);
if (typeof k === 'object' && k != null) {
return k;
} else {
return o;
}
};

五,原型链继承的例子

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<title>proto</title>
</head> <body>
<div id="div1">123</div>
<script>
// 封装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>234p</p>').on('click', function() {
alert('1');
}).html('<p>js</p>');
</script>
</body> </html>

六:原型实际应用

1,看一个平时使用jquery或者zepto的例子:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<title>jquery</title>
</head> <body>
<p>jquery 1</p>
<p>jquery 2</p>
<p>jquery 3</p>
<div id="div1">
<p>jquery test in div</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
var $p = $('p');
$p.css('color', 'red'); //css是原型方法
console.log($p.html()); //html是原型方法,这里只打印第一个 jquery 1 var $div = $('#div1');
$div.find('p').css('color', 'blue'); //find,css是原型方法
console.log($div.html()); //html是原型方法 <p style="color: blue;">jquery test in div</p>
</script>
</body> </html>
2,zepto如何使用原型(简化版)-my-zepto.js
(function(window) {
// 空对象
var zepto = {}; // 构造函数
function Z(dom, selector) {
var i, len = dom ? dom.length : 0;
for (i = 0; i < len; i++) {
this[i] = dom[i];
}
this.length = len;
this.selector = selector || '';
} zepto.Z = function(dom, selector) {
// 注意,出现了 new 关键字
return new Z(dom, selector);
} zepto.init = function(selector) {
// 源码中,这里的处理情况比较复杂,但因为本次只针对原型,因此这里就弱化了
var slice = Array.prototype.slice;
var dom = slice.call(document.querySelectorAll(selector));
return zepto.Z(dom, selector);
} // 使用zepto的$
var $ = function(selector) {
return zepto.init(selector);
}
window.$ = $; $.fn = {
constructor: zepto.Z,
css: function(key, value) {
console.log('css'); },
html: function(value) {
// console.log('html');
return '这是一个模拟的html函数';
}
} zepto.Z.prototype = Z.prototype = $.fn; //!!! })(window)
测试:新建zepto.html
<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<title>zepto</title>
</head> <body>
<p>zepto 1</p>
<p>zepto 2</p>
<p>zepto 3</p>
<div id="div1">
<p>zepto test in div</p>
</div>
<script src="./my-zepto.js"></script>
<script>
var $p = $('p');
$p.css('color', 'red'); //css是原型方法
console.log($p.html()); //html是原型方法,这是一个模拟的html函数"
</script>
</body> </html>
3,jquery如何使用原型(简化版)-my-jquery.js
(function(window) {
var jQuery = function(selector) {
// 注意new关键字,第一步就找到了构造函数
return new jQuery.fn.init(selector);
}
window.$ = jQuery; // 初始化 jQuery.fn
jQuery.fn = jQuery.prototype = { //!!!
constructor: jQuery, // 其他函数
css: function(key, value) { },
html: function(value) {
return 'html'; }
} // 定义构造函数-简化版
var init = jQuery.fn.init = function(selector) {
var slice = Array.prototype.slice;
var dom = slice.call(document.querySelectorAll(selector)); var i, len = dom ? dom.length : 0;
for (i = 0; i < len; i++) {
this[i] = dom[i];
}
this.length = len;
this.selector = selector || '';
} // 定义原型
init.prototype = jQuery.fn; })(window)

测试:新建jquery.html

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<title>jquery</title>
</head> <body>
<p>jquery 1</p>
<p>jquery 2</p>
<p>jquery 3</p>
<div id="div1">
<p>jquery test in div</p>
</div>
<script src="./my-jquery.js"></script>
<script>
var $p = $('p');
$p.css('color', 'red'); //css是原型方法
console.log($p.html()); //html是原型方法,这里只打印第一个 "jquery 1"
</script>
</body> </html>
4,如何体现原型的扩展性-插件机制
思考:为何要把原型方法放在$.fn?:扩展插件。(第一,构造函数的 prototype 肯定得指向能扩展的对象;第二,$.fn 肯定得指向能扩展的对象)
看一个简单的插件的例子:
$.fn.getNodeName = function(){
return this[0].nodeName;
}

好处:

1,只有$会暴露在window全局变量
2,将插件扩展统一到 $.fn.xxx 这一个接口,方便使用

实践:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<title>jquery</title>
</head> <body>
<p>jquery 1</p>
<p>jquery 2</p>
<p>jquery 3</p>
<div id="div1">
<p>jquery test in div</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
// 插件扩展
$.fn.getNodeName = function(){
// console.log(this);
console.log(this[0].nodeName);
}
</script>
<script>
// 验证
var $p = $('p');
$p.getNodeName() //P
$div1 = $('#div1');
$div1.getNodeName() //DIV
</script>
</body> </html>

JavaScript原型与原型链,原型的实际应用的更多相关文章

  1. javascript中的对象,原型,原型链和面向对象

    一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...

  2. JavaScript中的继承(原型链)

    一.原型链 ECMAScript中将原型链作为实现继承的主要方法,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 实例1: function SupType() { this.pro ...

  3. 【javascript基础】4、原型与原型链

    前言 荒废了好几天,在宿舍闷了几天了,一直想着回家放松,什么也没搞,论文就让老师催吧.不过,闲的没事干的感觉真是不好,还是看看书,写写博客吧,今天和大家说说函数的原型. 原型是什么 第一次看到这个的时 ...

  4. JavaScript 变量、函数与原型链

    定义 || 赋值 1-函数的定义 函数定义的两种方式: “定义式”函数:function fn(){ alert("哟,哟!"); } “赋值式”函数:var fn = funct ...

  5. JavaScript系列:再巩固-原型链

    图 1.实例:'对象(实例)'有属性__proto__,指向该对象(实例)的'构造函数的原型对象'. 2.方法:'构造函数'除了有属性__proto__,所有构造函数方法的__proto__指向Fun ...

  6. 深入理解JavaScript中的继承:原型链篇

    一.何为原型链 原型是一个对象,当我调用一个对象的方法时,如果该方法没有在对象里面,就会从对象的原型去寻找.JavaScript就是通过层层的原型,形成原型链. 二.谁拥有原型 任何对象都可以有原型, ...

  7. JavaScript中的继承与原型链

    先看一个例子 function User(){} var u1 = new User(); console.log(u1.prototype);// undefined 使用对象实例无法访问到prot ...

  8. javascript中的构造函数和原型及原型链

    纯属个人理解,有错误的地方希望大牛指出,以免误人子弟 1.构造函数: 构造函数的作用 : 初始化由new创建出来的对象    new 的作用: 创建对象(空对象) new 后面跟的是函数调用,使用ne ...

  9. Javascript之其实我觉得原型链没有难的那么夸张!

    原型链.闭包.事件循环等,可以说是js中比较复杂的知识了,复杂的不是因为它的概念,而是因为它们本身都涉及到很多的知识体系.所以很难串联起来,有一个完整的思路.我最近想把js中有点意思的知识都总结整理一 ...

  10. 还在问什么是JavaScript构造函数、实例、原型对象以及原型链?看完这篇你就懂

    1概述 ES6, 全称 ECMAScript 6.0 ,2015.06 发版.在ES6之前,对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和它们的特征. 2构造函数 构造函数是一种特 ...

随机推荐

  1. CGI 和 FastCGI 协议的运行原理

    目录 介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 ...

  2. LabVIEW(十一):条件结构的巧用

    一.LabVIEW中条件结构使用起来并不是那么简便,主要体现在两点: 1.由隧道的产生引起的一些问题.(当箭头停留在隧道处时不显示为“自动索引隧道”,所以此隧道非彼隧道) 2.由多层结构判断引起的不易 ...

  3. Swift5 语言指南(八) 函数

    函数是执行特定任务的自包含代码块.您为函数指定了一个标识其功能的名称,此名称用于“调用”函数以在需要时执行其任务. Swift的统一函数语法足够灵活,可以表达从没有参数名称的简单C风格函数到具有每个参 ...

  4. 日志查看技巧之筛选&去重[排查篇]

    引语:相信大家都会偶尔遇到要排查问题发生的原因的情况,那这种时候,我们最有力后盾就是日志文件了,所以谨记日志记录真的很重要.但是日志文件往往是很大的文件,而且里面有太多的东西可能不是我们需要的,如无数 ...

  5. 在notepad++中使用正则匹配功能(一-龥!-~) 中文[利刃篇]

    用正则时间越久,人就越懒,就越知道正则的强大.正则,不只是在代码里用到,在字符查找是也会用到,学会适当使用正则,将会使你的工作事办功倍!但是,中文却是一个砍,不容易过. 于是在用notepad++,也 ...

  6. B - Red and Black 问题思考

    红黑地板问题 There is a rectangular room, covered with square tiles. Each tile is colored either red or bl ...

  7. Linux入门搭建可视化桌面环境小合集virtual box centOS7.10

    常用命令: 关联主机与虚拟机(方便文件共享): # sudo mount -t vboxsf share(主机文件夹名) /usr/share(虚拟机内自创) Linux shell进入root模式: ...

  8. ubuntu16.04 程序开机自启动设置及启动优化

    使用过程中,为了方便使用,有一些程序需要开机时自启动应用,下面将介绍一下ubuntu16.04下程序的开机自启动设置方法. 1  建立一个可执行程序的运行脚本如 keepalive.sh.内部写入要执 ...

  9. Apache Commons Beanutils 一 (使用PropertyUtils访问Bean属性)

    BeanUtils简要描述 beanutils,顾名思义,是java bean的一个工具类,可以帮助我们方便的读取(get)和设置(set)bean属性值.动态定义和访问bean属性: 细心的话,会发 ...

  10. ckeditor 在dwz里面使用

    在ckeditor的配置的过程中,所有的配置的地方都配置了,但是就是不显示编辑器(编辑器代码如下),很郁闷哦 1 <textarea id="editor1" name=&q ...