Jul 20, 2023
js中的包装对象 在JavaScript中有三种包装对象,他们对应的构造函数分别是String,Number,Boolean
当我们使用原始类型调用toString方法的时候,原始类型会先通过其包装对象对应的构造函数转换成对象,然后用这个对象调用方法 ,调用方法之后,原始类型仍是原始类型,新创建的包装对象会被销毁
this 指向 JS(ES5)里面有三种函数调用形式:
只需要知道第三种调用形式,才是正常调用形式就很好理解this的指向了
至此我们的函数调用只有一种形式
这样,this 就好解释了
this的变态面试题
proto 和 prototype要了解__proto__ 和 prototype需要了解原型和构造函数
new做了什么
不用创建临时对象,因为 new 会帮你做 不用绑定原型,因为 new 会帮你做(new 为了知道原型在哪,所以指定原型的名字为 prototype) 不用 return 临时对象,因为 new 会帮你做; 不要给原型想名字了,因为 new 指定名字为 prototype。 所以就可以推断出这样:
再看__proto__和prototype
简单手写 trim
bind
关于闭包 经典面试题:
闭包的特点:
能让一个函数维持住一个变量 但并不能维持住这个变量的值 尤其时变量的值会变化的时候 对象是穷人的闭包
对象可以维持住一个变量 如果一门语言不支持闭包,可以用对象代理 闭包是穷人的对象
如果一门语言不支持对象,可以用闭包代理
箭头函数 箭头函数对this与其他变量一视同仁,不会特殊对待。
关于var var生命的变量会自动提升,全局下会自动挂载到window上。
JS内置的高阶函数
bind.call
参考
Unlock Full Access const b = new Number(22);
b.toFixed(2); // b 是一个对象,对象上有toFixed方法
const a = 22;
a.toFixed(2); // b 是一个数字,数字上怎么会有toFixed方法?
(22).toFixed(2); // 调用的时候隐式的包装一下
// let temp = new Number(22)
// value = temp.toFixed(2)
// 删除 temp
// return value
func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2)
func(p1, p2) 等价于
func.call(undefined, p1, p2)
obj.child.method(p1, p2) 等价于
obj.child.method.call(obj.child, p1, p2)
func.call(context, p1, p2)
function func(){
console.log(this)
}
func()
// 等价于
function func(){
console.log(this)
}
func.call(undefined) // 可以简写为 func.call()
var obj = {
foo: function(){
console.log(this)
}
}
obj.foo()
// 等价于
obj.foo.call(obj)
let length = 10
function fn() {console.log(this.length)}
let obj = {
length: 5,
method(fn) {
fn() // fn.bind(undefined)
arguments[0]() // arguments[0].bind(arguments) => fn.bind(arguments)
}
}
obj.method(fn, 1)
// 会打印 3 和 2
// 构造函数
function Person(name) {
this.name = name;
}
Person.prototype.run = function () {
console.log('run');
}
// 或者这样
Person.prototype = {
constructor: Person, // 在构造函数中初始化独有属性
run: function () { // 共有属性
console.log('run');
}
}
const p = new Person('x')
// 1 2 3 为new做的事情
const p = function('x') {
this = {} // 1. 初始化this
this.name = 'x'; // 初始化独有属性
this.__proto__ = Person.prototype; // 2. 构造函数添加__proto__并指向prototype(共有属性)
return this; // 3. 返回当前对象
}
a = {} // new Object()
// 1. new 之后就有__proto__
// 2. __proto__等于普通对象的prototype
a.__proto__ === window.Object.prototype // true
// 原型(共有属性)找到根上就是null了
window.Object.prototype.__proto__ // null
// prototype 指向一块内存,这个内存里面有共用属性
// __proto__ 指向同一块内存
// prototype 和 __proto__ 的不同点在于prototype 是构造函数的属性,而 __proto__ 是对象的属性
// 难点在于……构造函数也是对象!
// 如果没有 prototype,那么共用属性就没有立足之地
// 如果没有 __proto__,那么一个对象就不知道自己的共用属性有哪些。
var a = {} // new Object()
a.toString === window.Object.prototype.toString // true
a.__proto__.toString === window.Object.prototype.toString // true
var b = [] // new Array()
b.split === window.Array.prototype.split // true
b.__proto__.split === window.Array.prototype.split // true
window.Object.prototype.__proto__ // null
const trim = (str) =>{
return str.replace(/^\s+|\s+$/g, '')
}
const trim2 = (str) => {
while (str[0] === ' ') {
str = str.slice(1)
}
while (str[str.length - 1] === ' ') {
str = str.slice(0, -1)
}
return str
}
const bind = function(asThis, ...args) {
return (...args2) => {
this.call(asThis, ...args, ...args2);
}
}
// 打印6个6
for (var i = 0; i < 6; i++) {
setTimeout(() => {
console.log(i)
}, 0)
}
// 怎么解决两种方案 一种用匿名函数 另一种使用let
// 原因 用var时所有闭包公用一个i 用let每个闭包分配一个i
for (var i = 0; i < 6; i++) {
!function (i) {
setTimeout(() => {
console.log(i)
}, 0)
}(i)
}
for (let i = 0; i < 6; i++) {
setTimeout(() => {
console.log(i)
}, 0)
}
Function.prototype.bind
Function.prototype.apply
Function.prototype.call
Function.prototype.sort
Function.prototype.map
Function.prototype.filter
Function.prototype.reduce
var bind = Function.prototype.bind;
var f1 = function () {
console.log(this);
console.log(arguments);
console.log("---------");
};
var newF1 = f1.bind({ a: 1 }, 1, 2, 3);
// console.log(newF1());
// 定理: 以下两个等价
// obj.method(a,b,c)
// obj.method.call(obj, a,b,c)
// 设 obj = f1
// 设 method = bind
// 代入
// f1.bind(a,b,c)
// f1.bind.call(f1, a,b,c)
// 代入参数
// f1.bind({ a: 1 }, 1, 2, 3)
// f1.bind.call(f1, { a: 1 }, 1, 2, 3)
// f1.bind === Function.prototype.bind
// var bind = Function.prototype.bind;
// 所以 f1.bind === bind
// bind.call(f1, { a: 1 }, 1, 2, 3)
// bind.call 接收一个函数 fn this arguments
// 返回一个新的函数,调用fn 并传入 this arguments