原型链是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. 数据结构(一): 键值对 Map

    Map基本介绍 Map 也称为:映射表/关联数组,基本思想就是键值对的关联,可以用键来查找值. Java标准的类库包含了Map的几种基本的实现,包括:HashMap,TreeMap,LinkedHas ...

  2. 9:集合collection

    第一 集合框架的概述 集合类的由来:  对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定,就使用集合容器进行存储.   集合和数组的区别: 数组虽然可以存储对象,但是长度是固定的:集合长度 ...

  3. Android网络请求与数据解析,使用Gson和GsonFormat解析复杂Json数据

    版权声明:未经博主允许不得转载 一:简介 [达叔有道]软件技术人员,时代作者,从 Android 到全栈之路,我相信你也可以!阅读他的文章,会上瘾!You and me, we are family ...

  4. 数组的三种声明方式总结、多维数组的遍历、Arrays类的常用方法总结

    1. 数组的三种声明方式 public class WhatEver { public static void main(String[] args) { //第一种 例: String[] test ...

  5. Win10手记-为应用集成SQLite(二)

    接上篇内容,这里给大家分享我的辅助访问类,采用了异步方法,封装了常用的访问操作,一些操作还是纯CLI的. SQLiteDBManager using System; using System.Coll ...

  6. Docker部署Vue 工程包

    docker部署 Vue 工程包 目录结构 [root@host ~]# tree front/ front/ ├── dist.conf ├── dist.zip ├── Dockerfile └─ ...

  7. 脚手架vue-cli系列五:基于Nightwatch的端到端测试环境

    不同公司和组织之间的测试效率迥异.在这个富交互和响应式处理随处可见的时代,很多组织都使用敏捷的方式来开发应用,因此测试自动化也成为软件项目的必备部分.测试自动化意味着使用软件工具来反复运行项目中的测试 ...

  8. asp.net mvc开发过程中的一些小细节

    现在做网站用mvc越来越普及了,其好处就不说了,在这里只记录一些很多人都容易忽视的地方. 引用本地css和js文件的写法 这应该是最不受重视的地方,有同事也说我有点小题大作,但我觉得用mvc还是得有一 ...

  9. MathWorks官方消息:神经网络工具箱不能编译

    各位会员大家好,大家关心的问题,我已经大部分得到答案. 10月25号-27号我访问了MathWorks公司在波士顿的总部,大家经常关心的问题,我大部分都得到了答案. 关于神经网络工具箱,我与Matla ...

  10. GraphX之Pregel(BSP模型-消息传递机制)学习

    /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreem ...