new

原理

用new实例化一个对象后,该对象会继承构造函数及其原型上的属性。可以发现其实new的操作也是一种继承,不过不是类与类之间的继承,而是实例与类之间的继承。
那么 new 在这个生成实例的过程中到底进行了哪些步骤来实现呢?总结下来大致分为以下几个步骤。

  1. function Person(){
  2. this.name = 'Jack';
  3. }
  4. var p = new Person();
  5. console.log(p.name) // Jack
  1. 创建一个新对象;
  2. 将构造函数的作用域赋给新对象(this 指向新对象);
  3. 执行构造函数中的代码(为这个新对象添加属性);
  4. 返回新对象。

    手写一个new

    ```javascript function new() { let obj = {} // 生成一个空对象 let Constructor = [].shift.call(arguments) // 获取第一个参数(构造函数) obj._proto = Constructor.prototype // 对象继承构造函数原型属性方法 let result = Constructor.apply(obj, arguments) // 对象this指向构造函数(继承构造函数的属性和方法) return typeof result === ‘object’ ? result : obj // 确保返回的是一个对象 }

function Person(name) { this.name = name; this.say = function () { console.log(‘my name is ‘ + name); } } Person.prototype.type = ‘人’ let person = new Person(‘hkj’) let person1 = _new(Person,’hkj’) console.log(person) console.log(person1)

  1. `applay,``call`,`bind`都可以改变函数的 this 指向。<br />apply call 的区别在于,传参的写法不同:apply 的第 2 个参数为数组; call 则是从第 2 个至第 N 个都是给 函数的传参;而 bind 和这两个(callapply)又不同,bind 虽然改变了 func this 指向,但不是马上执行,而这两个(callapply)是在改变了函数的 this 指向之后立马执行。
  2. ```javascript
  3. var name = 'name'
  4. var obj = {
  5. name: 'objName'
  6. }
  7. function getName(p1, p2) {
  8. console.log(p1, p2,this.name)
  9. }
  10. getName(1, 2) //1 2 "name"
  11. getName.applay(obj, [1, 2])//1 2 "objName"
  12. getName.call(obj, 1, 2)//1 2 "objName"

applay

apply接收的第一个参数是this,第二个参数是 所需参数所组成的数组。 (中括号内的是可选参数,可写可不写)

  1. Function.apply(obj[,argArray])

applay模拟实现

  1. function myApply(context) {
  2. if (typeof this !== 'function') {
  3. throw new TypeError('Error');
  4. }
  5. context = context || window;
  6. context.fn = this;
  7. var result;
  8. if (arguments[1]) {
  9. result = context.fn(...arguments[1]);
  10. } else {
  11. result = context.fn();
  12. }
  13. delete context.fn;
  14. return result;
  15. }
  16. // 验证
  17. var name = 'name'
  18. var obj = {
  19. name: 'objName'
  20. }
  21. function getName(p1, p2) {
  22. console.log(p1, p2,this.name)
  23. }
  24. Function.prototype.myApply = myApply
  25. getName.myApply(obj,[ 1, 2])//1 2 "objName"

call

  1. 明确是谁调用call:函数。
  2. call接收的第一个参数是要改变的this指向(去执行这个函数)。若无指定,默认为window
  3. call接收的后续参数就是作为调用call的那个函数所需的参数。 ```javascript function myCall(context) { //判断一下 if (typeof this !== ‘function’){ throw new TypeError(‘error’) } //this指向,谁去执行去这个函数 context = context || window //要执行的函数 context.fn = this //取出参数 const args = […arguments].slice(1) //执行函数 const result = context.fn(…args) //删除fn delete context.fn return result }

Function.prototype.myCall = myCall getName.myCall(obj, 1, 2)//1 2 “objName”

  1. <a name="SvuL6"></a>
  2. # bind
  3. bind 方法 与 apply 和 call 比较类似,也能改变函数体内的 this 指向。不同的是,**bind 方法的返回值是函数**,并且需要稍后调用,才会执行。而 apply 和 call 则是立即调用。
  4. ```javascript
  5. function myBind(context) {
  6. if (typeof this !== 'function') {
  7. throw new TypeError('Error')
  8. }
  9. const _this = this
  10. const args = [...arguments].slice(1)
  11. // 返回函数
  12. return function F() {
  13. // 1 判断是否用作构造函数
  14. if (this instanceof F) {
  15. return new _this(...args, ...arguments)
  16. }
  17. // 2 用作普通函数
  18. return _this.apply(context, args.concat(...arguments))
  19. }
  20. }
  21. // 验证
  22. var name = 'name'
  23. var obj = {
  24. name: 'objName'
  25. }
  26. function test(p1, p2){
  27. this.a = p1
  28. this.b = p2
  29. console.log(this.name,p1, p2)
  30. }
  31. Function.prototype.myBind = myBind
  32. var f1 = test.myBind(obj, 1)
  33. f1(2)//objName 1 2