跳到主要内容

3 篇博文 含有标签「javascript」

查看所有标签

prototype

所有的函数都有一个prototype属性 将函数看成是一个普通的对象时,它具备__proto__属性

构造函数Parent有一个原型对象Parent.prototype上面有一个constructor Parent可以通过 prototype 指向原型 原型Parent.prototype可以通过constructor指向构造函数

function Parent() {
this.name = "parent";
}

var p = new Parent();
console.log(p.__proto__ === Parent.prototype); // true

__proto__是一个指向原型对象的指针,它指向的是Parent.prototype 可以使用 getPrototypeOf

如果要创建一个新的对象同时继承另一个对象的属性,可以使用Object.create

function Parent() {
this.name = "parent";
}
var p = new Parent();
var p1 = Object.create(p);

创造原型对象的方法

function createObject(o) {
function f() {}
f.prototype = o;
return new f();
}
//创建对象的过程
function inherit(Subtype, Supertype) {
Subtype.prototype = createObject(Supertype);
Object.defineProperty(Subtype.prototype, "constructor", {
enumerable: false,
configurable: true,
writable: true,
vlaue: Subtype,
});
}
//寄生式函数

这种方法是将子类的原型对象指向父类的原型对象,同时将子类的原型对象的构造函数指向子类

javascript阅读需 1 分钟

假设存在一个函数func func接受三个参数 a b c 那么函数最多被柯里化三次

function func(a, b, c) {
return a + b + c;
}
var c1 = curry(func, 1);
var c2 = curry(func, 2);
var c3 = curry(func, 3);
c3(); //6

参数定长的柯里化

function curry(fn) {
const argLen = fn.length;
const presetArg = [].slice.call(arguments, 1);
return function () {
const restArgs = [].slice.call(arguments);
const allArgs = [...presetArg, ...restArgs];
if (allArgs.length >= argLen.length) {
return fn.apply(this, allArgs);
} else return curry.call(null, fn, ...allArgs);
};
}

这样写我们的柯里化就支持三个参数的运算

function func(a, b, c) {
return a + b + c;
}
var currried = curry(func);
curried(1, 2, 3);
curried(1)(2, 3);

参数不定长的柯里化

我们需要让这个函数满足返回一个函数并且可以通过这个函数来得到我们要的值

function curry_unlimited(fn) {
const presetArg = [].slice.call(arguments, 1);
function curry_unlimited() {
const restArgs = [].slice.call(arguments);
const allArgs = [...presetArg, ...restArgs];
return curry_unlimited.call(null, fn, ...allArgs);
}
curry_unlimited.toString = function () {
return fn.apply(null, presetArg);
};
return curry_unlimited;
}

测试这个参数不定长的柯里化

const curriedSum = curry_unlimited(sum);
function sum(...args) {
return args.reduce((acc, curr) => acc + curr, 0);
}
// 测试不同的调用方式
console.log(curriedSum(1)(2)(3) + ""); // 输出 6
console.log(curriedSum(1, 2, 3)(4)(5) + ""); // 输出 15
javascript阅读需 1 分钟

  • 函数在调用的过程中,JavaScript 会给 this 一个值
  • this 的绑定和定义的位置没有关系
  • this 的绑定和调用的方式和调用的位置有关

this 的四个绑定规则

  • 默认绑定
  • 隐式绑定
  • 显示绑定
  • new 绑定

默认绑定

function foo() {
console.log(this);
}
foo(); //这里独立函数调用输出window

把函数定义在对象中,但是独立调用

var obj = {
name: "fanc",
bar: function () {
console.log("bar:", this);
},
};
var bazzz = obj.bar;
bazzz();

严格模式下独立调用函数中的 this 指向的是 undefined

隐式绑定

必须在调用对象的内部有一个对函数的引用,如果没有这样的引用就会报错找不到函数

function foo() {
console.log("foo:", this);
}
var obj = {
bar: foo,
};
obj.bar();
function foo() {
console.log(this);
}
var obj1 = {
name: "obj1",
foo: foo,
};
var obj2 = {
name: "obj2",
foo: foo,
obj1: obj1,
};
foo(); // window
obj1.foo(); // obj1
obj2.foo(); // obj2
obj2.obj1.foo(); // obj1

obj2.obj1就是调用了 obj1

new 绑定

创建一个全新的对象 这个新对象会被执行 prototype 连接 这个欣对象会绑定到函数调用的 this 上 如果函数没有返回其他的对象,表达式会返回这个新对象

function preson() {
console.log("foo:", this); //person
}
new foo();

显示绑定

var obj = {
name: "obj",
};
function foo() {
console.log("foo:", this);
}

//直接执行函数,this的指向为obj
foo.call(obj); //foo: {name: "obj"}
foo.apply(obj); //foo: {name: "obj"}

如果不想再对象内部包含这个函数的引用,可以使用 call 或者 apply 来改变 this 的指向

如果要传递参数怎么办 apply第一个参数是绑定 this 的第二个参数是传递额外的实参,是以数组的形式

function foo(a, b) {
console.log("foo:", this, a, b);
}
foo.apply(obj, [1, 2]); //foo: {name: "obj"} 1 2

call 是多参数的形式来进行传递的

foo.call(obj, 1, 2); //foo: {name: "obj"} 1 2

bind

bind方法会创建一个新的绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入的第一个参数作为 this,传入的第二个参数加上绑定函数运行时传入的参数按顺序作为参数来调用原函数

function foo() {
console.log("foo:", this);
}
var obj = {
name: "obj",
};
var bar = foo; //这里bar是一个全局函数
bar(); //foo: window
//如果是
var bar1 = foo.bind(obj);
bar1(); //foo: {name: "obj"}

bind 也是和 call 一样的

function foo(a, b) {
console.log("foo:", this, a, b);
}

内置函数的调用绑定

setTimeout(function () {
console.log("foo:", this); //window
}, 1000);

[1, 2, 3].forEach(function (item) {
console.log("item:", this);
}, "aaa");
//item: aaa

var btnEl = document.getElementById("btn");
btnEl.onclick = function () {
console.log("this:", this); //btn
};

this 绑定的优先级

显示绑定的优先级高于隐式绑定

function foo() {
console.log("foo:", this);
}
var obj1 = {
name: "obj1",
foo: foo,
};
var obj2 = {
name: "obj2",
};
obj1.foo.call(obj2); //foo: {name: "obj2"}

这里的隐式绑定是 obj1.foo,但是显示绑定是 obj2

new 绑定高于隐式绑定

var obj = {
name: "obj",
foo: function () {
console.log("foo:", this);
},
};
new obj.foo(); //foo: {}

new 不可以和 call apply 一起使用

new 和 bind 可以一起使用并且 new 绑定高于显示绑定

function foo() {
console.log("foo:", this);
}

var bar = foo.bind("aaa");
new bar(); //foo: {}

new 绑定高于显示绑定

var obj = {
name: "obj",
foo: function () {
console.log("foo:", this);
},
};
var bar = new obj.foo();

箭头函数的 this

箭头函数没有 this,箭头函数的 this 是继承外层的 this

var obj = {
name: "obj",
foo: function () {
setTimeout(() => {
console.log("foo:", this);
}, 1000);
},
};
obj.foo(); //foo: {name: "obj"}
javascript阅读需 4 分钟