函数对象
function foo(a, b) {
return a * b
}
1. length属性
foo.length
// 2
参数个数为2
2. constructor属性
foo.constructor)
// [Function: Function]
constructor属性,引用的是Function()这个构造器函数
3.arguments对象
function f() {
return arguments
}
f(1, 2, 3) // [1, 2, 3]
arguments 是类数组对象,包含了索引元素和length属性,但是不提供sort()、slice()这样的方法
可以将类数组转化为数组
function f() {
return [].slice.call(arguments)
}
4. call 和 apply方法
这两个方法用来触发函数,并制定相关的调用参数。最重要的功能,是它可以让一个对象去"借用"另一个对象的方法
const obj = {
name: 'Ninja',
say (who) {
return `${who} say I'm ${this.name} `
}
}
obj.say('Jack')
// Jack say I'm Ninja
const my = {name: ‘runner’}
obj.say.call(my, 'Lee')
// Lee say I'm runner
当call被调用时,其中的this,就被自动设置成了my对象的引用,this.name返回的不再是"Ninja",而是"runner"了。
如果没有指定call的第一个参数,或者传入null,它的调用对象会被默认为全局对象
call()传入参数,是一次传入
obj.say.call(my, 'a', 'b', 'c')
apply() 传入参数是以数组的形式
obj.say.apply(my, ['a', 'b', 'c'])
5. prototype属性
typeof foo.prototype
// object
function Person(name, age) {
this.name = name
this.age = age
this.say = function() {
return `I'm ${this.name}, ${this.age}`
}
}
5.1 通过prototype添加属性和方法
Person.prototype.place = 'china'
Person.prototype.getInfo = function() {
return `I'm come from ${this.place}`
}
const bob = new Person('bob', 18)
bob.say()
// I'm bob, 18
bob.getInfo()
// I'm come from china
对于原型来说,它具有"实时"性。js中对象都是通过引用传递,因此我们创建的所有实体中并没有一份属于自己的原型副本。
这意味着我们随时可以修改prototype属性,并且由同一个构造器创建的所有对象的prototype属性也都会同时改变
5.2当向原型添加新方法
Person.prototype.get = function(what) {
return this[what]
}
bob对象在新方法定义之前就被创建,但是依然可以在该对象中访问新增的方法
bob.get('place')
5.3 自身属性与原型属性
getInfo()
方法中用this指针访问对象,也可以用Person.prototype
Person.prototype.getInfo = function() {
return `I'm come from ${Person.prototype.place}`
}
bob.place
访问实例的属性时,在bob对象上找不到place,就会去构造器的原型bob.constructor.prototype
上查找。
bob.constructor === Person
bob.constructor.prototype.place === bob.place
5.4 利用自身属性重写原型属性
Person.prototype.name = 'mirror'
bob.name = 'dog'
bob.name
// 'dog'
bob.hasOwnProperty('name'))
// true
delete bob.name
bob.name
// 'mirror'
bob.hasOwnProperty('name')
// false
hasOwnProperty属性可以判断原型属性到底是原型链中哪个原型的属性
bob.toString()
// [object Object]
bob.hasOwnProperty('toString')
// false
bob.constructor.hasOwnProperty('toString')
// false
bob.constructor.prototype.hasOwnProperty('toString')
// false
Object.hasOwnProperty('toString')
// false
Object.prototype.hasOwnProperty('toString')
// true
5.5 枚举
使用for-in枚举对象的属性
-
- 不是所有的属性都可以被枚举,length、constructor属性就不会被显示。判断属性是否可以被枚举,可以用propertyIsEnumerable()方法来判断
-
- 原型链中的属性也会被显示出来,前提是可以被枚举。可以使用hasOwnProperty判断是自身属性还是原型属性
-
- 对于原型属性,propertyIsEnumerable()都会返回false
for(let prop in bob) {
console.log(`${prop} = ${bob[prop]}`)
}
for(let prop in bob) {
if (bob.hasOwnProperty(prop)) {
console.log(`${prop} = ${bob[prop]}`)
}
}
bob.propertyIsEnumerable('place')
// false
5.6 isPrototypeOf()
每个对象都有一个isPrototypeOf()方法,判断当前对象是否是另一个对象的原型
const monkey = {
hair: true,
feeds: 'bananas',
breathes: 'air'
}
function Human(name) {
this.name = name
}
Human.prototype = monkey
const tom = new Human('tom')
monkey.isPrototypeOf(tom)
// true
在知道monkey可能是tom的原型才使用isPrototypeOf
判断
在不知道某个对象原型是什么的情况下,使用Object.getPrototypeOf()
方法来判断
Object.getPrototypeOf(tom) === monkey
// true
5.7 __proto__
tom.feeds = 'rice'
tom.feeds
// rice
tom.breathes
// air
breathes 不在tom对象的自身属性中,所以就去原型中查询,有一个__proto__
属性链接原型
tom.__proto__ === monkey
// true
__proto__
是某个实例对象的属性,prototype是构造器函数的属性