js面向对象大总结

一 类和对象概念

1)面向对象?

 面向对象是一种编程思想,里面有两个非常重要的概念:类,对象。

类:是抽象地,不具体的,类别就是有相同特征的一类事物。JS中有很多的类,我们也可以自己定义类。

对象:通过类创建出对象,是具体的。JS中也有很多的对象,我们也可以自己去创建对象。

2) 对象?

对象中有很多的静态特征,通常使用变量来描述,此时变量也叫属性。

对象中有很多的动态特征,通常使用函数来描述,引时函数也叫方法(属性)。

 对象是属性的无序集合(操作(CRUD)集合)。

3)类?

JS中提供很多类,如Number, String, Boolean, Object, Math, Date, ....

通过类创建出对象,使用new运算符来创建,如: let d = new Date();

 new一个类就可以创建出一个对象。

4)三条定律,两条链:

定律一:一切都是对象(数组,函数,对象,基本数据类型在特定场合下也是对象)

定律二:所有的对象都是通过类(函数在某些场合下面也是类)来创建的

定律三:对象是属性的无序集合(操作(CRUD)集合)

 两条链:作用域链,原型链。

5)对象是属性的无序集合(对象里面的增删改查):

----创建对象的两种方式:字面量,new

let wc = {

name:"wangcai",

age:100,

say:function(){

console.log("wangwang...")}}

-----访问对象中的属性:通过点运算符,通过【“”】语法访问对象中的属性

!请注意一种特殊的情况:如果属性名是一个变量:只有一种方式来获取对象中的属性:【】注意里面不用加引号

给一个对象增加属性:通过点运算符,通过【“”】语法访问对象中的属性。注意如果添加了同名的属性,同名属性将会被覆盖

设置对象的属性(精细化设置):configuration:是否删除;writable:是否可以修改属性值;enumerable:是否可以枚举;value:表示属性值,没有给定属性值,默认值是:undefined;注意,如果对象中没有这个属性,精细化设置属于添加了这个新的属性。

!删除对象中的属性

delect  对象名.属性名(删除对象中的某一属性);默认情况下是可以修改对象中的属性的,枚举:用for in来遍历属性

特殊例子删除属性: a和b都是全局变量,全局变量是作为window的属性

var a = 110;

b = 666;

delete a; // 删除window这个对象上的a属性

delete b; // 删除window这个对象上的b属性

console.log(a) // 110 a没有被删除

console.log(b) // ReferenceError: b is not defined b被删除了

注意:加var的全局变量是不能被删除的,没有var的全局变量是可以被删除的

注意: 如果使用了var,相当于给window这个对象的a属性,设置了configurable:false

!枚举对象中的属性

举个枚举对象中属性的例子:for 。。in

for(item in wc){

      console.log(item)

}

举个枚举对象中属性的例子Object.keys(对象名):遍历对象的属性,不能找值,只在自己内部找,而且不能遍历不可枚举的属性

console.log(Object.keys(wc)) //  ["name", "age", "say"]

value:可以直接修改或者获取。

普及一个小知识:数组可以理解成键值对:

let arr = ["a","b","c"]

{0:"a",1:"b",2:"c"}

for(var i=0; i<arr.length; i++){

 console.log(arr[i]) }

接下来讲一下如何精细化设置对象的属性:

1)Object.defineproperty(对象名,“属性名”,{配置表})

2)Object.defineproperty会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。

3)Object是一个类 类.xxx 说明xxx是类上的一个属性(静态属性)

4)defineproperty是Object这个类上的静态属性  define是定义的意思  Property

!!注意在设置时的属性名一定要加引号,不然会报错。它会给你当成变量,变量不能精细化设置特征。

!!注意修改属性的特征:一旦设置不能被删除,那么就不能再设置可以被删除了!!

来个标准例子:

let wc = {

name:"wangcai",

age:100,

say:function(){

console.log("wangwang...")}}

精细化设置

Object.defineProperty(wc,"score",{

configurable:false, // wc这个对象上的score这个属性不能被删除

value:100

});

delete wc.score

console.log(wc.score)

举例子定义一个常量,就是不能被修改,不能被删除,

let obj = {};

Object.defineProperty(obj,"PI",{

writable:false, // 不能修改

configurable:false, // 不能删除

value:3.14,

enumerable:true, // 可以枚举

})

console.log(obj.PI)

(6)判断某一属性是否属于某一对象

in 运算符:判断某一个属性是否属于某一个对象。

