javascript面向对象编程(OOP)——汇总
目录
一、JS的解析与执行过程
- 预处理阶段
- 执行阶段
二、作用域
- 块作用域
- 函数作用域
- 动态作用域
- 词法作用域
三、闭包
- 什么是闭包
- 闭包的好处
四、函数与对象
- 对象
函数
原型(prototype)
this
new的理解
五、封装
六、继承
七、多态
八、项目实战minijQuery
一、JS的解析与执行过程
1.1、预处理阶段
注意:js预处理阶段会扫描所有var声明的变量,把var声明的变量或函数存放到词法作用域里,如果是变量初始值为“undefined”,如果是函数则指向函数;
全局(window)
词法作用域(Lexical Environment):顶级的Lexical Environment是window;
1、先扫描函数声明后扫描变量(var声明);
2、处理函数声明有冲突,会覆盖;处理变量声明时有冲突,会忽略。
函数
词法作用域(Lexical Environment):每调用一次,产生一个Lexical Environment;
1、先函数的参数:比如arguments(函数内部对象,代表函数实参,可通过下标获取调用函数时传的实参);
2、先扫描函数声明后扫描变量(var声明);
3、处理函数声明有冲突,会覆盖;处理变量声明时有冲突,会忽略。
1.2、执行阶段
1、给预处理阶段的成员赋值
2、如果没有用var声明的变量,会成为最外部LexicalEnvironment的成员(即window对象的变量)
函数内部对象:arguments
<script>
/*提示:*/
// arguments是每一个函数内部的一个对象
// 可以访问实际传递给函数的参数的信息。
// 声明的时候参数的个数与实际调用时无关 function add(a,b){
console.log(add.length);// 形参的个数
console.log(arguments.length);// 实际传过来的参数
var total = 0;
for(var i = 0;i< arguments.length;i++){
total += arguments[i];
}
return total;// 返回实参的总和
} // 调用时传的实参
var result = add(1,2,3,4,5);
var result2 = add(1,2); console.log(result);//
console.log(result2);//
</script>
二、作用域
提示:js的作用域不是块级别的;js的作用域是函数级别的。
2.1、块作用域
2.2、函数作用域
2.3、动态作用域
2.4、词法作用域
代码示例:
<script>
//js作用域
// 定义:用来查找变量的值的规则集;决定一个变量的范围
// 提示:js的作用域不是块级别的;js的作用域是函数级别的。
// javascript使用的是词法作用域,它的最重要的特征是它的定义过程发生在代码的书写阶段 /*以下js代码用立即调用写法(私有化),避免变量冲突*/ //1、块作用域:代码在花括号里面有效(js没有块作用域)
(function(){
for(var i=0;i<5;i++){
var a = i ;
}
// 在花括号外面可以访问到i,a
console.log(i);//
console.log(a);//
})(); //2、函数作用域:代码在function()函数的花括号里面有效
(function(){
var message = "函数外部的";
function fn(){
var message = "函数内部的";
console.log(message);// 函数内部的
}
console.log(message);// 函数外部的
})(); //3、动态作用域:在运行时决定(是this指向的表现;谁调用,this指向谁);动态作用域其实是指this的词法作用域
// 动态作用域并不关心函数和作用域是如何声明以及在任何处声明的,只关心它们从何处调用。
// 换句话说,作用域链是基于调用栈的,而不是代码中的作用域嵌套
(function(){
var a = 2;
function foo() {
console.log( a );
}
function bar() {
var a = 3;
foo();// 此时this===window
}
bar();//
})();
/*
var a = 2;
bar = {
a:3,
foo:function(){
console.log(this.a);
}
}
bar.foo();//3
*/ //4、词法作用域:词法作用域(也称为静态作用域或闭包)
// js的作用域解析,用new Function创建函数
(function(){
// 闭包
var a = 2;
function bar() {
var a = 3;
return function(){
console.log(a);// 此时捕获a=3
};
}
var foo = bar();
foo();//
})(); // 如果处于词法作用域,也就是现在的javascript环境。变量a首先在foo()函数中查找,没有找到。于是顺着作用域链到全局作用域中查找,找到并赋值为2。所以控制台输出2
// 如果处于动态作用域,同样地,变量a首先在foo()中查找,没有找到。这里会顺着调用栈在调用foo()函数的地方,也就是bar()函数中查找,找到并赋值为3。所以控制台输出3 //小结:两种作用域的区别,简而言之,词法作用域是在定义时确定的,而动态作用域是在运行时确定的 </script>
三、闭包(Closure)
3.1、什么是闭包
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数,内部函数并访问父函数的局部变量”。
理解闭包:
1、闭包可以理解为一个对象,里面包含函数以及被函数捕获的变量 , 一个圈里包含函数与捕获的变量
2、也可以只把函数捕获的变量称之为闭包。
<script>
//如何写会产生闭包
function P(){
var a = 5;
var b = 6;
return function C(){
console.log(b);//此时捕获变量b,值为6
} }
var result = P();
result();// 6
</script>
产生闭包的条件:
1、函数内部包含子函数;
2、子函数访问父函数的变量;
3.2、闭包的好处
用途:一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
<script>
// 闭包实例
function Person(){
var age = 1;
this.getAge = function(){
return age ;
} this.setAge = function(val){
age = val;
}
}
var p = new Person();
p.setAge(20);
console.log(p.getAge());
</script>
代码示例:
<script type="text/javascript">
/*闭包--理解*/
// 提示:this由运行时决定! // 题目一:理解r1与r2的输出
function addFactory(){
var adder = 5;
return function(data){
adder += data;// 此时adder变量是闭包捕获到的值
return adder;
}
}
var adder1 = addFactory();
var r1 = adder1(1);//6
r1 = adder1(1);//7 var adder2 = addFactory();
var r2 = adder2(2);//7
r2 = adder2(2);//9 // 题目二:下面的代码输出什么
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;// 输出"The Window";this = window;
//return object.name;// 输出"My object"
};
}
};
//alert(object.getNameFunc()());// The Window // 理解二:
var fun = object.getNameFunc();// 返回一个函数,此时函数this指向window;window.fun()
alert(fun());// 所以,输出是:"The Window" // 题目三:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;//this = object;
return function(){
return that.name;//闭包捕获父函数的that,that = object;
};
}
};
alert(object.getNameFunc()());// My Object // 理解三:
// var obj = object.getNameFunc();
// alert(obj());// 此时函数由于内部的name是object调用 </script>
四、函数与对象
4.1、对象
4.2、函数
4.3、原型(prototype)
javascript对象部署:
JavaScript是一种通过原型实现继承的语言;在JavaScript中所有都是对象,原型(prototype)也是一个对象,通过原型可以实现对象的属性继承;
prototype:在js中是函数特有的属性;指向该函数的原型(this.prototype)
__proto__:在js中是所有对象都有的属性;指向此对象的构造器(函数)的原型对象(prototype)
<!--
对象都有这属性(找对象的父类对象):__proto__;
只有函数有的属性(找函数的原型,是个对象):prototype;
对象(或函数)的构造器(顶级构造器时Function()):constructor;
-->
<script>
function Aaa(){}
//undefined
var aaa = new Aaa();
//undefined
aaa.__proto__;
//{constructor: ƒ}
Aaa.prototype;
//{constructor: ƒ}
aaa.__proto__ === Aaa.prototype;
//true
aaa.constructor;
//ƒ Aaa(){}
Aaa.constructor;
//ƒ Function() { [native code] }
aaa.constructor.constructor
//ƒ Function() { [native code] } </script>
原型理解:
1. 函数Foo的__proto的值等于Foo.prototype,对吗?
错,函数Foo.__proto__===Function.prototype,函数Foo的实例的__proto__属性的值等于函数Foo.prototype 2.Object的prototype可以修改吗?能与不能原因是什么?
//可以,函数(对象)的原型可以任意修改或继承
不可以,因为Object.prototype是只读,所以不能赋值;但可以修改或添加 3. 顶级constructor是谁?
Function() 4.顶级原型对象是谁?
Object 5.对象的construtor成员是个属性还是个方法?
可以是属性,也可以是方法(一般不建议这么写,耗资源,在每次new是都要执行很多代码) 6.Function有没有__proto__,为什么?值等于Object.prototype吗?
1.有(是对象都有),与prototype相等,因为Function是顶级构造器,所以,函数的__proto__属性指向的构造器原型是与Function.prototype相等;
2.不等于,Function.prototype与Function.__proto__指向function.prototype 7.所有的构造器的__proto__都等于其对应的prototype
错,等于Function.prototype;因为对象的__proto__属性指向的是对象的构造器的prototype(函数的构造器是Function()) 8.创建类形式的继承的四部曲是什么?
1.创建父类
2.创建子类
3.确定继承关系:A.prototype = Object.create(B.prototype);
4.修改构造器(因为继承后的构造器指向是父类的原型指向的构造器,也就是说,子类的原型指向的构造器===父类的原型指向的构造器) 9.Function的constructor于prototype值可以修改吗?
不可以,Function是顶级构造器,Function.__proto__指向Function.prototype 10.Object.prototype === Object.__proto__吗?
不相等,Object.prototype是object.prototype;Object.__proto__是function.prototype 11. Function.prototype === Function.__proto__吗?
相等,(因为Function是顶级构造器,__proto__指向Function.prototype)Function.prototype===Function.__proto__ 12. function F(){}; var f1 = new F();
f1.__proto__ === Object.prototype吗?
不对,f1.__proto__ === F.prototype;f1.__proto__.__proto__ === Object.prototype;
4.5、this
原则:
1、this由运行时决定!
2、函数中 this 到底指向谁 , 由调用此函数时的对象决定 , 而不是由定义函数所在的对象决定。
在JavaScript中this表示:谁调用它,this就是谁。
如何改变this指向:
call:
apply:
<script>
/*
var data = {};
Array.prototype.push.call(data,100,200);
Array.prototype.push.apply(data,[1,2,3,8,10]);
console.log(data);
*/
</script>
4.6、new的理解
简单的可以理解为:new改变了this指向的对象;
五、封装
六、继承
七、多态
八、项目实战minijQuery
<script type="text/javascript">
/*
// 提示:
// 暴露外部使用的一个接口
var jQuery = window.jQuery = window.$ = function(selector){
return new jQuery.fn.init(selector);
} // 处理原型对象
jQuery.fn = jQuery.prototype = {}
jQuery.fn.init.prototype = jQuery.fn; // 实现继承,并且只处理只有一个参数,也就是插件的扩展
jQuery.extend = jQuery.fn.extend = function(){} // 添加静态方法
jQuery.extend({}); // 添加实例方法
jQuery.fn.extend({}); // 1.获取节点对象
var jq1 = jQuery(".pp");
或
var jq1 = jQuery.fn.init(".pp");
*/ // 提供全局访问接口($()、jQuery())
(function () {
/// 暂时把window的全局变量存起来,用做处理变量冲突
var _$ = window.$;
var _jQuery = window.jQuery; //暴露外部使用的一个接口(获取节点对象)
var jQuery = window.jQuery = window.$ = function(selector){ return new jQuery.fn.init(selector);// init.prototype;
}; //处理原型对象
jQuery.fn = jQuery.prototype = {
init:function(selector){
var elements = document.querySelectorAll(selector);
Array.prototype.push.apply(this,elements);
return this;
},
version:"1.0.0",
length:0,
size:function(){
return this.length;
} };
// jQuery.fn.init.prototype === init.prototype;
// jQuery.prototype;
jQuery.fn.init.prototype = jQuery.fn;
//实现继承,并且只处理只有一个参数,也就是插件的扩展
jQuery.extend = jQuery.fn.extend = function(){
var o = arguments[0];
for(var p in o){
this[p] = o[p];
}
};
/// 测试:(继承方法)
// var obj = {name:"张三三"}
// var jq = $(".pp");
// jq.extend(obj); //添加静态方法
jQuery.extend({
trim:function(text){
return (text||"").replace(/^\s+|\s+$/g,"");// 替换text字符串的开头和结尾匹配任何空白字符为空(即,替换开头和结尾的空格字符为空)
},
noConflict:function(){
window.$ = _$;
window.jQuery = _jQuery;
return jQuery;
}
}); /// 测试:(命名冲突)
// var jq = jQuery.noConflict();//返回一个jQuery函数,解决与全局的jQuery属性冲突
// var obj = jq(".pp"); //添加实例方法
jQuery.fn.extend({
get:function(num){
return this[num];
},
each:function(fn){
for(var i = 0 ;i< this.length; i++){
fn(i,this[i]);
}
return this;
},
css:function(){
var l = arguments.length;
if(l == 1){
return this[0].style[arguments[0]];
} else {
var name = arguments[0];
var value = arguments[1];
this.each(function(index,ele) {
ele.style[name] = value; });
}
return this;
} }); })();
</script>
javascript面向对象编程(OOP)——汇总的更多相关文章
- JS--我发现,原来你是这样的JS:面向对象编程OOP[3]--(JS继承)
一.面向对象编程(继承) 这篇博客是面向对象编程的第三篇,JS继承.继承顾名思义,就是获取父辈的各种"财产"(属性和方法). 怎么实现继承? 我们的JavaScript比较特别了, ...
- 【转】Javascript 面向对象编程(一):封装
原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html Javascript ...
- Javascript 面向对象编程(一):封装 by 阮一峰
<Javascript高级程序设计(第二版)>(Professional JavaScript for Web Developers, 2nd Edition) 它们都是非常优秀的Java ...
- 转:javascript面向对象编程
作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学 ...
- JavaScript面向对象编程(二)构造函数和类
new关键字和构造函数 在文章JavaScript面向对象编程(一)原型与继承中讨论啦JavaScript中原型的概念,并且提到了new关键字和构造函数.利用new关键字构造对象的实例代码如下: // ...
- (一)Javascript 面向对象编程:封装
Javascript 面向对象编程:封装 作者:阮一峰 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP ...
- Javascript 面向对象编程(一):封装 作者:yuan一峰
学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学者不容易掌握. 下面就是我的学习笔记,希望对大 ...
- [JAVA] 面向对象编程OOP Note
面向对象编程OOP Note OOP五个基本特性1. 万物皆对象.2. 程序是对象的集合,它们通过发送消息来告知彼此所要做的.3. 每个对象都有自己的由其他对象所构成的存储.4. 每个对象都拥有其类型 ...
- JavaScript面向对象编程学习笔记
1 Javascript 面向对象编程 所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量.对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例 ...
- 快速学习JavaScript面向对象编程
到处都是属性.方法,代码极其难懂,天哪,我的程序员,你究竟在做什么?仔细看看这篇指南,让我们一起写出优雅的面向对象的JavaScript代码吧! 作为一个开发者,能否写出优雅的代码对于你的职业生涯至关 ...
随机推荐
- MIRO做发票校验时实现替代功能的多种方式
http://blog.sina.com.cn/s/blog_3f2c03e30100ngje.html MIRO做发票校验时,如果需要对产生的会计凭证做某些字段的替代,可有多种方法. 1.GGB1替 ...
- Linux入门(15)——Ubuntu16.04安装codeblocks搭建C/C++的IDE环境
安装codeblocks: sudo add-apt-repository ppa:damien-moore/codeblocks-stable sudo apt-get update sudo ap ...
- LINUX 笔记-netstat命令
netstat命令用于显示与IP.TCP.UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况.netstat是在内核中访问网络及相关信息的程序,它能提供TCP连接,TCP和UDP ...
- Git相关操作一
1.将目录变为Git项目: 输入git init将当期目录变为Git项目 git init git项目可以被认为分为三个区域,Working Directory,Staging Area,Reposi ...
- Web前端性能优化——如何有效提升静态文件的加载速度
WeTest 导读 此文总结了笔者在Web静态资源方面的一些优化经验. 一.如何优化 用户在访问网页时, 最直观的感受就是页面内容出来的速度,我们要做的优化工作, 也主要是为了这个目标.那么为了提高页 ...
- HDU 5242 Game(三个贪心)
Game Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- Fibonacci Check-up
Fibonacci Check-up Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- IdentityServer4 禁用 Consent screen page(权限确认页面)
IdentityServer4 在登录完成的适合,会再跳转一次页面(权限确认),如下: 我之前以为 IdentityServer4 就是这样使用的,但实际业务场景并不需要进行权限确认,而是登陆成功后直 ...
- window10下的eclipse用java连接hadoop执行mapreduce任务
一.准备工作 1.eclipse连接hadoop的插件,需要版本匹配,这有几个常用的 2 版本的插件 hadoop2x-eclipse-plugin-master 密码:feg1 2.hadoop-c ...
- JavaUtil_04_验证码生成器
一.原理 验证码其实就是随机串.原理上可分为两种: 1.简单的验证码 直接通过字母和数字的ASCII码生成.本文采用的验证码就是这种. 2.复杂的验证码 通过一个随机串,一个指定串(如accesske ...