Skip to content

参数按值传递

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指向不变

  1. 返回一个新的函数
  2. 能够传入参数

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)