简述面向对象
// 类。每一个类都有一个属性原型'prototype'
function Person(){
this.skin='黄色'
this.hair='黑头发'
this.spack=function(){
console.log('hello')
}
}
//实例。每一个实例都有一个属性叫做隐式原型'__proto__',它和该实例的类的原型是一样的,所以实例的__proto__ === 类的prototype !
// 这就是经常说的原型链
var ming=new Person()//这就是类的一个实例,实例就是类的一个具体表现
// 一
function Obj(name){
this.name=name
console.log(this.name)
}
var p=new Obj(大黄)//当我们都通过new一个实例的时候,那么上面构造函数里的this的指向就是p这个实例
// 二
var two={
name:'大黄',
sayName(){
console.log(this.name)//这里的this指向就是two这个对象
}
}
two.sayName()
// this在声明的时候并不能看出它到底指向谁,只要一执行它的时候就会知道它到底指向谁
// 比如:
function sayName(){
console.log(this.name)
}
let p1={
name:'m1',
sayName
}
let p2={
name:'m2',
sayName
}
p1.sayName()//此时打印的就是'm1'
p2.sayName()//此时打印的就是'm2'
// 所以说只有在执行的时候才会知道this的指向到底是谁
sayName()// 或者我们可以直接调用 此时this的指向就是全局,也就是window
window.name='全局'//现在它打印出来的就是'全局'
// 所以函数内部的this指向当前函数的执行环境(函数所挂靠的实例对象),如果没有挂靠,那它就会指向全局
// 设定this的意义:同一个函数在不同的环境下执行会有不同的效果(多态)
// 三. 修改this的指向 call、apply、bind
function sayName(){
console.log(this.name)
}
let p1={
name:'m1',
sayName
}
let p2={
name:'m2',
}
p1.sayName()//此时打印的就是m1,但是我想让它打印m2,就是改变this的指向怎么办呢?我们可以用call(p2)
p1.sayName.call(p2,x,x,x,)//此时打印的就是m2,call方法它接受的参数就是新的指向环境,call也有第二个参数。p1.sayName.call(p2,‘m3’)
//注意此时p2里面并没有sayName这个函数,所以说call方法还有劫持的功能,让p2拥有了p1的方法
apply
p1.sayName.apply(p2,['m3','m4'])//apply和call基本是一样的,唯一区别就传参数时apply是放在数组里的,而call可以直接写
bind
p1.sayName.bind(p2,'m3')()//bind和call差不多但是它要在最后加一个小括号,它在执行时返回一个函数所以在后面加小括号来执行它
//这三个方法在面试时被问到的几率还是挺大的,因为它们很有意思,它就像强盗一样可以劫持别人的东西,并且还能执行,传参数
//es6创建一个类
class Obj{//用class的方法创建
constructor(){//构造函数
this.name='大黄',//实例属性
this.age=4
}
speak(){//成员方法,成员方法之间是通过this来沟通的
console.log('他是个好人',this.name)//这样就能拿到上面的name
}
walk(){
console.log('他一天走1万步')
}
}
let huang=new Obj()//这里可以给构造函数传参数
//继承 extends
class myObj{
constructor(){
this.length=0
}
toString(){
console.log('wo是xxxx')
}
}
class myObj2 extends myObj{//这是第一步通过extends继承。
constructor(){
super()//调用super,此时myObj2也拥有了myObj的length和toString方法
}
myLength(){
console.log(this.length)
}
}
let arr=new myObj2()