参数按值传递
JavaScript 中的函数参数都是按值传递的。 按值传递:函数接收的是实参的副本,对副本的修改不会影响实参。(即函数外部的值复制给函数的参数)
javascript
var value = 1;
function changeValue(value) {
value = 2;
console.log(value);
}
changeValue(value); // 2
console.log(value); // 1
javascript
var obj = {
value: 1
}
function changeObjValue(obj) {
obj.value = 2;
console.log(obj.value);
}
changeObjValue(obj); // 2
console.log(obj.value) // 2
javascript
var obj = {
value: 1
}
function changeObjValue(obj) {
obj = 2;
console.log(obj);
}
changeObjValue(obj); // 2
console.log(obj.value) // 1
手写call
call的使用
javascript
const obj = {
value: 1
}
function bar() {
console.log(this.value)
}
bar.call(obj)
手写call实现
- 将要执行的函数设置为this指向对象的属性
- 执行函数
- 将this指向对象的属性删除
javascript
Function.prototype._call = function (thisArg, ...args) {
const fn = Symbol('fn')
thisArg = (thisArg === undefined || thisArg === null) ? window : Object(thisArg)
thisArg[fn] = this
const result = thisArg[fn](...args)
delete thisArg[fn]
return result
}
手写apply
与手写call类似,只是将参数数组作为参数传入
javascript
Function.prototype._apply = function (thisArg, args = []) {
const fn = Symbol('fn')
thisArg = (thisArg === undefined || thisArg === null) ? window : Object(thisArg)
thisArg[fn] = this
const result = thisArg[fn](...args)
delete thisArg[fn]
return result
}
手写bind
bind: 会创建一个新的函数,新函数的this指向bind的第一个参数,其余参数将作为新函数的参数,返回的新函数的this指向不变
- 返回一个新的函数
- 能够传入参数
bind的使用
javascript
const obj = {
value: 1
}
function bar() {
console.log(this.value)
}
const newBar = bar.bind(obj)
newBar(); // 1
javascript
var value = 1;
var foo = {
value: 1
}
function bindFn(name, age, gender) {
this.habbit = 'shopping'
console.log(this.value)
console.log(name, age, gender)
}
bindFn.prototype.friend = 'John'
var bindFoo = bindFn.bind(foo, 'tom')
var obj = new bindFoo(20, 'M')
console.log(obj.habbit) // shopping
console.log(obj.friend) // John
手写bind实现
javascript
Function.prototype._bind = function (thisArg, ...args) {
const _this = this
if (typeof this !== 'function') {
throw new TypeError('this is not a function')
}
const fNOP = function () {}
const fBound = function (...args2) {
return _this._apply(this instanceof fNOP ? this : thisArg, args.concat(args2))
}
// fBound.prototype = this.prototype 会造成共用一个原型,导致修改原型会影响所有实例
fNOP.prototype = this.prototype
fBound.prototype = new fNOP()
return fBound
}
手写new
new的使用
javascript
function Person(name, age) {
this.name = name
this.age = age
this.habbit = 'shopping'
}
const person = new Person('tom', 20)
Person.prototype.friend = 'John'
Person.prototype.sayName = function () {
console.log(this.name)
}
console.log(person.name) // tom
console.log(person.age) // 20
new的实现
javascript
function _new(Constructor, ...args) {
const obj = {}
obj.__proto__ = Constructor.prototype
const result = Constructor.apply(obj, args)
return typeof result === 'object' ? result : obj
}
类数组对象与arguments
类数组对象:拥有length属性,但不是数组,可以通过索引访问其元素,如DOM节点的classList、arguments arguments:类数组对象,包含所有传入函数的参数,可以通过索引访问其元素,但不能直接修改元素值,只能通过arguments.length修改参数个数
javascript
var arrLike = {
length: 3,
0: 1,
1: 2,
2: 'name'
}
console.log(arrLike[0]) // 1
console.log(arrLike.length) // 3
Array.prototype.push.call(arrLike, 'age')
console.log(arrLike.length)