有bind的this是特殊的情况
- bind和call,apply功能类似.
- call和apply是临时的改变this.
- bind是永久改变this.
- call是"改变this", bind叫"绑定this"。
- bind返回的函数,内部的this,永远指向bind的第一个参数.(不管以何种方式调用)
- bind的优先级比call高.
bind方法:
- 用来干嘛 => 永久绑定this.
- 参数问题 => 和call一致.
- 返回 => 一个和原函数一模一样的函数.(和原函数不是同一个)
- 原函数.bind(绑定的对象,参数1,参数2,.....).
方式一:
function fn() {
console.log(this)
}
fn();// 执行会打印window
fn.call(document);// 执行会打印document
function fn() {
console.log(this)
}
fn = fn.bind(document);
fn(); // 执行会打印document
fn.call(window);// 执行会打印document
//call会引起fn触发.
fn.call(document);
//bind不会引起fn的触发.
fn.bind(document);
let show = fn.bind(document);
// show和原函数fn长得一模一样.(和fn不是同一个函数.)
console.log(show === fn);
// show里面的this永远指向bind的第一个参数.(注意,受bind影响的是show,而不是fn)
show(); // document
show.call(window); // document
fn(); // window
fn.call(document.body);// body
方式二:
4种情况的优先级:
箭头 => bind => call //apply
let fn = () =>{console.log(this)}
//箭头函数用call来调用,还是以箭头函数为准?
fn.call(document);//window
//以箭头函数为准
fn.bind(document)();//windw
nnn
属性可以分为私有属性和公有属性:
- 私有属性.(自定义属性)(手动添加)
- 公有属性(继承属性)(不手动添加,默认就有的属性)
方法也分私有和公有:
- 私有方法(自定义,手动添加的方法)
- 公有方法(继承方法)(默认就有的方法,默认就能使用的方法)
// name是obj的属性.(私有属性)
const obj = {
name: '小陈',
}
// 私有属性age.
obj.age = 32;
// toString方法,不是我们手动添加的,它默认就有.是公有方法.
console.log(obj.toString());
const arr = [1,2,3];
// 私有方法.
arr.fn = function() {console.log('这是一个数组')};
// 调用私有方法.
arr.fn();
// 不存在的方法是不能调用的
// arr.abc();
// push是默认存在的方法,是公有方法.我们学习过的数组方法都是公有方法.
arr.push(4);
如何判断一个属性是不是私有的?
hasOwnProperty => 判断是不是私有属性的.
- 用来干嘛 => 判断一个属性是不是某个对象的私有属性
- 参数就是要检测的属性名
- 返回布尔值
- 对象.hasOwnProperty(属性名);
const obj = { name: '小陈' };
// 判断name属性是不是obj的私有属性。
console.log(obj.hasOwnProperty('name'));
// 判断toString属性是不是obj的私有属性。
console.log(obj.hasOwnProperty('toString'));
私有属性 存储在对象身上.
公有属性 不存储在对象身上.
hasOwnProperty => 只能检测属性是不是私有属性。不是私有的一定是公有的吗?
如果一个属性,既不是私有属性,也不是公有属性,则这个属性对象是无法访问的。
let obj = {};
push不是obj的私有属性.
console.log(obj.hasOwnProperty('push'));// false
push也不是obj的公有方法。
obj.push();
// in => 可以检查一个对象能不能访问某个属性(方法)
if (!obj.hasOwnProperty('toString') && 'toString' in obj) {
alert('toString是公有方法')
}
公有属性存储在哪里 => 存储在原型对象上.
const obj = {};
纯对象的原型对象.
console.log(Object.prototype);
toString存储在Object.prototype上.(是Object.prototype的私有属性).
console.log(Object.prototype.hasOwnProperty('toString')); // true
const arr = [1,2,3];
// 数组的公有方法,存储在哪里? Object.prototype上吗?
// 数组的原型对象
// console.log(Array.prototype);
// push存储在数组的原型对象上,(是数组原型的私有属性)
console.log(Array.prototype.hasOwnProperty('push'));
const obj = {};
obj 继承 Object.prototype (Object.prototype是obj它爹);
const arr = [];
- arr 继承 Array.prototype (Array.prototype是arr它爹);
- 纯对象继承 Object.prototype
- 数组对象继承 Array.prototype
- Object.prototype构成了一个'家族'.Object是家族名.
- Array.prototype构成了另一个'家族'.Array是家族名.
- obj是Object家族的一个一份子(实例)
- arr是Array家族的一个一份子(实例)
arr是一个数组实例.
vm是Vue的一个实例.
原型prototype => 给类中所有的实例添加公有方法,属性
面向对象 => 类,对象
- Array是一个'家族名'
- 编程世界中,一个家族,一个种群,一个群体,应该叫一个"类".
- 数组是一个类,纯对象是一个类,函数也是一个类.....
- 每种数据类型都是一个类.
// 每种类都有一个原型对象.所有类的实例都继承该类的原型.
function fn() {
console.log(1000)
}
function show() {
console.log(2000)
}
array => Array
object => Object
function => Function
// 函数原型.
console.log(Function.prototype);
Function.prototype.car = '保时捷';
console.log(fn.car);
console.log(show.car);
let x = 100;
let y = 200;
// number类 => Number
// number的原型 => Number.prototype
// Number.prototype.abc = 'number的abc公有属性';
console.log(x.abc);
console.log(y.abc);
类都是函数
- 原型 => prototype => 纯对象
- 原型都是某个函数的私有属性.
- 每个类都对应一个原型,同时也对应一个函数.
- 实例的公有方法,存储在类的原型对象上,不是存储在类(函数)上.
- 实例继承的是类的原型,而不是继承类本身.
- prototype就是爸爸.Array就是妈妈,实例就是小孩.
console.log(Object);
console.log(typeof Object); // function
console.log(Array);
console.log(typeof Array); // function
console.log(typeof Number);// function
//prototype是类(函数)的私有属性.
console.log(Array.hasOwnProperty('prototype'));
- 给Array的原型对象添加一个abc属性,这样数组实例都可以访问abc.
- Array.prototype.abc = '公有属性';
- 给类Array函数添加一个div属性.这个属性,数组实例无法访问.
- Array.div = '类的属性';
console.log([].abc);
console.log([].div);
- 类都是函数. => 对
- 类都有原型prototype属性. => 对
- 函数都是类 => 不是, 自定义函数是
- 函数都有prototype属性吗. => 不是, 自定义函数有
- 系统默认的方法,没有prototype属性.
console.log(alert.hasOwnProperty('prototype'));
- function fn() {};
- 自定义的方法有prototype属性.有prototype属性意味着fn可以实现一个自定义类.(面向对象)
console.log(fn.hasOwnProperty('prototype'));
方式一:
let arr1 = [1,2,3];
let arr2 = [4,5,6];
// arr1.forEach(() => {});
// arr2.forEach(() => {});
// 给数组的原型添加一个公有方法myForEach.
// 这个方法内的this,就表示调用这个方法的数组实例.
Array.prototype.myForEach = function (fn) {
for (let i = 0; i < this.length; i++) {
fn(this[i], i);
}
};
arr1.myForEach((item, i) => {console.log(item)});
arr2.myForEach((item, i) => {console.log(item)});
// 封装一个window的方法。处理不同数组需要传递不同的数组作为参数
function myForEach(arr, fn) {
for (let i = 0; i < arr.length; i++) {
fn(arr[i], i);
}
};
myForEach(arr1,(item, i) => {
console.log(item);
});
myForEach(arr2,(item, i) => {
console.log(item);
});
方式二:
String.prototype.fn = function (i) {
// if (i < 0) {
// i = i + this.length;
// }
// return this.slice(i, i+1);
return this.substr(i, 1);
}
let str = 'abcd';
let msg = str.fn(1);
console.log(msg); // d
- obj继承Object.prototype => obj的爸爸是Object.prototype
- arr继承Array.prototype. => arr的爸爸是Array.prototype
- Array.prototype的爸爸又是谁 => Object.prototype
- 原型链 => 用于面试对象间的一种继承关系.
- 所有原型链的顶层对象都是 Object.prototype (null)
- 任何类的实例,都可以访问Object.prototype的方法.
- 实例可以访问它原型链上的所有方法.
- arr => Array.prototype => Object.prototype (原型链)
- 100 => Number.prototype => Object.prototype
- alert => Function.prototype => Object.prototype
- 作用域链 => 非面向对象 => 确定某个作用域内能访问到的变量,作用域链确定了,能访问到的变量也就确定了.
- 原型链 => 面向对象 => 确定某个实例能访问到的属性(方法),原型链确定了,能访问到的属性(方法)就确定.
作用域链 => 实现变量查找
- 1:先写除作用域链.
- 2:沿着作用域链查找,查找变量声明,找到就停止查找.(就近原则).找到全局作用域,如果还没有就报错.
原型链 => 实现属性查找
- 1:先写原型链.
- 2:沿着原型链查找,查找当前的原型对象有没有对应的私有属性,有就停止查找(就近原则),找到Object.protorype,
如果还没有,得到undefined.
arr => Array.prototype => Object.prototype
1: 先看看arr有没有abc私有属性.如果有就是它,停止往上查找
2: 如果arr没有abc私有属性,看看Array.prototype有没有abc私有属性.如果有就是它,停止往上查找
3: 如果Array.prototype没有abc私有属性,看看Object.prototype有没有abc私有属性.如果有就是它.没有就返回undefined
let arr = [1,2,3];
console.log(arr.abc);
// in => 检查对应的属性是不是存在于实例的原型链上.
let obj = {name: '小陈'};
Object.prototype.age = 32;
// for in 可以检测变量实例原型链上的可枚举的属性.
// 可枚举 => 可for in.
for (let key in obj) {
console.log(key);
}
oDiv
=> HTMLDivElement.prototype
=> HTMLElement.prototype
=> Element.prototype
=> Node.prototype
=> EventTarget.prototype
=> Object.prototype