原型链是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>

最新文章

  1. Redis安装及实现session共享
  2. SqlServer数据冗余的问题和解决
  3. 权威指南之脚本化jquery
  4. Cannot update paths and switch to branch at the same time(转)
  5. angularJS+requireJS实现controller及directive的按需加载
  6. 如何在require中使用VUE
  7. Java注释分类
  8. 系列文章|OKR与敏捷(三):赋予团队自主权
  9. oracle 时间日期常用语句及函数
  10. Spring data jpa JavassistLazyInitializer 不仅是Json序列化问题.以及解决办法
  11. LearnX控件漏洞挖掘与利用
  12. 关于W8.1不能安装VS2015(包括2017等)
  13. APNS推送服务证书制作 图文详解教程(新)
  14. Spring配置文件&lt;context:property-placeholder&gt;标签使用漫谈
  15. (6)Cocos2d-x 3.0坐标系详解
  16. 实例37foreach遍历数组
  17. 阿里云ECS下Ubuntu 16.04系统安装python3.6.5 环境并设置为默认
  18. Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined) A B 水 搜索
  19. 转:Java SoftReference 使用构建对象缓存
  20. 共鸣(resonance)

热门文章

  1. Request模块—数据解析工具
  2. PICE(5):MongoDBStreaming - gRPC -MGO Service
  3. Linux 定位网络不通问题
  4. B - Red and Black 问题思考
  5. vue elementui 引入第三方icon iconfront
  6. [每天解决一问题系列 - 0009] File System Redirector
  7. 第四章:Android架构
  8. 【详解】Spring Security 之 SecurityContext
  9. mybatis教程5(延迟加载和缓存)
  10. 单例模式写MySQL model类,简单的增、删、改、查