hasOwnProperty:方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。

in 和 hasOwnProperty的区别?

 in先在自己内部找,如果找不到,会去它的原型对象中找。

hasOwnProperty只会在在自己内部找。

运算符:

let wc = {

name:"wangcai",

age:100,

say:function(){

console.log("wangwang...")}}

 //console.log("name" in wc) // 键在外面的使用时需要加引号 true

//console.log(wc.hasOwnProperty("say")) // true这俩都可以获得身上的属性

in可以获得原型上的方法:

var arr = ["a","b","c"]

// arr是对象 push是方法 push在arr内部找不到,就去它的原型对象上找

arr.push("d")

console.log("push" in arr) // true

console.log(arr.hasOwnProperty("push")) // false

 

这一知识点的数组去重和统计数组中元素的个数:

数组去重:

var arr = [1,2,3,3,1,2,4,5,2,4,5,7,5,7,8];

// function fn(arr){

// var newArr = [];

// // 判断数组中的每一个元素是否处理过

// var o = {}; // {"1":true,"2":true,"3":true}

// for(var i=0; i<arr.length; i++){

// let t = arr[i]; // t表示老数组中的每一项元素

// if(o[t]){ }else{

// newArr.push(arr[i])

// o[t] = true;}}

// return newArr; }

// var newArr = fn(arr);

// console.log(newArr) //   [1, 2, 3, 4, 5, 7, 8]

统计数组中元素的个数:

var arr = [1,2,3,3,1,2,4,2,6,2];

function fn(arr){

var obj = {};// {"1":2, "2":3, "3":100} {"1":1,"2":1}

for(var i=0; i<arr.length; i++){

var t = arr[i]

// obj[t] = 1 obj[t] = obj[t]+1

if(obj.hasOwnProperty(t)){

obj[t] = obj[t] + 1

}else{

obj[t] = 1;}}

return obj;}

let res = fn(arr)

// res中应该包含每个元素出现多少次 res是一个对象

console.log(res)

二 函数(js中的VIP,我们的重头戏)

函数在JS中比较特殊:

1)前面我们所学的函数,仅仅是把函数当作是一个普通的函数

2)函数在JS中可以当作是一个类(构造器),通常会把函数名(类名)的首字母大写。

函数声明(此时这个函数仅仅是一个普通的函数)

function fn(a,b){

 产生一个局部的执行上下文(局部栈,函数栈..)

形参赋值,声明的提升,代码的执行

return a+b;

 }

// console.log(fn(1,2))

3)类的作用就是为了创建出一个对象

function CreateDog(name, age){

this.name = name;

this.age = age;}

let wc = new CreateDog("wangcai",100);

console.log(wc.name)

console.log(wc.age)

4)函数的两个角色

 把函数当作一个类(构造器):

 目的:创建对象

函数有现在有两个角色:

!普通函数-->局部执行上下文

// 把函数当作普通函数来调用

// function fn(a,b){

// return a+b

// }

// 调用 得到函数的返回值 会产生局部的执行上下文

// fn(1,2)

 !类(构造器,构造函数)--->new;把函数当作一个类 和 把函数当作普通函数的区别?

当作一个类,需要new,new相比我们之前直接去调用函数有什么区别?

 1)new在执行代码时会创建一个对象,2)然后把this指向这个对象,3)最后把对象的地址返回。

// 通常类名的首字母会大写

function CreateDog(name,age){

this.name = name;

this.age = age;}

let wc = new CreateDog("wangcai",1000);

console.log(wc.name)

console.log(wc.age)

注意:

1:把函数当作类

 !Fn的首字母大写,不是强制要求,但是是一个行业的默认规则

!它内部会给我们创建出一个对象并返回 不需要我们做

!在每一个类中都有一个this,this就指了创建出来的对象

!new最终肯定要得到一个对象

大的注意事项:return后面的语句不会执行

如果把一个函数当成一个类,那么你再返回一个普通的基本数据类型的数据,相当于没有返回

它内部会返回一个对象

2:如果在一个类中返回一个对象:如果把函数当作类,在类中返回一个对象,最终这个对象会把默认的对象覆盖掉

function Fn(){

this.name = "xxx";

return {

age:666}}

console.log(Fn()); // {age: 666}

let r = new Fn();

console.log(r); // {age: 666}

5)new出来的对象都是独立的:!!!!

// 代码执行到CreateDog时,做几件事:

// 形参的赋值

// 声明的提升

// 代码的执行

