构造函数
箭头函数不能用来做构造函数,箭头函数没有this,不能new
构造函数首字母一般大写,使用大驼峰命名
function Person (name) {
// 构造函数里的this指向将来new的那个对象
this.name = name // 给this对象新增一个name属性,属性值为参数name
this.say = function () {
console.log(this.name)
}
}
// Person()
var xm = new Person('xiaoming')
console.log(xm)
xm.say()
var xh = new Person('xiaohong')
console.log(xh)
xh.say()
function Person (name) {
this.name = name
this.say = function () {
console.log(this.name)
}
}
// 给Person的原型对象上新增eat方法
Person.prototype.eat = function (food) {
// 原型方法的this也是指向将来的实例对象
console.log(`${this.name} is eating ${food}`)
}
var xm = new Person('xiaoming')
var xh = new Person('xiaohong')
// 构造函数里的方法不能复用,每个实例对象里都存了一份一摸一样的方法,浪费内存
console.log(xm.say === xh.say) //false
console.log(Person)
console.dir(Person) //用来打印对象的详细信息,可以发现会有prototype 和 __proto__两个属性 实例对象的__ptoto__指向构造函数的prototype
// 实例对象可以调用原型上的方法
xm.eat('rice')
xh.eat('noodles')
console.log(xm.eat === xh.eat)
console.log(xm)
// 实例对象都有__proto__属性,这个属性指向构造函数的prototype
console.log(xm.__proto__ === Person.prototype) // true
// console.log(xm.toString())
// person的原型也是一个普通对象,就相当于来自于new Object(),所以他也有__proto__属性,这个属性指向Object.prototype
console.log(Person.prototype.__proto__ === Object.prototype)
console.log(Object.prototype.__proto__) // null
// 对象沿着原型一层一层往上查找的过程称之为原型链
// 所有原型链的终点都是Object.prototype
// js中任意数据都可以沿着自己的原型链最终找到Object.prototype,因此,一切皆为对象
// js中顶级对象就是Object,Object是所有对象里基类
当new去调用函数的时候,实际上new帮我们做了四件事
// 下面这些代码是伪代码,不能执行,只是演示过程
// function Animal (name) {
// // 1、new一个对象
// var obj = new Object()
// // 2、把this指向这个对象
// this = obj
// // 3、执行函数代码
// this.name = name
// // 4、返回这个对象
// return this
// }
给原型添加方法
Object.assign(Animal.prototype, {
say () {
},
init () {
}
})
function Animal (name) {
this.name = name
}
var dog = new Animal('mender')
console.log(dog)
// 下面这个写法可以更方便的写原型方法
Object.assign(Animal.prototype, {
say () {
},
init () {
}
})
console.log(Animal.prototype)
// 原型上的constructor属性指向构造函数本身
console.log(Animal.prototype.constructor === Animal) // true
console.log(dog instanceof Animal) // true
console.log(dog instanceof Object) // true
console.log(dog instanceof Function) // false
// instanceof用来判断数组
var arr = [3,4,5]
console.log(typeof dog) // object
console.log(typeof arr) // object
console.log(arr instanceof Array) // true
console.log(dog instanceof Array) // false
console.log(dog.hasOwnProperty('name')) // true
console.log(dog.hasOwnProperty('say')) // false
console.log(dog.hasOwnProperty('abc')) // false
// 判断Animal的protytype在没在dog的原型链上
console.log(Animal.prototype.isPrototypeOf(dog)) // true
class Person {
constructor (name) {
this.name = name
}
say () {
console.log(this.name)
}
}
var xm = new Person('xiaoming')
var xh = new Person('xiaohong')
// class上写的方法默认在构造函数的原型上
console.log(xm.say === xh.say) // true
this指向
// 1、全局this指window
console.log(this) // window
// 2、全局函数里的this指window
function fn () {
console.log(this) // window
}
fn()
// 3、事件里的this指向当前事件绑定的DOM对象
document.querySelector('#box').onclick = function () {
console.log(this) // box
}
// 4、对象里的this指向当前对象本身
var obj = {
fn: function () {
console.log(this) // obj
}
}
obj.fn()
// 5、构造函数里的this指将来实例化(new)出来的对象
function Person () {
console.log(this) // xm
}
var xm = new Person()
// 6、原型方法里的this指将来new的对象
Person.prototype.say = function () {
console.log(this) // xm
}
xm.say()
// 7、IIFE里的this指window
;(function () {
console.log(this)
})()
// 8、只要没有说明归属的匿名函数的this指window
setTimeout(function () {
console.log(this)
}, 1000)
// 9、箭头函数没有自己的this
const foo = () => {
console.log(this) // window
}
foo()
var obj2 = {
fn: function () {
setTimeout(function () {
console.log(this) // window
}, 1000)
},
fn2: function () {
setTimeout(() => {
console.log(this) // obj2
}, 1000)
}
}
obj2.fn()
obj2.fn2()
var a = 2
function fun () {
console.log(this.a)
}
var o = {a: 3, fun: fun}
o.fun() // 3
var p={ a: 4 }
// 把赋值结果放入一个新的函数里在调用,this还是window
;(p.fun=o.fun)() // 2
// 在面向对象程序里使用this
// 1、this指当前对象用普通函数
// 2、this指外层用箭头函数
// 3、内外都需要,就在外层用_this存起来,this指内层, _this指外层
// function fn () {
// const _this = this // 把外层this存起来了
// function foo () {
// this指向内层对象
// _this指向外层对象
// }
// }
改变this指向
1、bind(this):将this指向外层
2、call() apply()都是在函数调用前修改this指向。区别在于后面的传参方式,如下
var a = 20
var obj1 = {
a: 10,
fn: function (x, y) {
console.log(this.a + x + y)
},
fn2: function () {
// bind是在封装函数的时候直接把this修改为外层
// ES6有了箭头函数,bind相对用的少了
setTimeout(function () {
console.log(this.a)
}.bind(this), 1000)
}
}
obj1.fn(1, 2) // 10
// call和apply都是在函数调用之前修改this指向,区别在于传参
// call的参数依次传递即可
// apply需要传递一个数组
obj1.fn.call(window, 1, 2) // 把fn里的this指向window
obj1.fn.apply(window, [1, 2])
obj1.fn2()