创建对象
对象的创建也比较简单,一共有三种方式
-
通过字面量
var Student = { name: 'Robot', height: 1.2, run: function () { console.log(this.name + ' is running...') } } Student.run()
-
通过构造函数
先定义一个构造函数,通过 new 构造函数可以创建一个类
function Student(name) { this.name = name this.hello = function () { alert('Hello, ' + this.name + '!') } } var xiaoming = new Student('小明') xiaoming.name xiaoming.hello()
-
使用 class 关键字
新的关键字 class 从 ES6 开始正式被引入到 JavaScript 中,让定义类和继承类更简单
class Student { constructor(name) { this.name = name } hello() { alert('Hello, ' + this.name + '!') } } var xiaoming = new Student('小明') xiaoming.name xiaoming.hello()
原型与隐式原型
prototype
称为原型,是构造函数的一个属性
__proto__
称为隐式原型,是对象的一个属性
为了实现继承,因此对象隐式原型指向构造函数的原型
function Person(age) {
this.age = age || 0
}
Person.prototype.print = function () {
console.log('age', this.age)
}
let p = new Person(18)
console.log(p.__proto__ == Person.prototype)
console.log(Person.prototype.constructor == Person)
console.log(p.print())
你甚至可以这样做
let arr = { 0: 'zs', 1: 'ls', length: 2 }
console.log(arr)
// 强制改成Array
arr.__proto__ = Array.prototype
console.log(arr)
arr.push('we')
console.log(arr)
同时构造函数也是一个对象,他也具有__proto__
属性。Person 本身是一个函数,它的构造方法是 Function
Person.__proto__ == Function.prototype
对于基础构造函数的__proto__
属性
// 全是 ƒ () { [native code] } 都相等
console.log(Object.__proto__)
console.log(Function.__proto__)
console.log(Array.__proto__)
console.log(Number.__proto__)
console.log(Date.__proto__)
// Function.__proto__.__proto__
[native code].__proto__ == Object.prototype
对于基础构造函数的prototype
属性
Number.prototype // Object(0)
String.prototype // Object("")
Boolean.prototype // Object(false)
Array.prototype // []
Function.prototype // function(){}
Date.prototype // new Date(NaN)
属性/方法继承
通过原型可以清晰的发现有一条链式关系
let arr = new Array(1, 2)
app.push(3)
console.log(arr.__proto__ == Array.prototype)
console.log(Array.prototype.__proto__ == Object.prototype)
console.log(Object.prototype.__proto__ == null)
这个就是原型链
arr ---> Array.prototype ---> Object.prototype ---> null
当执行 push 方法的时候会顺着原型链去查找 push 的定义
// arr.push实际调用的是Array.prototype里面定义的方法
window.Array.prototype.push.call(arr, 3)
对于两个类是否具有继承关系,看他们的原型链就行了
function Student(name) {
this.name = name
}
// 绑定,不是继承
function GoodStudent(name) {
this.start = 5
Student.call(this, name)
}
// 这才是继承
function GoodStudent(name) {
this.start = 5
this.__proto__ = new Student(name)
}
new 的过程
有时候会很好奇,构造函数里面的 this 怎么就可以把属性绑定到对象上面呢
其实在 new 的过程中通过 call 或者 apply 的方式 this 映射到对象上,然后去调用 constructor
let p = new Person(18)
// 等价于
let p = Object.create(Person.prototype)
// p.__proto__ == Person.prototype
p.constructor.call(p, 18)
// Person.call(p,18)
instanceof
instanceof 的左值一般是一个对象,右值一般是一个构造函数,用来判断左值是否是右值的实例
var arr = [1, 2, 3]
// true
console.log(arr instanceof Array)
// true
console.log(arr instanceof Object)
它的判断依据如下
L.__proto__.[__proto__ ...] === R.prototype
所以就不难理解
// Object.__proto__ [Native Code]
// Function.prototype [Native Code]
// Function.__proto__ [Native Code]
console.log(Object instanceof Function) // true
console.log(Function instanceof Function) // true
console.log(Function instanceof Function) // true
// Number.__proto__ [Native Code]
// [Native Code].__proto__ Object.prototype
// [Native Code].__proto__.__proto__ null
console.log(Number instanceof Number) // false
总结
如果浏览器版本支持,最好使用 ES6 新提供的 class 关键字去定义类
如果弄不清 this 的指向,可以直接使用箭头函数
class Person extends Object {
// 定义类属性
name = '临时姓名'
constructor(age) {
super()
// 定义类属性
this.age = age || 0
}
// 静态方法
static Hello() {
console.log('hello')
}
}
console.log(new Person(18))