// 创建一个空对象

// 让this指向空对象

// 返回这个对象

// let a = 666; // 就是局部执行上下文中的一个局部变量

// this.name = name // 给这个对象添加一个name属性,并赋值

// this.age = age // 给这个对象添加一个age属性,并赋值

// this.say = function(){} // 给这个对象添加一个say属性,并赋值

function CreateDog(name, age){

let a = 666;

this.name = name;

this.age = age;

this.say = function(){

console.log("wangwang...")}}

let wc = new CreateDog("wangcai",100);

console.log(wc.a) // undefined

console.log(wc.name) // wangcai

// this就指向你创建出来的对象

let wc1 = new CreateDog("wc1",1);

let wc2 = new CreateDog("wc2",2);

console.log(wc1) // {name: "wc1", age: 1, say: ƒ}

console.log(wc2) // {name: "wc2", age: 2, say: ƒ}

console.log(wc1 === wc2) // false

// new CreateDog 可以不传参

// new一个类时,可以加(),也可以不加(), 区别是不加()是不能传参

let wc3 = new CreateDog;

console.log(wc3) // {name: undefined, age: undefined, say: ƒ}

instanceof 判断某个对象是否属于某个类(函数,构造器)

function CreateDog(name, age){

this.name = name;

this.age = age;}

let wc = new CreateDog("wangcai",100);

// console.log(wc instanceof CreateDog) // true

6)JS中默认就有很多的类。

如:Number, String, Boolean, Array, Object, Math, Date, RegExp...

基本数据类型也是属于某一个类的对象(实例)

instanceof对于基本数据类型没法检测,typeof可以对基本数据类型进行检测,但是对引用数据类型检测不精确

instanceof和typeof对于数据类型检测都有不足之处。

三 JSON :JavaScript Object Notation JS对象的表示法

// 校验JSON是否合法:http://www.bejson.com/

上网本质:客户端:手机,QQ,浏览器...服务器:计算机,上网就是客户端去请求服务器,服务器返回你需要的数据的过程。

JSON就是客户端与服务器之间通信的一种数据格式。

JSON通常的写法有两种:

数组的形式:[{},{},{}]

对象的形式:{}

1)JSON数据的语法:

1,有键值构成2,键值对与键值对之间使用逗号隔开3,{} 放对象 [] 放数组4,键也必须使用双引号包起来

var Stu = [

{"id":1,"name":"z3","age":4,"score":"10"},

{"id":2,"name":"z4","age":5,"score":"11"},

{"id":3,"name":"z5","age":6,"score":"12"}

]

var obj = {

name:"wangcai",

age:100,

isSleep:true,

say:function(){

}}

 

2)JSON:JavaScript Object Notation JS对象的表示法

是一种特殊的JS对象,JSON是一种轻量级的数据交换格式。

操作JSON: CRUD操作(增删改查)

var stu = [

{"id":1,"name":"z3","age":4,"score":"10"},

{"id":2,"name":"z4","age":5,"score":"11"},

{"id":3,"name":"z5","age":6,"score":"12"}

]

// 访问

console.log(stu[0])

console.log(stu[0].name)

console.log(stu[0]["name"])

 

// 修改

stu[0].score = "100"

console.log(stu[0])

 

// 删除

delete stu[0].score;

console.log(stu[0])

 

// 遍历

for(var i=0; i<stu.length; i++){

// console.log(stu[i])

for(var item in stu[i]){

console.log(stu[i].age)

}}

2)JSON对象,JSON字符串

JSON有两种形式:JSON字符串:本质是一个字符串,只能通过单引号引起来

JSON字符串:本质是一个字符串,只能通过单引号引起来

JSON对象:比较特殊的js对象

JSON对象

var obj = [{"id":"01","name":"wangcai"}]

JSON字符串

var obj = '[{"id":"01","name":"wangcai"}]'

JSON字符串和JSON对象之间的咋转化

把JSON对象转成JSON字符串

var obj = [{"id":"01","name":"wangcai"}]

let str = window.JSON.stringify(obj)

console.log(str)

 console.log(typeof str)//string

把JSON字符串转成JSON对象

var obj = ‘[{"id":"01","name":"wangcai"}]’

let str = window.JSON.parse(obj)

console.log(str)

 console.log(typeof str)//Object

四 原型和原型链

propertype 原型

 1)没一个函数(函数也是一个对象)都有一个prototype属性。prototype是一个属性名,它的属性值是一个对象,这个对象我们叫原型对象。

