面向对象
一、初识面向对象
JS也是面向对象的。基本上所有的高级语言都是面向对象编程。面向对象是一种思想。
常见几种思想:
面向过程:C语言 没有类 没有对象
面向对象:JAVA,C++,JS(恶心)
面向切面:Spring IOC AOP
1.面向对象特征
特征分别为:抽象、封装、继承、多态
1)抽象
抽象:把一个具体问题抽象化。
2)封装
封装:把属性和方法封装到类中,在JS中重点说对象。封装实现就是是对象内部的变化对外界是不可见的。
var obj = {
name:"wangcai",
age:15,
say:function(){
console.log("say...");
}
}
3)继承
一个类可类可以继承另一个类,在JS,类是通过函数表达式。
<script>
class NBAPlayer{
constructor(name,age)
{
this.name = name;
this.age = age;
}
score = 50;
run(){
console.log("run...");
}
static it = "123";
}
var nba = new NBAPlayer("乔丹",35);
console.log(nba.name); //乔丹
console.log(nba.age); //35
console.log(nba.score); //50
console.log(nba.run()); //run... undefined
console.log(NBAPlayer.it); //123
//静态对象只能通过类名调用,不能使用对象调用
</script>
4)多态
多态其实就是把做的内容和谁去做分开。
var makeSound=function (animal) {
animal.sound();
}
var Duck=function () {
}
var Dog=function () {
}
Duck.prototype.sound=function () {
console.log("嘎嘎嘎")
}
Dog.prototype.sound=function () {
console.log("旺旺旺")
}
makeSound(new Duck());
makeSound(new Dog());
二、JS默认提供了很多类
1.Number 类
<script>
var n = new Number("100");
console.log(n); // Number {100}
console.log(typeof n); // object
console.log(n instanceof Number); // true
</script>
instanceof 是一个运算符 判断一个对象是否属性某个类
2. String 类
<script>
var str = new String("hello oop");
console.log(str) // {"hello oop"}
console.log(typeof str) // object
console.log(str instanceof String); // true
console.log(str instanceof Number); // false
// 对象 也叫 实例
// 类 也叫 构造器(JS特有)
</script>
3.Boolean类
Boolean只有两个数值,true或者false。
<script>
var f = new Boolean(false);
console.log(f) // {false}
console.log(typeof f) // object
console.log(f instanceof Boolean) // true
</script>
4.Object 构造器
<script>
// 按理说,你要想写一个对象,都需要通过new一个构造器 得到一个对象
var obj = new Object(); // new一个构造器得到一个对象
obj.name = "wc";
obj.age = 110;
console.log(obj); // {name: "wc", age: 110}
// 下面的写法是上面的写法的语法糖(是上面写法的简写)
var obj2 = { // 字面量形式声明一个对象
name:"xiaoqiang",
age:100
}
</script>
5.Date日期
<script>
// Date 日期
var d = new Date();
console.log(d);
console.log(d.getFullYear())
</script>
6.Math
<script>
// Math 数学计算相关 不需要new 单体内置类
// 常驻内存不需要new
var r = Math.random();
console.log(r);
</script>
7.Array类
<script>
// Array是一个内置类 new
var arr = new Array("a","b","c");
console.log(arr); // ["a", "b", "c"]
// 是上面的形式的语法糖
var arr2 = ["d","e","f"]; // 字面量创建数组(对象)
console.log(arr2); // ["d", "e", "f"]
</script>
除了上面列举的,还有很多其他类型…在这里不作详细的描述
三、JS中一切数据都是对象
一般对象都是以通过"."对自己内部属性进行访问,下面证明一切数据都是对象这一观点。
1.证明一:html元素是一个对象
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
// 证明一:html元素是一个对象
let lis = document.getElementsByTagName("li"); yigeyuansudezh //得到一个元素
console.log(lis); // HTMLCollection [li, li, li]
console.log(lis[0])
console.dir(lis[0])
console.dir(lis[0] instanceof HTMLLIElement); // true
let a = document.getElementsByTagName("a")[0];
console.dir(a); // HTMLAnchorElement
console.log(a instanceof HTMLAnchorElement)
</script>l
2. 证明二:数组也是对象
<script>
// 证明二:数组也是对象 对象里面有一堆的属性和方法
var arr = ["a","b","c"]; // 也是Array这个类
console.log(arr); // ["a", "b", "c"]
console.dir(arr);
console.dir(typeof arr); // object
console.log(arr.length);
arr.push("d");
console.log(arr);
console.log(arr instanceof Array); // true
</script>
3.证明三:函数也是对象
<script>
//函数也是对象
function f(a,b) {
console.log("f...")
}
console.dir(f)
console.dir(f.name)
console.dir(f.length)
f.call()
f.apply()
f.bind()
console.log(f instanceof Function); // true
console.log(typeof f); // function
</script>
4.证明四:基本数据类型也是对象
<script>
// 证明4:基本数据类型也是对象(基本数据类型在某些情况下也是对象)
var a = 110; // 现在要证明a也是对象
console.dir(a); // 110
console.log(typeof a) // number
console.log(a instanceof Number) // false
// 如果a不是对象 是不可能打点调用toFiexed
console.log(a.toFixed(3)); // 110.000
// 上面的a叫包装对象
// 上面调用toFixed时,它会把a瞬间包装成一个对象
var str = "hello";
console.log(str.length); // 5 str也是瞬间包装成对象了
console.log(str.toUpperCase()); // HELLO
</script>
5.证明五:console也是对象 window也是对象
<script>
// 证明5:console也是对象 window也是对象
console.log("wc")
console.dir(console)
console.log(console instanceof Object) // true
console.dir(window)
console.log(window instanceof Window) // true
</script>
四、对象是属性的无序集合
操作集合:增删改查
如何访问对象里面的属性
1)打点调用(使用较多)
2)通过[]来调用
<script>
var obj = {
name:"wangcai", // name叫属性名 “wangbai"叫属性值
123:456, // 123是属性名(键),456是属性值(值)
"1+1":2, // "1+1"是属性名 2是属性值
"a":"hello",
"b":null,
"c":function () {
console.log("c..")
},
"d":["1","2","3"],
"e":{ x:"xxx" }
}
console.log(obj.name)
console.log(obj[123]); // 456
console.log(obj.a); // hello
console.log(obj["1+1"]); // 2
// 如果我们的键是一个变量 我们需要通过变量去访问 必须使用[]
var k = "name";
console.log(obj[k]); // wangcai
//如果我们在全局定义的变量名字与 对象中定义的属性名字 相同,则需要通过[]进行访问
</script>
<script>
// 访问一个对象中不存在的属性 结果是undefined
var obj = {};
console.log(obj.name); //undefined
// 操作对象中的属性之遍历对象 for in
var obj = {
name:"wangcai",
age:100,
say:function () {
console.log("say...")
}
}
for (var key in obj) { // 通常遍历一个对象使用for in
// key是一个变量
//这里的key指的是属性名,而不是属性值
console.log(obj[key]);
}
console.log(obj.length) // undefined
// 得不到一个对象中有多少个属性
//数组可以得到长度,但是对象无法知道有多少属性
let arr = ["a","b","c"];
console.dir(arr)
for (const key in arr) { // 使用for in 并不能遍历出一个对象中所有的属性 如数组中的length和__proto__
// console.log(key);
console.log(arr[key])
}
</script>
console.dir(obj);打印出该对象的所有属性和属性值.
<script>
// 给添加添加新的属性
var obj = {
name:"wangcai"
}
console.log(obj.name); // 打印出obj中的name属性 访问
obj.name = "xiaoqiang"; // 修改属性
console.log(obj.name); // 同名属性后面的会把前面的覆盖掉
obj.age = 1100; // 新增属性
obj["address"] = "北京"; // 新增属性
console.log(obj)
</script>
如果对象中有对应的属性名,直接修改相应的属性值,如果没有,则在对象中创建新的属性名,赋值新的属性值。
<script>
var obj = {
name:"wangcai",
age:100
}
console.log(obj)
delete obj.age;
console.log(obj)
var a = 110; // var的变量放到GO中,是不能删除的
console.log(window.a)
delete window.a;
console.log(window.a)
b = 666; // 没有加var的变量 默认是可以删除的
console.log(window.b) // 666
delete window.b;
console.log(window.b) // undefined
let c = 111;
delete c; // delete用来删除一个对象上的属性
console.log(c)
</script>
delete:操作符用于删除对象的某个属性;如果没有指向这个属性的引用,那它最终会被释放。
delete object.property :object对象的名称,或计算结果为对象的表达式。
delete object['property']:property 要删除的属性。
五、读取对象中的属性有4大特征
1)configurable:表示是否可以被删除,true表示可以删除,默认true
2)writable:表示是否可以修改,true表示可以被修改,默认true
3)enumerate:表示是否可以枚举/输出 ,输出表示可以输出,默认true
4)value:当前的属性值,默认是undefined
<script>
var obj = {
name:"wangguowei"
}
//Object.getOwnPropertyDescriptor 获取属性的特征
//writable: true, enumerable: true, configurable: true
console.log(Object.getOwnPropertyDescriptor(obj,"name"));
var a = 48;
b = 68;
//writable: true, enumerable: true, configurable: false 不可被修改
console.log(Object.getOwnPropertyDescriptor(window,"a"));
//writable: true, enumerable: true, configurable: true 可以被修改
console.log(Object.getOwnPropertyDescriptor(window,"b"));
var arr = ["a"];
//writable: true, enumerable: false, configurable: false 不可枚举/输出 不可被修改
console.log(Object.getOwnPropertyDescriptor(arr,"length"));
</script>
Object.getOwnPropertyDescriptor 获取属性的特征
六、属性的分类
对象上的属性是分成两类的: 私有属性、公有属性
<script>
var obj = {
name:"wangcai",
age:100
}
console.log(obj.hasOwnProperty("name")); // true 查看name是否是obj的私有属性
console.log(obj.hasOwnProperty("age")); // true
// 公有属性 原型属性
console.log(obj)
console.dir(obj.hasOwnProperty("toString")); // false 查看toString是否是obj的私有属性
console.log(obj.hasOwnProperty("__proto__")); // false 查看__proto__是否是obj的私有属性
console.log(obj.__proto__.hasOwnProperty("toString")); // true // 查看toString是否是obj.__proto__这个对象的私有属性
// 对于obj来说:name和age是它的私有属性 toString是它的公有属性
// 对于obj.__proto__来说:toString是它的私有属性
// 也就是说一个属性是私有属性还是公有属性,还需要看它针对是谁。
var arr = ["a","b"];
console.dir(arr);
console.log(arr.hasOwnProperty("length")); // true
console.log(arr.hasOwnProperty("push")); // false
console.log(arr.hasOwnProperty("__proto__")); // false
console.log(arr.__proto__.hasOwnProperty("push")); // true
// delete只能删除私有属性 不能删除公有属性
delete arr[0];
console.log(arr);
delete arr.push;
console.dir(arr)
// 如果一个私有属性和公有属性重名了,私有属性会把公有属性覆盖掉
var a1 = ["a"];
console.dir(a1)
a1.push("b")
console.dir(a1)
a1.push = function () {
console.log("自己的push");
}
a1.push("c");
</script>
<script>
// 判断一个属性是否属于某个对象
// hasOwnProperty
// in 是一个运算符 是公有属性 得到的也是true
var obj = {
name:"wangcai"
}
console.log(obj.hasOwnProperty("name"));// 判断name是否是obj的私有属性 true
console.log("name" in obj); // 判断name是否是obj的属性 true
console.dir(obj)
console.dir("toString" in obj) // 判断toString是否是obj的属性 true
console.dir("xxx" in obj) // 判断xxx是否是obj的属性 false
</script>
可以查看一个属性是否是私有属性叫 hasOwnProperty()
七、对象是由函数创造的
在JS中,一个函数是有多个角色:
1)普通的函数
2)类 构造器
3)对象
1.普通的函数
<script>
function f(){
console.log("f...");
}
var g = new Function("a","b","return a + b");
console.log(g(1,2));
</script>
Function():一个普通函数是由Function()创建的。
构造器
<script>
function f(){
}
let f1 = new f();
console.log(f1)
console.log(typeof f1)
console.log(f1 instanceof f)
</script>
对象
<script>
var person={
lassname:'human'
}//将这个对象当做原型
var p1 = Object.create(person) //生成实例对象
console.log(p1.classname) //human,相当于p1.__proto__.classname
</script>
八、函数的四种
函数大约有四个角色:一个普通函数;在对象中可以当作一个方法;当作类,或者说是构造器;当成一个对象
1.角色一:一个普通的函数
<script>
// 角色一:一个普通的函数
function f() {
console.log("f...")
}
// f(); 作用1:让函数体执行 作用2:得到返回值
f();
</script>
2. 角色2:在对象中可以当成一个方法
<script>
// 角色2:在对象中可以当成一个方法
let obj = {
say:function () { // 方法
console.log("say...")
},
sleep:function () { // 方法
console.log("sleep...")
}
}
obj.say()
obj.sleep()
</script>
3.角色3:类 构造器
<script>
// 角色3:类 构造器
function NBAPlayer() {
}
var nbaPlayer1 = new NBAPlayer();
var nbaPlayer2 = new NBAPlayer();
var nbaPlayer3 = new NBAPlayer();
console.log(nbaPlayer1);
console.log(nbaPlayer2);
console.log(nbaPlayer3);
</script>
4.角色4:可以当作一个对象
<script>
// 角色4:也可以当作是一个对象
function F() {
}
F.name1 = "wangcai";
F.age = 100
console.log(F.name1)
console.log(F.age)
</script>
九、让函数充当一个类
<script>
function NBAPlayer() {
}
var p1 = new NBAPlayer();
var p2 = new NBAPlayer();
var p3 = new NBAPlayer();
p1.name = "科比"
p2.name = "乔丹"
console.log(p1.name);
console.log(p2.name);
</script>
<script>
function NBAPlayer(name) { // 类
// console.log(this)
this.name = name;
}
// new 运算符 肯定干几件事
// 1)在构造器内部创建一个空对象
// 2)让构造器中的this指向这个对象
// 3)返回这个对象
var p1 = new NBAPlayer("乔丹");
var p2 = new NBAPlayer("科比");
console.log(p1.name);
console.log(p2.name);
</script>
<script>
function NBAPlayer(name,age) { // 类
this.name = name;
this.age = age;
}
var p1 = new NBAPlayer("乔丹",10); //带入参数
var p2 = new NBAPlayer("科比",20);
console.log(p1.name);
console.log(p1.age);
console.log(p2.name);
console.log(p2.age);
</script>
<script>
function Go(name,age) {
this.name = name;
this.age = age;
}
var go = new Go("wc",100);
console.log(window.go); // {name: "wc", age: 100}
console.log(window.name); // window上面本身就有一个name,输出值为window的值
console.log(window.age);
</script>
<script>
function F() {
var a = 110;
this.b = 1;
this.c = 2;
this.d = 3;
}
var f = new F();
console.log(f); // {b: 1, c: 2, d: 3}
//普通函数调用,函数里面的this指的是window里面的数据
//变量a是局部变量,最后输出结果为 {b: 1, c: 2, d: 3}
</script>
<script>
function F() {
var a = 110;
this.a = 1;
}
var f = new F();
console.log(f); // { a:1 }
</script>
<script>
function Fn(x) {
let y = 20;
this.total = x+y;
this.say = function () {
console.log(x+"+"+y+"="+this.total)
}
}
let f1 = Fn(10);
console.log(f1); // undefined
//f1没有返回值,默认为undefined
console.log(say()); //10 + 20 = 30 undefined内部函数无返回值
console.log(total); //30
console.log(y); //y is not defined 因为y是局部变量,在函数外部没有办法访问
let f2 = new Fn(10); //new 开辟了一个新空间
f2.say(); // 10 + 20 = 30
console.log(f2.total); // 30
</script>
因为f2新开辟了一个空间,函数内部只存在say(),total
<script>
function Fn(x) {
let y = 20;
this.total = x+y;
this.say = function () {
console.log(x+"+"+y+"="+this.total)
}
}
let f2 = new Fn(10);
console.log(f2.x); // undefined
console.log(f2.y); // undefined
</script>
因为新开辟了新空间,内部为空,无法访问数据x,y
<script>
function Fn(x) {
let y = 20;
this.total = x+y;
this.say = function () {
console.log(x+"+"+y+"="+this.total)
}
}
let f1 = Fn(10);
// cannot read property 'total' of undefined
console.log(f1.total);
</script>
函数的返回值为空,无法指向变量名。会产生报错信息
<script>
function Fn(x) {
let y = 20;
this.total = x+y;
this.say = function () {
console.log(x+"+"+y+"="+this.total)
}
}
let f1 = new Fn(10);
let f2 = new Fn(10);
console.log(f1 == f2); //false
</script>
f1与f2均开辟了新空间,且堆地址不同,所以输出结果为false
<script>
function Fn(x) {
let y = 20;
this.total = x+y;
this.say = function () {
console.log(x+"+"+y+"="+this.total)
}
}
let f1 = Fn(10);
console.log(window.total); //30
</script>
因为普通函数调用,函数里面的this指的是window,最终从GO里面找到数据,30。