【JavaScript OPP基础】---新手必备
今天和大家分享一下近期整理的有关JavaScriptOOP的基础知识~~~我们一起来学习一下……
JavaScriptOOP基础
一、面向对象编程OOP
1、语言的分类:
面向机器:汇编语言
面向过程:C语言
面向对象:C++,Java,PHP等
2、面向过程和面向对象
①面向过程:专注于如何去解决一个问题的过程。
编程特点:用一个个函数去实现过程操作,没有类和对象的概念;
②面向对象:专注于有哪一个对象实体去解决这个问题。
编程特点是:出现了一个个的类,由类去生成对象。
二、面向对象的三大特征
继承,封装,多态
三、类&对象的关系
1、类:一群有相同特征(属性)和行为(方法)的集合
eg: 人类
属性:"身高,体重,年龄"
方法:"吃饭,睡觉,敲代码"
2、对象:从类中,new出的具有确定属性值和方法的个体称为对象。
eg:张三:属性:身高:身高178,体重150 方法:说话---我叫张三
3、类和对象的关系:
类是抽象的,对象是具体的。
(!类是对象的抽象化,对象是类的具体化!)
通俗的来讲:
类是一个抽象概念,表示具有相同属性和行为的集合。
但是类仅仅表示表明这类群体具有相同的属性,但是没有具体的属性值。
而对象是对类的属性进行具体赋值后,而得到的一个具体的个体;
eg:人类有身高体重年龄,但不能具体说人类的身高体重具体是多少;而张三是人类的一个具体个体,身高体重等有具体值,则张三就是人类的一个对象。
4、使用类和对象的步骤:
①创建一个类(构造函数):
类名,必须要每个单词首字母都大写
function 类名(属性一){
this.属性 = 属性一;
this.方法= function(){}
//this指向谁?即将调用当前构造函数的对象。
}
②通过类,实例化出一个新的对象;
var obj = new 类名(属性一Value);
//原构造函数中this,指向新创建的obj对象
obj.方法();调用方法
obj.属性();调用属性
实例化对象的时候,会执行构造函数
5、两个重要属性:
constructor:返回当前对象的构造函数。(只有对象才有,返回的是构造函数-类)
>>>zhangsan.constructor == Person
>>>对象的constructor,位于_proto_原型对象上(后续讲解)
instanceof:判断对象是否是某个类的实例
>>>zhangsan instanceof Person true
>>>zhangsan instanceof Object true
>>>Person instanceof Object true(函数也是对象)
6、广义对象与狭义对象:
广义对象:除了用字面量声明的基本数据类型之外,外物皆对象,换句话说,能够添加属性和方法的变量,就是对象;
var s = "1" ; 不是对象
var s = new String("1") ; 就是对象
狭义对象:只有属性,方法,除此之外没有任何东西。
var obj = {}; var obj = new Object();
成员属性与成员方法
一、成员属性与成员方法
1、在构造函数中通过this.属性声明;或者实例化出对象后,通过"对象.属性"追加的。
都属于成员属性,或成员方法;也叫实例属性与实例方法。
成员属性/方法,是属于实例化出的这个对象。
通过"对象.属性"调用
二、静态属性与静态方法
2、通过"类名.属性名","类名.方法名"声明的变量,称为静态属性,静态方法;也叫类属性、类方法。
类属性/类方法,是属于类的(属于构造函数的)
通过"类名.属性名"调用
3、成员属性,是属于实例化出的对象的,会出现在新对象的属性上
静态属性,是属于类(构造函数)自己的,不会出现在新对象的属性上
4、JS对象属性的删除:
①对象无需手动删除,JS
②删除对象的属性:delete 对象名.属性名
5、对象是引用数据类型
也就是说,当new出一个对象时,这个obj变量存储的实际上是对象的地址,在对象赋值时,赋的也是地址。
function Person(){}
var xiaoxi = new Person();//xiaoxi对象实际上存的是地址
var ashu = xiaoxi;//赋值时,实际是将xiaoxi存的地址给了ashu
ashu.name = "阿树";//阿树通过地址,修改了地址
console.log(xiaoxi.name);//xiaoxi再通过地址打开对象,实际已经变了
引用数据类型,赋值时传递的是引用(地址)---快捷方式
基本数据类型,赋值时传递的是数据(值)
三、私有属性和私有方法
6、在构造函数中,通过var声明的属性,成为私有属性:
function Person(){var num=1;}
私有属性的作用域,仅在当前函数有效。对外不公开,即通过对象/类都无法调用到。
原型与原型链
【__proto__与prototype】
1、prototype(函数的原型):函数才有prototype。
prototype是一个对象,指向了当前构造函数的引用地址。
2、__proto__(对象的原型对象):所有对象都有__proto__属性。当用构造函数实例化(new)一个对象时,
会将新对象的__proto__属性,指向构造函数的prototype。
eg:zhangsan.__proto__==Person.prototype √
所有对象最终都会指向Object()的prototype。
【原型链】
1、通过构造函数,new出的对象,新对象的__proto__指向构造函数的prototype。
2、所有函数的__proto__指向Function()的prototype。
3、非构造函数new出的对象({} new Object() 对象的prototype)的__proto__指向Object的prototype。
4、Object的__proto__指向Null。
原型属性与原型方法
【类中属性与方法的声明方式】
1、成员属性、成员方法:
this.name = ""; this.func = function(){}
>>>属于实例化出的对象的。通过"对象.属性"调用。
2、静态属性、静态方法:
Person.name = ""; Person.func = function(){}
>>>属于类(构造函数)的。通过"类名.属性"调用。
3、私有属性、私有方法:
在构造函数中,使用var num = 1;声明
>>>只在构造函数内部能用,在外部无法通过任何方式访问。
4、原型属性、原型方法:
Person.prototype.name = "";
Person.prototype.func = function(){};
>>>写在了构造函数的prototype上,当使用构造函数实例化对象时,该属性方法会进入新对象的__proto__上。
也就是说,1/4使用对象可访问,2使用类名可访问,3只能在函数的{}内使用。
5、习惯上,我们会将属性写为成员属性,而方法写为原型方法;
eg:
function Person(){
this.name = "zhangsan";
}
Person.prototype.say = function(){}
原因:
①实例化出对象后,所有属性直接在对象上,所有方法都在__proto__上,非常直观清晰。
②方法写到prototype上,要更加节省内存。
③使用for in 循环时,会将对象以及对象原型链上的所有属性和方法打印出来,而方法往往是不需要展示的。
将方法写到__proto__上,可以使用hasOwnProperty将原型上的方法更好的过滤。
④官方都这么写。
6、当访问对象的属性/方法时,会优先使用对象自有的属性和方法。
如果没有找到,便使用__proto__属性在原型上查找,如果找到即可使用。
但是,当对象自身,以及__proto__上有同名方法,执行对象自身的。
7、可以通过prototype扩展内置函数的相关方法。
代码演示:
function Person(){
this.name1 = "name1"; //成员属性
this.age = "age1";
this.sex = "男";
this.say = function(){
alert("我是大帅哥!");
}
var name2 = "name2";//私有属性
}
Person.name3 = "name3";//静态属性
Person.prototype.name4 = "name4";//原型属性 Person.prototype.say = function(){
alert("我叫"+this.name1);
} var zhangsan = new Person();
// zhangsan.say = function(){
// alert("我是大帅哥!");
// }
zhangsan.say();
zhangsan.toString(); console.log(zhangsan); // console.log(zhangsan.name1);
// console.log(zhangsan.name2);
// console.log(zhangsan.name3);
// console.log(zhangsan.name4);
//
// console.log(s);
可以通过prototype扩展内置函数的相关方法
代码演示:
Number.prototype.add = function(a){
return this+a
} var num = new Number(10);
console.log(num);
alert(num.add(3)); /*
* 为Array类添加一个find(val)方法,当一个Array对象调用该方法的时候,如果能找到val值,则返回其下标,否则返回-1。
*/
Array.prototype.find = function(val){
for (var i = 0; i<this.length;i++) {
if(this[i]==val){
return i;
}
}
return -1;
}
var arr = new Array(1,2,3,4,5);
alert(arr.find(1));
位String类添加一个字符串反转方法
String.prototype.fanzhuan = function(){
var arr = this.split("");
arr.reverse();
return arr.join("")
} console.log(str.fanzhuan()); for-in循环 【for-in循环】
for-in循环,主要用于遍历对象。
for()中格式:for(keys in obj){} keys表示obj对象的每一个键值对的键,所以{}中,使用obj[keys]读取每个值;
但是,使用for-in循环,不但能遍历对象本身的属性和方法。还能够遍历对象原型链上的所有属性和方法。 可以使用hasOwnProperty判断一个属性,是否是对象自身的属性。
obj.hasOwnProperty(keys)==true 表示:keys是对象自身的一个属性 代码演示:
// foreach
function Person(){
this.name1 = "name11111"; //成员属性
this.age = "age11111";
this.func2 = function(){
console.log("thisFun")
}
}
Person.name3 = "name333333";
Person.prototype.name4 = "name44444";
Person.prototype.func1 = function(){
console.log("prototypeFun")
}
var zhangsan = new Person();
for(keys in zhangsan){
if(zhangsan.hasOwnProperty(keys)){ //过滤掉原型上的属性,只打印对象自身属性
console.log(zhangsan[keys])
}
}
JS OOP 中的继承【JS模式实现继承的三种方式】
【文档注释】第一行两个星号
/**
* ……
*/
调用函数时,可以看到注释内容
【JS OOP 中的继承】
1、使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方法。
>>>继承的两方,发生在两个类之间。
2、JS模式实现继承的三种方式:
1)扩展Object实现继承
①定义父类:function Parent(){}
②定义子类:function Son(){}
③通过原型给Object对象添加一个扩展方法。
Object.prototype.customExtend = function(parObj){
for(var i in parObj){
//通过for-in循环,把父类的所有属性方法,赋值给自己。
this[i] = ParObj[i];
}
}
④子类对象调用扩展方法
son.customExtend(Parent);
2)使用call和apply
首先,了解一下call和apply:通过函数名调用方法,强行将函数中的this指向某个对象;
call写法:func.call(func的this指向的obj,参数1,参数2...);
apply写法:func.apply(func的this指向的obj,[参数1,参数2...]);
call与apply的唯一区别:在于接收func函数的参数方式不同。call采用直接写多个参数的方式,而apply采用是一个数组封装所有参数。
①定义父类 funtion Parent(){}
②定义子类 function Son(){}
③在子类中通过call方法或者apply方法去调用父类。
function Son(){
Parent.call(this,....);
}
3)使用原型继承
①定义父类function Parent(){}
②定义子类function Son(){}
③把在子类对象的原型对象声明为父类的实例。
Son.prototype = new Parent();
闭包
【JS中的作用域】
1、全局变量:函数外声明的变量
局部变量:函数内声明的变量
在JS中,函数为唯一的局部作用域,而if、for等其他{}没有自己的作用域
所以,函数外不能访问局部变量。
其实,变量在函数执行完毕以后,占用的内存就被释放。
2、如何访问函数私有变量?
JS中,提供了一种"闭包"的概念:在函数内部,定义一个子函数,可以用子函数访问父函数的私有变量。执行完操作以后,将子函数通过return返回。
function func2(){
var num = 1;
function func3(){
var sum = num+10;
alert(sum);
}
return func3;
}
var f = func2();
f();
3、闭包的作用:
① 访问函数的私有变量;
② 让函数的变量始终存在于内存中,而不被释放。
代码演示:
function func1(){
var n = 1;
}
if(true){
var m = 3;
}
//alert(m); // 3
func1();
//alert(n);// 报错。函数外不能访问局部变量。其实,n变量在func1函数执行完毕以后,占用的内存就被释放。 /*闭包*/
function func2(){
var num = 1;
function func3(){
var sum = num+10;
alert(sum);
}
return func3;
}
var f = func2();
f(); // 循环转一次,创建一个lis[i].onclick函数。但是,当点击li执行函数的时候,i已经变为6,所以无论点击哪一个,i都是6
// 循环创建lis[i].onclick的时候, 循环一次,li[i]里面的i都被赋为不同值;创建了 li[1] li[2] li[3]...
// 但是,创建过程中,并没有执行onlick后面的函数,所以函数里面的i并没有赋值,还是字母i。
// 最终,我们点击li[1] li[2]...时,onclick函数里面的i才会赋值。(但此时,全局变量的i ,已经成为6 了)
var lis = document.getElementsByTagName("li");
for (var i=0;i<lis.length;i++) {
lis[i].onclick = function(){
//alert("您/点击了第"+i+"个li!");
//console.log(lis[i]);
//console.log(this);
}
} // 循环转一次,创建一个自执行函数。
// 而自执行函数拥有自己的作用域,所以用函数局部作用域j保存当前的全局变量i值。这样,创建第一个自执行函数,它的j=1;创建第二个,它的j=2...不同函数的j互不干扰。
// 这样,循环转完以后,相当于创建了6个自执行函数,每个函数中都有一个不同的j变量
var lis = document.getElementsByTagName("li");
for (var i=0;i<lis.length;i++) {
!function(){
var j = i;
lis[j].onclick = function(){
alert("您/点击了第"+j+"个li!");
//console.log(lis[i]);
//console.log(this);
}
}();
} var lis = document.getElementsByTagName("li");
for (var i=0;i<lis.length;i++) {
!function(j){
lis[j].onclick = function(){
alert("您/点击了第"+j+"个li!");
//console.log(lis[i]);
//console.log(this);
}
}(i);
}
【JavaScript OPP基础】---新手必备的更多相关文章
- [新手必备]Python 基础入门必学知识点笔记
Python 作为近几年越来越流行的语言,吸引了大量的学员开始学习,为了方便新手小白在学习过程中,更加快捷方便的查漏补缺.根据网上各种乱七八糟的资料以及实验楼的 Python 基础内容整理了一份极度适 ...
- Android基础新手教程——1.2.1 使用Eclipse + ADT + SDK开发Android APP
Android基础新手教程--1.2.1 使用Eclipse + ADT + SDK开发Android APP 标签(空格分隔): Android基础新手教程 1.前言 这里我们有两条路能够选,直接使 ...
- Android基础新手教程——1.2 开发环境搭建
Android基础新手教程--1.2 开发环境搭建 标签: Android基础新手教程 如今主流的Android开发环境有: ①Eclipse + ADT + SDK ②Android Studio ...
- JavaScript RegExp 基础详谈
前言: 正则对于一个码农来说是最基础的了,而且在博客园中,发表关于讲解正则表达式的技术文章,更是数不胜数,各有各的优点,但是就是这种很基础的东西,如果我们不去真正仔细研究.学习.掌握,而是抱着需要的时 ...
- JavaScript学习基础部分
JavaScript学习基础 一.简介 1.JavaScript 是因特网上最流行的脚本语言,并且可在所有主要的浏览器中运行,比方说 Internet Explorer. Mozilla.Firefo ...
- JavaScript入门基础
JavaScript基本语法 1.运算符 运算符就是完成操作的一系列符号,它有七类: 赋值运算符(=,+=,-=,*=,/=,%=,<<=,>>=,|=,&=).算术运 ...
- JavaScript 语言基础知识点总结(思维导图)
JavaScript 数组 JavaScript 函数基础 Javascript 运算符 JavaScript 流程控制 JavaScript 正则表达式 JavaScript 字符串函数 JavaS ...
- JavaScript语言基础知识点图示(转)
一位牛人归纳的JavaScript 语言基础知识点图示. 1.JavaScript 数据类型 2.JavaScript 变量 3.Javascript 运算符 4.JavaScript 数组 5.Ja ...
- JavaScript 语言基础知识点总结
网上找到的一份JavaScript 语言基础知识点总结,还不错,挺全面的. (来自:http://t.cn/zjbXMmi @刘巍峰 分享 )
随机推荐
- [SinGuLaRiTy] 数论基础
[SinGuLaRiTy-1004] Copyright (c) SinGuLaRiTy 2017 . All Rights Reserved. 整除: 设a,b为整数,且a不为0,如果存在一个整数q ...
- 开启 .NET Core 的新篇章
今天开始要开始研究.net core了 规划了一下要学习的点: 1.CentOS7 2.asp.net Core 3.Linux的常用命令与运维 4.nginx的常用配置 5.mysql的使用与日常维 ...
- Uva 11029 Leading and Trailing (求n^k前3位和后3位)
题意:给你 n 和 k ,让你求 n^k 的前三位和后三位 思路:后三位很简单,直接快速幂就好,重点在于如何求前三位,注意前导0 资料:求n^k的前m位 博客连接地址 代码: #include < ...
- Codeforces Round #384 (Div. 2).C
C. Vladik and fractions time limit per test 1 second memory limit per test 256 megabytes input stand ...
- "!function",自执行函数表达式
如题为自执行函数表达式.在这种情况下,解析器在解析function关键字的时候,会将相应的代码解析成function表达式,而不是function声明.下面2个括弧()都会立即执行 (function ...
- Centos7部署Zabbix
转载于http://www.cnblogs.com/xqzt/p/5124894.html,更正了部分错误,并增加了个别问题处理办法. 一.Zabbix简介 zabbix是一个基于WEB界面的提供分布 ...
- Python爬虫 URLError异常处理
1.URLError 首先解释下URLError可能产生的原因: 网络无连接,即本机无法上网 连接不到特定的服务器 服务器不存在 在代码中,我们需要用try-except语句来包围并捕获相应的异常.下 ...
- Tensorflow学习笔记---0--TensorBoard
运行mnist_with_summaries学习TensorBoard时,由于需要GPU支持,运行窗口报错:Couldn't open CUDA library cupti64_80.dll 解决办法 ...
- setTimeout 和 setInteval 的区别。
学习前端的可能都知道js有2个定时器setTimeOut和setinteval.用的时候可能不是很在意,但是2者还是有区别的 setTimeout方法是定时程序,也就是在什么时间以后干什么.干完就完了 ...
- [原创] IAR7.10安装注册教程
代码开发简单化的趋势势不可挡,TI 公司推出的 IAR7.10 以上版本,集成代码库,方便初学者进行学习移植.本教程详细列出IAR7.10安装以及注册步骤,不足之处望多多交流. 好了进入正题. 第一, ...