2)原型对象上放了很多的公共的属性和方法。

3)每一个原型对象上面必有一个属性叫constructor。construct也是一个属性名,它的属性值是当前函数本身

4)每一个对象上都有一个属性叫__proto__,也是属性名,它指向原型对象

Func是一个类(构造器),本质是一个函数,函数也是对象

每一个函数(函数也是对象)都有一个prototype属性

function Func(){

this.name = "xxx"

}

// obj1中的__proto__指向创建obj1这个对象的类的原型对象。

let obj1 = new Func();

let obj2 = new Func();

Func.prototype.say = function(){

console.log("say...")

}

访问对象中的属性:

访问对象中的属性

// console.log(obj1.name) // 它内部有name属性,就去它内部找

// obj1.say() // 它内部没有say方法,就去它的原型对象中找

// obj2.say() // 它内部没有say方法,就去它的原型对象中找

Object是所有对象的最顶层的类,也叫基类。所以Object.prototype.__proto__指向它自己。

 由于指向自己没有任何意义,所以说它的默认值就是null

原型链:如果找一个属性,先在自己内部(私有的)找,如果有,就使用,不再向后找。

如果没有,就沿着__proto__,找类原型对象上的属性,一直向上找,直到找到Object.prototype为止。

// 测试题

console.log(obj1.say === obj2.say) // true

console.log(Func.prototype.say === obj1.say) // true

console.log(obj1.__proto__.say === Func.prototype.say) // true

console.log(obj1.__proto__ === Func.prototype) // true

console.log(obj1.name === obj2.name) // true

console.log(obj1 instanceof Func) /// true

console.log(obj1 instanceof Object) // true

 

原型和原型链(关于js中内置对象)

内置对象Array(构造器),arr叫对象。

var arr1 = new Array("a","b","c")

var arr2 = new Array("d","e","f")

console.log(Array.prototype === arr1.__proto__) // true

console.log(Array.prototype.push === arr1.push) // true

console.log(arr1 === arr2)//false

console.log(arr1 instanceof Array)//true

console.log(arr1 instanceof Object)//true

原型链:

console.dir(arr1.__proto__)

console.dir(arr1.__proto__.__proto__)

console.dir(arr1.__proto__.__proto__.__proto__) // null

五:this问题

// ------------------ 情况一:在监听器中this表示事件源

// DOM

var btn = document.getElementById("btn")

// btn叫事件源 on是前缀 click中事件类型

// function(){} 事件处理程序(监听器)

btn.onclick = function(){

// alert(this) // [object HTMLButtonElement]

console.log(this)

// alert("登录成功...")

}

//------------------ 情况二:在非严格模式下,this出现在普通的函数中,表示window,在严格模式下,表示undeeind

