1.說說Javascript中對象的幾種創建模式
- 對象-繼承-面向對象
- 創建對象第一個想到的關鍵字是
new
- 創建對象的目的是實現
繼承
,繼承部分通用屬性 - 問題可以轉換成 : JavaScript如何實現對象的繼承,繼承的形式
- 創建對象第一個想到的關鍵字是
- 構造函數
- 首先定義一個構造函數,可以傳入構造參數,demo如下:
function Student(name,sex){ this.name = name this.sex = sex this.sayName = function(){ console.log(this.name) } } var student_1 = new Student('張三','male')
- 限制和優勢
- 必須使用
new
關鍵字 - 創建一個對象需要使用一次
new
語句 - 屬性和方法直接賦予
this
對象 - 限制1:每個對象的屬性和方法都需要創建一遍,如果是公用的屬性會造成浪費
- 限制2:多次創建相似對象,需要重複的進行
new
動作,無法快速創建
- 必須使用
- 首先定義一個構造函數,可以傳入構造參數,demo如下:
- 快速批量創建對象的 工廠模式
- 使用一個工廠函數,入參接受構造參數,返回創建的對象,避免重複的
new
關鍵字function factory(name,sex){ var obj = new Object() obj.name = name obj.sex = sex obj.sayName = function(){ console.log(this.name) } return obj } var person_1 = factory('zhangsan','male') var person_2 = factory('lisi','female')
- 限制和優勢
- 生成相似的同類對象避免多次重複的
new
關鍵字 - 限制:只能構造同類元素
- 生成相似的同類對象避免多次重複的
- 使用一個工廠函數,入參接受構造參數,返回創建的對象,避免重複的
- 避免重複屬性性能浪費的 原型模式
-
每個函數都有一個原型屬性指針
prototype
,指向一個原型對象,所有實例的該屬性指向同一個對象,並不會重複創建對象,所以再原型對象裏面添加屬性,可以避免實例重複創建對象的性能浪費
```:javacsript
function student_proto(){} student_proto.prototype.sayNme = funciton(){ console.log(this.name) } student_proto.prototype.sex = 'male' student_proto.prototype.name = 'zhangsan' var student_1 = new student_proto() ```
-
如果實例上沒有某個屬性,就會往上向原型鏈上查找,會拿到prototype上面的統一的一個對象屬性
-
如果實例上有這個屬性則會直接返回實例屬性,如果原型鏈上也沒有這個屬性那麼就會返回Undefined
-
限制:實例對原型對象引用屬性的修改會修改所有實例的原型屬性,沒法做到獨立性
-
- 組合使用 原型模式和構造函數
- 在使用構造函數的保證實例屬性獨立的前提下,原型屬性也使用,實現混合模式
function Student(name,sex,grade){ this.name = name; this.sex = sex; this.grade = grade; } Student.prototype.sayName = function(){ console.log(this.name); } Student.prototype.school = 'Joooh school';
- 在使用構造函數的保證實例屬性獨立的前提下,原型屬性也使用,實現混合模式
- 動態原型模式
- 原理:還是把所有的信息都封裝在構造函數裏面,但是爲了避免方法的重複定義和性能損耗,在定義重複方法之進行了一個判斷,如果this.function 已經存在則不在進行重複定義,如果不存在,將原型鏈上添加上該方法
- demo
function Person(name, age, job){ //屬性 this.name = name; this.age = age; this.job = job; //方法 if (typeof this.sayName != "function"){ Person.prototype.sayName = function(){ alert(this.name); }; } } var friend = new Person("Nicholas", 29, "Software Engineer"); friend.sayName();
- 寄生構造函數模式
-
原理:Javascript 中構造函數如果有返回值的情況會怎麼樣
- 無返回值: 實例爲正常實例化對象
- 有返回值但是返回值爲非引用類型:實例爲正常實例化對象
- 有返回值並且返回值爲引用類型:實例爲返回值引用對象
-
所謂寄生構造函數就是創建一個函數,然這個函數只是封裝創建對象的代碼,然後再返回新創建的對象。
```:javascript function Person(name,age,job){ var o = new object(); o.name = name; o.age=age; o.job=job; o.sayName = function(){ alert(this.name) } return o; } var friend = new Person(name1,age1,job1) friend.sayName(); // name1 ```
-
構造函數裏面通過一個函數返回引用對象,不推薦使用,並且無法通過
Instanceof
判斷所屬關係
-
Javascript中如何實現異步編程
- 回調函數
- 原理:在需要持續很長的代碼塊結束位置調用回調函數,可以保證代碼在結束時調用,後者等待前者的結果
- 缺點:不利於代碼維護,冗長,跳轉調用閱讀困難,控制反轉
promise
- 原理:ES6中註冊promise對象,根據異步任務執行狀態,調用promise的
resolve
和reject
方法,將promise狀態置爲resolved
和rejected
,promise對象會在狀態轉變時自動調用resolve
回調或者是reject
回調 - 優點:代碼結構優秀,可以鏈式調用
- 原理:ES6中註冊promise對象,根據異步任務執行狀態,調用promise的
- 發佈/訂閱模式
- 相當於有個事件bus,任何監聽了bus事件的訂閱者,在bug觸發一定事件時都會執行相應回調函數
- 事件監聽
- 事件監聽其實也是發佈訂閱模式的一種形式,在事件觸發時,所有訂閱者的對應函數都會被執行,常用的是vue的bus
async/await
- ES6 中可迭代對象,可以使用
next()
生成,下一個序列的可迭代屬性,在手動調用next
方法時,只要返回值done
不是true
,則會阻塞下一次next()
的調用 - 所以通過
next
的阻塞作用,使用async
和await
達到異步阻塞,在前者執行完之前不會執行後者,達到異步的效果 - 可以結合
Promise
同時使用
- ES6 中可迭代對象,可以使用
Javascript 的同源策略
- 概念:JavaScript只能讀取和所屬文檔同源的窗口和文檔的屬性
- 判斷來源:指腳本本身的來源並不作爲同源依據,而是指腳本所屬文檔的來源作爲判斷依據
- 同源:協議,主機,端口必須全部相同
爲什麼JavaScript會有同源策略限制
- 避免跨域跨來源的安全問題
爲什麼說Function函數在JavaScript中是第一類對象
- 函數擁有對象能做的一切能力
- 可以動態創建
- 可以當作引用賦值
- 可以擁有自己的屬性和方法
- 可以分配變量,可以將他們的引用複製到其他變量,可以被拓展或者刪除
- instance 函數和Object都是true,函數的原型鏈最上層也是Object,擁有對象的所有原型屬性和方法
JavaScript中函數聲明和函數表達式的區別
- 什麼是函數聲明
- function type(){ } 類似這樣,聲明一個名叫type的函數
- var type = function(){} 類似這樣則是函數表達式,並且把函數表達式賦值給一個變量
- 主要就是函數聲明會和var聲明變量一樣,會有變量提升的問題
- JavaScript中定義函數的四種方式
- 函數聲明
- 函數表達式
- 箭頭函數
- new Function()
JavaScript如何刪除cookie中的一個鍵值對
- 原理:
document.cookie
在賦值時是設置單個cookie
,但是獲取document.cookie
的時候是返回所有的cookie- 在需要刪除的cookie鍵值對後面增加一個
exires=時間戳
exires鍵值對,瀏覽器就會立刻刪除該cookie鍵值對,注意此處的時間戳必須是UTC或者是GMT時間不能是本地時間 - 需要將
document.cookie
=>.split(';')
=>拆分成數組,for of
遍歷,在需要修改的鍵值對後面進行添加exire
鍵值對
手寫一個方法求字符串的字節長度
- 思路:
- 字符串自帶屬性.length,可直接拿到字符長度
- 遍歷字符串,通過charCode識別時候是中文字符,如果是中文字符>255 則字節數額外+1
attribute 和 property的區別
attribute
: 特性,特性節點(attribute node
),每個dom
節點都有有個attribute
屬性用來存儲特定的attribute node
屬性節點property
:屬性,每個dom節點,如果當作普通Object看,property就是存儲在Object中的一個鍵值對- 設置方法不一樣:
attribute
需要setAttribute
方法設置,property
直接.
語法設置 - 刪除方式不一樣:
attribute
需要removeAttribute
方法設置,property
則是使用Object
的delete
方法
延時腳本在JavaScript中的作用
defer
和async
屬性對腳本加載的意義不一樣- 相同點: 都會使腳本的加載過程不阻礙html的解析
- 不同點:
defer
延時即使腳本加載完成,也會等待html解析完畢再執行腳本,而async
則是異步加載腳本,腳本一加載完成則會立即執行腳本,可能還是會阻礙html解析 - 相同作用:都是爲了更好的html體驗,減少白屏時間,優化用戶體驗
閉包是什麼,閉包的優缺點
- 閉包
- 函數:封裝作用域
- 閉包:利用函數封裝作用域的特性,實現了私有域變量的封裝,同時暴露出方法,允許獲取或者操作私有域變量
- 實現:函數-》 函數作用域的變量聲明 -》 暴露方法允許操作或者修改變量
- 優點:私有域的變量,防止變量污染,防止全局污染,私有屬性
- 缺點:內存消耗巨大,變量不會自動回收(變量引用一直都在)
如何判斷一個對象是否屬於一個類
instanceof
object
instanceof
Object
右邊參數是否存在左右對象的原型鏈上,存在返回 true 不存在返回 false
constructor
object
.constructor
===Object
一個實例在創建過程中,prototype
中會自動創建一個constructor
屬性,並且指向這個構造函數
是否存在一個函數,只在當前對象查找屬性,不會順原型鏈查找
hasownproperty
- 返回值:一個
boolean
值,該對象本身是否擁有該屬性 - 可能會有坑:
hasOwnProperty
也是Object
原型鏈上一個屬性,可以被重寫
- 返回值:一個
document.write和innerHTML的區別
- 是否重繪整個頁面:
- document.write在修改html片段之後會重繪頁面
- innerHtml修改html片段 會重繪部分頁面片段
在JavaScript中讀取文件的方法是什麼
- JavaScript環境區分
- node環境:
- fs 庫
// 1. 使用 require 方法加載 fs 核心模塊 var fs = require('fs') // 2. 讀取文件 // 第一個參數就是要讀取的文件路徑 // 第二個參數是一個回調函數 // 成功 // data 數據 // error null // 失敗 // data undefined沒有數據 // error 錯誤對象 fs.readFile('read.txt', function (error, data) { // 在這裏就可以通過判斷 error 來確認是否有錯誤發生 if (error) { console.log('讀取文件失敗了') } else { console.log(data.toString()) } })
- 瀏覽器環境:
- 後端讀取文件,返回前端解析 前端通過
xhr
http
請求拿取文件內容
function readAjaxFile(url) { // 創建xhr var xhr = new XMLHttpRequest(); // 監聽狀態 xhr.onreadystatechange = function() { // 監聽狀態值 if(xhr.readyState === 1 && xhr.status === 200) { console.log(xhr.responseTest) } } // 打開請求 xhr.open('GET', url, true) // 發送數據 xhr.send(null) }
- 前端通過input 上傳文件
let file = document.queryselector('file-input')[0].file[0] let reader = new FileReader() reader.readAsText(file) reader.onload = function(data) { console.log(data, this.result); }
- 後端讀取文件,返回前端解析 前端通過
- node環境:
Javascript如何分配對象屬性
- 對象賦值?
.
屬性點操作賦值obj.test = 1
[]
方括號屬性操作obj['test'] = 1
- 區別:方括號內部允許變量動態值,點屬性只能直接獲取屬性