function f(){

console.log(this) // Window }

f()

function f(){

"use strict"

console.log(this) // undefined}

f()

// ------------------ 情况三:this出现在一个对象的方法中,表示当前这个对象

var obj = {

name:"wangcai",

say:function(){

console.log(this) // {name: "wangcai", say: ƒ}}}

obj.say();

// ------------------ 情况四:this出现在一个类中,表示指向一个新对象

function Func(){

 this.name = "xxx";

console.log(this) // {name: "xxx"} }

let obj1 = new Func();

// ------------------ 情况五:在全局作用域下,this表示window

console.log(this) // Window

注意:方法中的this指向不确定,谁调用了方法,this就是谁

注意:不管是私有方法还是公有方法,谁调用了方法,this就是谁

六:关于匿名函数

把一个匿名函数赋给f

// var f = function(){}

g是函数名 对于函数表达式来说,可以指定函数名

// var f = function g(){console.log("haha...")}

// f()

// 不能通过函数表达式的函数名来调用函数

// g() // g is not defined

g是函数名,可以在函数体中使用,可以通过g()调用这个函数,但是没有出口会死循环,把基本数据类型赋值给g没有作用,引用数据类型赋值给g也没有作用。

对于函数表达式来说,它可以有函数名,不能在函数外面通过函数名调用这个函数,可以在函数内部使用函数名或函数调用(死循环),不能给这个函数名重新赋值

七:call方法

------------------------------------------ 初步了解call方法

1)call是函数的原型对象上的方法

 2)一个函数.call,可以把这个函数调用了

 3)f.call() f中的this表示window

 4)f.call(obj) f中的this表示obj

// 需求,想通过obj调用f函数,怎么做?

 方式一:把函数作为obj的属性:把这个函数挂在obj的属性上面

// obj.f = f;

// obj.f(); // f....

方式二:不作用obj的属性,用完就删除

// delete obj.f;

// console.log(obj) // {name: "wangcai"}

方式三:使用call 表示让obj去借用f方法 f方法中的this就指向obj

f.call(obj);

console.log(obj) // {name: "wangcai"}

----------------- 在JS中,this的指向可以通过call进行改变

 深入了解call方法 call的第一个参数-----------------第一个参数

// fn.call目的是让fn执行,并且改变fn中this的指向

// 在JS中,this的指向可以通过call进行改变

function fn(){

console.log(this)

console.log("fn...")

}

// fn() 它里面的this表示window

// fn.call(); // fn中的this表示window

// fn.call(123) // fn中的this表示Number {123}

// fn.call("hello") // fn中的this表示String {"hello"}

// fn.call(true) // fn中的this表示Boolean {true}

// fn.call({}) // {}

// let obj = {name:"xxx"}

// fn.call(obj) // {name: "xxx"}

// ----------------- 深入了解call方法 call的其它参数

 call方法支持传参,从call方法的第2个实参起,就表是实参列表

let r = fn.call(obj,1,2)

console.log(r)

// ----------------- 深入了解call方法 call的其它参数----------------------

// 总结:

// 1)call是函数的原型对象上的属性

// 2)任何一个函数都可以.call

// 3)当一个函数.call时,这个函数被执行,函数中的this就指向了call中的第1个实参

// 4)如果call方法没有实参,这个函数也能执行,只是函数中this表示window(非严格模式下),在严格模式下,是undefined

// 5)如果call的第一个参数是null,非严格模式下,函数中的this表示window,严格模式下,this表示null

// 6)函数.call()时,函数肯定会执行,可以给函数传参,从call的第2个参数起的实参,都会传给这个函数

//手写call原理,这里就不描述了。

八:apply方法

apply和call的唯一区别是传参的区别。call是一个一个传参,apply是通过数组的形式传参。apply方法原理这里不写。

function fn(a, b){

console.log(this);

return a+b;

}

var obj = {name:"xxx"}

// fn.call(obj,11,22)

let res = fn.apply(obj,[11,22])

console.log(res)

 

九:bind方法

1)和call/apply一样,都可以改变函数中的this。

 2)和call/apply不一样,bind不会让前面的函数执行。需要手动调用。

// ----------------- bind的应用场景

<button id="btn">登录</button>// btn叫事件源 click叫事件类型 function(){}叫监听器

var btn = document.getElementById("btn");

// btn.onclick = function(){//注册点击事件

// console.log("....")

// }

 JS是单线程,同一时刻只能执行一个任务,他先把同步任务执行完,当异步任务发生,才会执行异步任务。

// console.log("start")

// function fn(){

// console.log("666")

// }

// // 事件是异步任务

// btn.onclick = fn;

// console.log("end")

// function fn(){

// console.log(this)

// }

// btn.onclick = fn;

 

// 需求:不想让监听器中的this表示事件源,想让this表示obj

// var obj = {name:"xxx"}

// function fn(){

// console.log(this)

// }

// btn.onclick = fn.call(obj) // 此时使用call就不合适了,因为call会立即执行

// // 需求:不想让监听器中的this表示事件源,想让this表示obj

// var obj = {name:"xxx"}

// function fn(){

// console.log(this)

// }

// btn.onclick = function(){

// fn.call(obj)

// }

 需求:不想让监听器中的this表示事件源,想让this表示obj

var obj = {name:"xxx"}

function fn(){

console.log(this)

}

btn.onclick = fn.bind(obj);

bind的原理这里不描述了

十:判断一个属性是否是公有属性(面试题中提及)

一个面试题:

function fn1(){console.log(1)}

function fn2(){console.log(2)}

fn1.call(fn2); //1

fn1.call.call(fn2); //2

Function.prototype.call(fn1) //无

Function.prototype.call.call(fn1) //1

十一:继承和原理在企业面试题中提及:

求数组中最大最小值的四种方法:

基于原型链继承:

基于call或者apply继承:

组合继承:

完美继承:

封装一个方法实现继承:

new原理实现:

instanceof原理实现:

call原理:

apply原理:

bind原理:

myflat原理:

push原理:

// push的原理 Array.prototype.push = function(value){

// this[this.length] = value;

// this.length++;

// return this.length;

// }

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值